From 541c75ed5c0d850d875c2bc0357b4e6cf46ecb93 Mon Sep 17 00:00:00 2001 From: Rocky Meza Date: Sun, 15 Jun 2014 08:14:37 -0600 Subject: [PATCH 0001/1182] Fixed the order of args to grep in README. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6497ad1596..5024eb9978 100644 --- a/README.rst +++ b/README.rst @@ -756,7 +756,7 @@ Or the output of another program: .. code-block:: bash - $ grep /var/log/httpd/error_log '401 Unauthorized' | http POST example.org/intruders + $ grep '401 Unauthorized' /var/log/httpd/error_log | http POST example.org/intruders You can use ``echo`` for simple data: From 5e556612d9fbe8fdb9479346f3629d4a62702340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Tue, 24 Jun 2014 17:25:29 +0200 Subject: [PATCH 0002/1182] Added `$ brew install httpie` to README https://twitter.com/jakubroztocil/status/481453834024550400 Thanks @insomniacslk! --- README.rst | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 5024eb9978..f179ef7233 100644 --- a/README.rst +++ b/README.rst @@ -67,23 +67,30 @@ Installation Stable version |version| ------------------------ -The **latest stable version** can always be installed or updated to via `pip`_: +On **Mac OS X**, HTTPie can be installed via `Homebrew `_: .. code-block:: bash - $ pip install --upgrade httpie + $ brew install httpie + + +Most **Linux** distributions provide a package that can be installed via +system package manager, e.g. ``yum install httpie`` or ``apt-get install httpie``. +Note that the package might include a slightly older version of HTTPie. + +A **universal installation method** (that works on **Windows**, Mac OS X, Linux, …, +and provides the latest version) is to use `pip`_: -If the above fails, please use ``easy_install`` instead: .. code-block:: bash + # Install or update to the latest version. + $ pip install --upgrade httpie + - $ easy_install httpie +If the above fails, please use ``easy_install`` instead (``$ easy_install httpie``). -Many Linux distributions also provide a package that can be installed via -system package manager, e.g. -``yum install httpie`` or ``apt-get install httpie``. From a02a1eb562970f6a33a727bfcd459440f2ea25af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Tue, 24 Jun 2014 17:27:01 +0200 Subject: [PATCH 0003/1182] Fixed README formatting --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f179ef7233..9b0667699a 100644 --- a/README.rst +++ b/README.rst @@ -84,7 +84,7 @@ and provides the latest version) is to use `pip`_: .. code-block:: bash - # Install or update to the latest version. + $ pip install --upgrade httpie From 8c892edd4fe700a7ca5cc733dcb4817831d253e2 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 28 Jun 2014 13:08:58 +0200 Subject: [PATCH 0004/1182] PEP8 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index d39e5342b0..7a23a277b3 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,6 @@ import sys import codecs + from setuptools import setup, find_packages from setuptools.command.test import test as TestCommand From 040d981f00c3f6830b2d0db3daf3c64c080e96e3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 28 Jun 2014 13:24:14 +0200 Subject: [PATCH 0005/1182] Fixed custom Host Closes #235 --- httpie/models.py | 3 +-- tests/test_regressions.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 tests/test_regressions.py diff --git a/httpie/models.py b/httpie/models.py index f6b9dff9da..af6163fd1e 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -102,8 +102,7 @@ def headers(self): ) headers = dict(self._orig.headers) - - if 'Host' not in headers: + if 'Host' not in self._orig.headers: headers['Host'] = url.netloc.split('@')[-1] headers = ['%s: %s' % (name, value) diff --git a/tests/test_regressions.py b/tests/test_regressions.py new file mode 100644 index 0000000000..8c21d1d338 --- /dev/null +++ b/tests/test_regressions.py @@ -0,0 +1,17 @@ +"""Miscellaneous regression tests""" +import socket + +from utils import http, HTTP_OK + + +def test_Host_header_overwrite(): + """ + https://github.com/jakubroztocil/httpie/issues/235 + + """ + host = 'httpbin.org' + url = 'http://{httpbin_ip}/get'.format( + httpbin_ip=socket.gethostbyname(host)) + r = http('--print=hH', url, 'host:{}'.format(host)) + assert HTTP_OK in r + assert r.lower().count('host:') == 1 From 79329ed1c6c979fe5f1b7d59ba13d72528bce1f8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 28 Jun 2014 13:26:48 +0200 Subject: [PATCH 0006/1182] Mention "brew install httpie --HEAD". --- README.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 9b0667699a..006764c25c 100644 --- a/README.rst +++ b/README.rst @@ -72,14 +72,14 @@ On **Mac OS X**, HTTPie can be installed via `Homebrew `_: .. code-block:: bash $ brew install httpie - + Most **Linux** distributions provide a package that can be installed via system package manager, e.g. ``yum install httpie`` or ``apt-get install httpie``. Note that the package might include a slightly older version of HTTPie. -A **universal installation method** (that works on **Windows**, Mac OS X, Linux, …, +A **universal installation method** (that works on **Windows**, Mac OS X, Linux, …, and provides the latest version) is to use `pip`_: @@ -93,7 +93,6 @@ If the above fails, please use ``easy_install`` instead (``$ easy_install httpie - ------------------- Development version ------------------- @@ -108,6 +107,10 @@ 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/jakubroztocil/httpie/tarball/master From 2a72ae23d52ec2ca583a7b2324d69bd3f2421386 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 28 Jun 2014 16:35:57 +0200 Subject: [PATCH 0007/1182] Run tests against local httpbin instance via pytest-httpbin. --- httpie/models.py | 9 +++-- requirements-dev.txt | 1 + setup.py | 1 + tests/test_auth.py | 25 +++++++------ tests/test_binary.py | 14 ++++---- tests/test_cli.py | 46 +++++++++++++----------- tests/test_defaults.py | 64 ++++++++++++++++----------------- tests/test_downloads.py | 18 +++++----- tests/test_exit_status.py | 43 +++++++++++----------- tests/test_httpie.py | 38 ++++++++++---------- tests/test_output.py | 69 ++++++++++++++++++----------------- tests/test_regressions.py | 8 ++--- tests/test_sessions.py | 76 ++++++++++++++++++++++----------------- tests/test_stream.py | 14 ++++---- tests/test_unicode.py | 56 ++++++++++++++--------------- tests/test_uploads.py | 39 +++++++++++--------- tests/test_windows.py | 10 +++--- tests/utils.py | 29 +++++++-------- tox.ini | 1 + 19 files changed, 299 insertions(+), 262 deletions(-) diff --git a/httpie/models.py b/httpie/models.py index af6163fd1e..d7c5414f8e 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -105,8 +105,13 @@ def headers(self): if 'Host' not in self._orig.headers: headers['Host'] = url.netloc.split('@')[-1] - headers = ['%s: %s' % (name, value) - for name, value in headers.items()] + headers = [ + '%s: %s' % ( + name, + value if isinstance(value, str) else value.decode('utf8') + ) + for name, value in headers.items() + ] headers.insert(0, request_line) headers = '\r\n'.join(headers).strip() diff --git a/requirements-dev.txt b/requirements-dev.txt index bd00cc5563..1b0b06ae3e 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,4 +2,5 @@ tox pytest pytest-xdist pytest-cov +pytest-httpbin docutils diff --git a/setup.py b/setup.py index 7a23a277b3..a4cc27193a 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ def run_tests(self): tests_require = [ 'pytest', + 'pytest-httpbin', ] diff --git a/tests/test_auth.py b/tests/test_auth.py index 1977a064ec..539626152f 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -2,42 +2,45 @@ import requests import pytest -from utils import http, httpbin, HTTP_OK +from utils import http, add_auth, HTTP_OK import httpie.input class TestAuth: - def test_basic_auth(self): + def test_basic_auth(self, httpbin): r = http('--auth=user:password', - 'GET', httpbin('/basic-auth/user/password')) + 'GET', httpbin.url + '/basic-auth/user/password') assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} @pytest.mark.skipif( requests.__version__ == '0.13.6', reason='Redirects with prefetch=False are broken in Requests 0.13.6') - def test_digest_auth(self): + def test_digest_auth(self, httpbin): r = http('--auth-type=digest', '--auth=user:password', - 'GET', httpbin('/digest-auth/auth/user/password')) + 'GET', httpbin.url + '/digest-auth/auth/user/password') assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} - def test_password_prompt(self): + def test_password_prompt(self, httpbin): httpie.input.AuthCredentials._getpass = lambda self, prompt: 'password' - r = http('--auth', 'user', 'GET', httpbin('/basic-auth/user/password')) + r = http('--auth', 'user', + 'GET', httpbin.url + '/basic-auth/user/password') assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} - def test_credentials_in_url(self): - url = httpbin('/basic-auth/user/password', auth='user:password') + def test_credentials_in_url(self, httpbin): + url = add_auth(httpbin.url + '/basic-auth/user/password', + auth='user:password') r = http('GET', url) assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} - def test_credentials_in_url_auth_flag_has_priority(self): + def test_credentials_in_url_auth_flag_has_priority(self, httpbin): """When credentials are passed in URL and via -a at the same time, then the ones from -a are used.""" - url = httpbin('/basic-auth/user/password', auth='user:wrong') + url = add_auth(httpbin.url + '/basic-auth/user/password', + auth='user:wrong') r = http('--auth=user:password', 'GET', url) assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} diff --git a/tests/test_binary.py b/tests/test_binary.py index 7a1bd0623e..7c112045a1 100644 --- a/tests/test_binary.py +++ b/tests/test_binary.py @@ -1,30 +1,30 @@ """Tests for dealing with binary request and response data.""" from httpie.compat import urlopen from httpie.output.streams import BINARY_SUPPRESSED_NOTICE -from utils import TestEnvironment, http, httpbin +from utils import TestEnvironment, http from fixtures import BIN_FILE_PATH, BIN_FILE_CONTENT, BIN_FILE_PATH_ARG class TestBinaryRequestData: - def test_binary_stdin(self): + def test_binary_stdin(self, httpbin): with open(BIN_FILE_PATH, 'rb') as stdin: env = TestEnvironment( stdin=stdin, stdin_isatty=False, stdout_isatty=False ) - r = http('--print=B', 'POST', httpbin('/post'), env=env) + r = http('--print=B', 'POST', httpbin.url + '/post', env=env) assert r == BIN_FILE_CONTENT - def test_binary_file_path(self): + def test_binary_file_path(self, httpbin): env = TestEnvironment(stdin_isatty=True, stdout_isatty=False) - r = http('--print=B', 'POST', httpbin('/post'), + 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): + def test_binary_file_form(self, httpbin): env = TestEnvironment(stdin_isatty=True, stdout_isatty=False) - r = http('--print=B', '--form', 'POST', httpbin('/post'), + r = http('--print=B', '--form', 'POST', httpbin.url + '/post', 'test@' + BIN_FILE_PATH_ARG, env=env) assert bytes(BIN_FILE_CONTENT) in bytes(r) diff --git a/tests/test_cli.py b/tests/test_cli.py index c19fcb2952..103d954354 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -9,7 +9,7 @@ from httpie.input import KeyValue, KeyValueArgType from httpie import ExitStatus from httpie.cli import parser -from utils import TestEnvironment, http, httpbin, HTTP_OK +from utils import TestEnvironment, http, HTTP_OK from fixtures import ( FILE_PATH_ARG, JSON_FILE_PATH_ARG, JSON_FILE_CONTENT, FILE_CONTENT, FILE_PATH @@ -93,27 +93,28 @@ def test_valid_items(self): class TestQuerystring: - def test_query_string_params_in_url(self): - r = http('--print=Hhb', 'GET', httpbin('/get?a=1&b=2')) + def test_query_string_params_in_url(self, httpbin): + r = http('--print=Hhb', 'GET', httpbin.url + '/get?a=1&b=2') path = '/get?a=1&b=2' - url = httpbin(path) + url = httpbin.url + path assert HTTP_OK in r assert 'GET %s HTTP/1.1' % path in r assert '"url": "%s"' % url in r - def test_query_string_params_items(self): - r = http('--print=Hhb', 'GET', httpbin('/get'), 'a==1', 'b==2') - path = '/get?a=1&b=2' - url = httpbin(path) + def test_query_string_params_items(self, httpbin): + r = http('--print=Hhb', 'GET', httpbin.url + '/get', 'a==1') + path = '/get?a=1' + url = httpbin.url + path assert HTTP_OK in r assert 'GET %s HTTP/1.1' % path in r assert '"url": "%s"' % url in r - def test_query_string_params_in_url_and_items_with_duplicates(self): - r = http('--print=Hhb', 'GET', httpbin('/get?a=1&a=1'), - 'a==1', 'a==1', 'b==2') - path = '/get?a=1&a=1&a=1&a=1&b=2' - url = httpbin(path) + def test_query_string_params_in_url_and_items_with_duplicates(self, + httpbin): + r = http('--print=Hhb', 'GET', + httpbin.url + '/get?a=1&a=1', 'a==1', 'a==1') + path = '/get?a=1&a=1&a=1&a=1' + url = httpbin.url + path assert HTTP_OK in r assert 'GET %s HTTP/1.1' % path in r assert '"url": "%s"' % url in r @@ -257,12 +258,13 @@ def test_guess_when_method_set_but_invalid_and_item_exists(self): class TestNoOptions: - def test_valid_no_options(self): - r = http('--verbose', '--no-verbose', 'GET', httpbin('/get')) + + def test_valid_no_options(self, httpbin): + r = http('--verbose', '--no-verbose', 'GET', httpbin.url + '/get') assert 'GET /get HTTP/1.1' not in r - def test_invalid_no_options(self): - r = http('--no-war', 'GET', httpbin('/get'), + def test_invalid_no_options(self, httpbin): + r = http('--no-war', 'GET', httpbin.url + '/get', error_exit_ok=True) assert r.exit_status == 1 assert 'unrecognized arguments: --no-war' in r.stderr @@ -270,16 +272,18 @@ def test_invalid_no_options(self): class TestIgnoreStdin: - def test_ignore_stdin(self): + + def test_ignore_stdin(self, httpbin): with open(FILE_PATH) as f: env = TestEnvironment(stdin=f, stdin_isatty=False) - r = http('--ignore-stdin', '--verbose', httpbin('/get'), env=env) + r = http('--ignore-stdin', '--verbose', httpbin.url + '/get', + env=env) assert HTTP_OK in r assert 'GET /get HTTP' in r, "Don't default to POST." assert FILE_CONTENT not in r, "Don't send stdin data." - def test_ignore_stdin_cannot_prompt_password(self): - r = http('--ignore-stdin', '--auth=no-password', httpbin('/get'), + def test_ignore_stdin_cannot_prompt_password(self, httpbin): + r = http('--ignore-stdin', '--auth=no-password', httpbin.url + '/get', error_exit_ok=True) assert r.exit_status == ExitStatus.ERROR assert 'because --ignore-stdin' in r.stderr diff --git a/tests/test_defaults.py b/tests/test_defaults.py index dffbaf6e9f..652a272b9f 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -2,34 +2,34 @@ Tests for the provided defaults regarding HTTP method, and --json vs. --form. """ -from utils import TestEnvironment, http, httpbin, HTTP_OK +from utils import TestEnvironment, http, HTTP_OK, no_content_type from fixtures import FILE_PATH class TestImplicitHTTPMethod: - def test_implicit_GET(self): - r = http(httpbin('/get')) + def test_implicit_GET(self, httpbin): + r = http(httpbin.url + '/get') assert HTTP_OK in r - def test_implicit_GET_with_headers(self): - r = http(httpbin('/headers'), 'Foo:bar') + def test_implicit_GET_with_headers(self, httpbin): + r = http(httpbin.url + '/headers', 'Foo:bar') assert HTTP_OK in r assert r.json['headers']['Foo'] == 'bar' - def test_implicit_POST_json(self): - r = http(httpbin('/post'), 'hello=world') + def test_implicit_POST_json(self, httpbin): + r = http(httpbin.url + '/post', 'hello=world') assert HTTP_OK in r assert r.json['json'] == {'hello': 'world'} - def test_implicit_POST_form(self): - r = http('--form', httpbin('/post'), 'foo=bar') + def test_implicit_POST_form(self, httpbin): + r = http('--form', httpbin.url + '/post', 'foo=bar') assert HTTP_OK in r assert r.json['form'] == {'foo': 'bar'} - def test_implicit_POST_stdin(self): + def test_implicit_POST_stdin(self, httpbin): with open(FILE_PATH) as f: env = TestEnvironment(stdin_isatty=False, stdin=f) - r = http('--form', httpbin('/post'), env=env) + r = http('--form', httpbin.url + '/post', env=env) assert HTTP_OK in r @@ -41,66 +41,66 @@ class TestAutoContentTypeAndAcceptHeaders: """ - def test_GET_no_data_no_auto_headers(self): + def test_GET_no_data_no_auto_headers(self, httpbin): # https://github.com/jakubroztocil/httpie/issues/62 - r = http('GET', httpbin('/headers')) + r = http('GET', httpbin.url + '/headers') assert HTTP_OK in r assert r.json['headers']['Accept'] == '*/*' - assert 'Content-Type' not in r.json['headers'] + assert no_content_type(r.json['headers']) - def test_POST_no_data_no_auto_headers(self): + def test_POST_no_data_no_auto_headers(self, httpbin): # JSON headers shouldn't be automatically set for POST with no data. - r = http('POST', httpbin('/post')) + r = http('POST', httpbin.url + '/post') assert HTTP_OK in r assert '"Accept": "*/*"' in r assert '"Content-Type": "application/json' not in r - def test_POST_with_data_auto_JSON_headers(self): - r = http('POST', httpbin('/post'), 'a=b') + def test_POST_with_data_auto_JSON_headers(self, httpbin): + r = http('POST', httpbin.url + '/post', 'a=b') assert HTTP_OK in r assert '"Accept": "application/json"' in r assert '"Content-Type": "application/json; charset=utf-8' in r - def test_GET_with_data_auto_JSON_headers(self): + def test_GET_with_data_auto_JSON_headers(self, httpbin): # JSON headers should automatically be set also for GET with data. - r = http('POST', httpbin('/post'), 'a=b') + r = http('POST', httpbin.url + '/post', 'a=b') assert HTTP_OK in r assert '"Accept": "application/json"' in r, r assert '"Content-Type": "application/json; charset=utf-8' in r - def test_POST_explicit_JSON_auto_JSON_accept(self): - r = http('--json', 'POST', httpbin('/post')) + def test_POST_explicit_JSON_auto_JSON_accept(self, httpbin): + r = http('--json', 'POST', httpbin.url + '/post') assert HTTP_OK in r assert r.json['headers']['Accept'] == 'application/json' # Make sure Content-Type gets set even with no data. # https://github.com/jakubroztocil/httpie/issues/137 assert 'application/json' in r.json['headers']['Content-Type'] - def test_GET_explicit_JSON_explicit_headers(self): - r = http('--json', 'GET', httpbin('/headers'), + def test_GET_explicit_JSON_explicit_headers(self, httpbin): + r = http('--json', 'GET', httpbin.url + '/headers', 'Accept:application/xml', 'Content-Type:application/xml') assert HTTP_OK in r assert '"Accept": "application/xml"' in r assert '"Content-Type": "application/xml"' in r - def test_POST_form_auto_Content_Type(self): - r = http('--form', 'POST', httpbin('/post')) + def test_POST_form_auto_Content_Type(self, httpbin): + r = http('--form', 'POST', httpbin.url + '/post') assert HTTP_OK in r assert '"Content-Type": "application/x-www-form-urlencoded' in r - def test_POST_form_Content_Type_override(self): - r = http('--form', 'POST', httpbin('/post'), + def test_POST_form_Content_Type_override(self, httpbin): + r = http('--form', 'POST', httpbin.url + '/post', 'Content-Type:application/xml') assert HTTP_OK in r assert '"Content-Type": "application/xml"' in r - def test_print_only_body_when_stdout_redirected_by_default(self): + def test_print_only_body_when_stdout_redirected_by_default(self, httpbin): env = TestEnvironment(stdin_isatty=True, stdout_isatty=False) - r = http('GET', httpbin('/get'), env=env) + r = http('GET', httpbin.url + '/get', env=env) assert 'HTTP/' not in r - def test_print_overridable_when_stdout_redirected(self): + def test_print_overridable_when_stdout_redirected(self, httpbin): env = TestEnvironment(stdin_isatty=True, stdout_isatty=False) - r = http('--print=h', 'GET', httpbin('/get'), env=env) + r = http('--print=h', 'GET', httpbin.url + '/get', env=env) assert HTTP_OK in r diff --git a/tests/test_downloads.py b/tests/test_downloads.py index ce72260671..3a8c8f24f4 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -9,7 +9,7 @@ parse_content_range, filename_from_content_disposition, filename_from_url, get_unique_filename, ContentRangeError, Download, ) -from utils import httpbin, http, TestEnvironment +from utils import http, TestEnvironment class Response(object): @@ -94,8 +94,8 @@ def exists(filename): class TestDownloads: # TODO: more tests - def test_actual_download(self): - url = httpbin('/robots.txt') + def test_actual_download(self, httpbin): + url = httpbin.url + '/robots.txt' body = urlopen(url).read().decode() env = TestEnvironment(stdin_isatty=True, stdout_isatty=False) r = http('--download', url, env=env) @@ -104,11 +104,11 @@ def test_actual_download(self): assert 'Done' in r.stderr assert body == r - def test_download_with_Content_Length(self): + def test_download_with_Content_Length(self, httpbin): devnull = open(os.devnull, 'w') download = Download(output_file=devnull, progress_file=devnull) download.start(Response( - url=httpbin('/'), + url=httpbin.url + '/', headers={'Content-Length': 10} )) time.sleep(1.1) @@ -118,20 +118,20 @@ def test_download_with_Content_Length(self): download.finish() assert not download.interrupted - def test_download_no_Content_Length(self): + def test_download_no_Content_Length(self, httpbin): devnull = open(os.devnull, 'w') download = Download(output_file=devnull, progress_file=devnull) - download.start(Response(url=httpbin('/'))) + download.start(Response(url=httpbin.url + '/')) time.sleep(1.1) download.chunk_downloaded(b'12345') download.finish() assert not download.interrupted - def test_download_interrupted(self): + def test_download_interrupted(self, httpbin): devnull = open(os.devnull, 'w') download = Download(output_file=devnull, progress_file=devnull) download.start(Response( - url=httpbin('/'), + url=httpbin.url + '/', headers={'Content-Length': 5} )) download.chunk_downloaded(b'1234') diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index 8e946317a2..7ac643f940 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -2,18 +2,18 @@ import pytest from httpie import ExitStatus -from utils import TestEnvironment, http, httpbin, HTTP_OK +from utils import TestEnvironment, http, HTTP_OK class TestExitStatus: - def test_ok_response_exits_0(self): - r = http('GET', httpbin('/status/200')) + def test_ok_response_exits_0(self, httpbin): + r = http('GET', httpbin.url + '/status/200') assert HTTP_OK in r assert r.exit_status == ExitStatus.OK - def test_error_response_exits_0_without_check_status(self): - r = http('GET', httpbin('/status/500')) - assert 'HTTP/1.1 500' in r + def test_error_response_exits_0_without_check_status(self, httpbin): + r = http('GET', httpbin.url + '/status/500') + assert '500 INTERNAL SERVER ERRO' in r assert r.exit_status == ExitStatus.OK assert not r.stderr @@ -21,40 +21,43 @@ def test_error_response_exits_0_without_check_status(self): tuple(map(int, requests.__version__.split('.'))) < (2, 3, 0), reason='timeout broken in requests prior v2.3.0 (#185)' ) - def test_timeout_exit_status(self): + def test_timeout_exit_status(self, httpbin): - r = http('--timeout=0.5', 'GET', httpbin('/delay/1'), + r = http('--timeout=0.5', 'GET', httpbin.url + '/delay/1', error_exit_ok=True) assert r.exit_status == ExitStatus.ERROR_TIMEOUT - def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected(self): + def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected( + self, httpbin): env = TestEnvironment(stdout_isatty=False) - r = http('--check-status', '--headers', 'GET', httpbin('/status/301'), + r = http('--check-status', '--headers', + 'GET', httpbin.url + '/status/301', env=env, error_exit_ok=True) - assert 'HTTP/1.1 301' in r + assert '301 MOVED PERMANENTLY' in r assert r.exit_status == ExitStatus.ERROR_HTTP_3XX assert '301 moved permanently' in r.stderr.lower() @pytest.mark.skipif( requests.__version__ == '0.13.6', reason='Redirects with prefetch=False are broken in Requests 0.13.6') - def test_3xx_check_status_redirects_allowed_exits_0(self): - r = http('--check-status', '--follow', 'GET', httpbin('/status/301'), + def test_3xx_check_status_redirects_allowed_exits_0(self, httpbin): + r = http('--check-status', '--follow', + 'GET', httpbin.url + '/status/301', error_exit_ok=True) # The redirect will be followed so 200 is expected. - assert 'HTTP/1.1 200 OK' in r + assert HTTP_OK in r assert r.exit_status == ExitStatus.OK - def test_4xx_check_status_exits_4(self): - r = http('--check-status', 'GET', httpbin('/status/401'), + def test_4xx_check_status_exits_4(self, httpbin): + r = http('--check-status', 'GET', httpbin.url + '/status/401', error_exit_ok=True) - assert 'HTTP/1.1 401' in r + assert '401 UNAUTHORIZED' in r assert r.exit_status == ExitStatus.ERROR_HTTP_4XX # Also stderr should be empty since stdout isn't redirected. assert not r.stderr - def test_5xx_check_status_exits_5(self): - r = http('--check-status', 'GET', httpbin('/status/500'), + def test_5xx_check_status_exits_5(self, httpbin): + r = http('--check-status', 'GET', httpbin.url + '/status/500', error_exit_ok=True) - assert 'HTTP/1.1 500' in r + assert '500 INTERNAL SERVER ERROR' in r assert r.exit_status == ExitStatus.ERROR_HTTP_5XX diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 74be3a5994..2ee647ea11 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -1,5 +1,5 @@ """High-level tests.""" -from utils import TestEnvironment, http, httpbin, HTTP_OK +from utils import TestEnvironment, http, HTTP_OK from fixtures import FILE_PATH, FILE_CONTENT import httpie @@ -23,43 +23,43 @@ def test_version(self): # FIXME: py3 has version in stdout, py2 in stderr assert httpie.__version__ == r.stderr.strip() + r.strip() - def test_GET(self): - r = http('GET', httpbin('/get')) + def test_GET(self, httpbin): + r = http('GET', httpbin.url + '/get') assert HTTP_OK in r - def test_DELETE(self): - r = http('DELETE', httpbin('/delete')) + def test_DELETE(self, httpbin): + r = http('DELETE', httpbin.url + '/delete') assert HTTP_OK in r - def test_PUT(self): - r = http('PUT', httpbin('/put'), 'foo=bar') + def test_PUT(self, httpbin): + r = http('PUT', httpbin.url + '/put', 'foo=bar') assert HTTP_OK in r - assert r'\"foo\": \"bar\"' in r + assert r.json['json']['foo'] == 'bar' - def test_POST_JSON_data(self): - r = http('POST', httpbin('/post'), 'foo=bar') + def test_POST_JSON_data(self, httpbin): + r = http('POST', httpbin.url + '/post', 'foo=bar') assert HTTP_OK in r - assert r'\"foo\": \"bar\"' in r + assert r.json['json']['foo'] == 'bar' - def test_POST_form(self): - r = http('--form', 'POST', httpbin('/post'), 'foo=bar') + def test_POST_form(self, httpbin): + r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar') assert HTTP_OK in r assert '"foo": "bar"' in r - def test_POST_form_multiple_values(self): - r = http('--form', 'POST', httpbin('/post'), 'foo=bar', 'foo=baz') + def test_POST_form_multiple_values(self, httpbin): + r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar', 'foo=baz') assert HTTP_OK in r assert r.json['form'] == {'foo': ['bar', 'baz']} - def test_POST_stdin(self): + def test_POST_stdin(self, httpbin): with open(FILE_PATH) as f: env = TestEnvironment(stdin=f, stdin_isatty=False) - r = http('--form', 'POST', httpbin('/post'), env=env) + r = http('--form', 'POST', httpbin.url + '/post', env=env) assert HTTP_OK in r assert FILE_CONTENT in r - def test_headers(self): - r = http('GET', httpbin('/headers'), 'Foo:bar') + def test_headers(self, httpbin): + r = http('GET', httpbin.url + '/headers', 'Foo:bar') assert HTTP_OK in r assert '"User-Agent": "HTTPie' in r, r assert '"Foo": "bar"' in r diff --git a/tests/test_output.py b/tests/test_output.py index a5ac1048e3..ad2dec041f 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -2,27 +2,28 @@ from httpie import ExitStatus from httpie.output.formatters.colors import get_lexer -from utils import TestEnvironment, http, httpbin, HTTP_OK, COLOR, CRLF +from utils import TestEnvironment, http, HTTP_OK, COLOR, CRLF class TestVerboseFlag: - def test_verbose(self): - r = http('--verbose', 'GET', httpbin('/get'), 'test-header:__test__') + def test_verbose(self, httpbin): + r = http('--verbose', + 'GET', httpbin.url + '/get', 'test-header:__test__') assert HTTP_OK in r assert r.count('__test__') == 2 - def test_verbose_form(self): + def test_verbose_form(self, httpbin): # https://github.com/jakubroztocil/httpie/issues/53 - r = http('--verbose', '--form', 'POST', httpbin('/post'), + r = http('--verbose', '--form', 'POST', httpbin.url + '/post', 'A=B', 'C=D') assert HTTP_OK in r assert 'A=B&C=D' in r - def test_verbose_json(self): - r = http('--verbose', 'POST', httpbin('/post'), 'foo=bar', 'baz=bar') + def test_verbose_json(self, httpbin): + r = http('--verbose', + 'POST', httpbin.url + '/post', 'foo=bar', 'baz=bar') assert HTTP_OK in r - assert '"baz": "bar"' in r # request - assert r'\"baz\": \"bar\"' in r # response + assert '"baz": "bar"' in r class TestColors: @@ -47,45 +48,47 @@ def test_get_lexer_not_found(self): class TestPrettyOptions: """Test the --pretty flag handling.""" - def test_pretty_enabled_by_default(self): + def test_pretty_enabled_by_default(self, httpbin): env = TestEnvironment(colors=256) - r = http('GET', httpbin('/get'), env=env) + r = http('GET', httpbin.url + '/get', env=env) assert COLOR in r - def test_pretty_enabled_by_default_unless_stdout_redirected(self): - r = http('GET', httpbin('/get')) + def test_pretty_enabled_by_default_unless_stdout_redirected(self, httpbin): + r = http('GET', httpbin.url + '/get') assert COLOR not in r - def test_force_pretty(self): + def test_force_pretty(self, httpbin): env = TestEnvironment(stdout_isatty=False, colors=256) - r = http('--pretty=all', 'GET', httpbin('/get'), env=env, ) + r = http('--pretty=all', 'GET', httpbin.url + '/get', env=env, ) assert COLOR in r - def test_force_ugly(self): - r = http('--pretty=none', 'GET', httpbin('/get')) + def test_force_ugly(self, httpbin): + r = http('--pretty=none', 'GET', httpbin.url + '/get') assert COLOR not in r - def test_subtype_based_pygments_lexer_match(self): + def test_subtype_based_pygments_lexer_match(self, httpbin): """Test that media subtype is used if type/subtype doesn't match any lexer. """ env = TestEnvironment(colors=256) - r = http('--print=B', '--pretty=all', httpbin('/post'), + 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): + def test_colors_option(self, httpbin): env = TestEnvironment(colors=256) - r = http('--print=B', '--pretty=colors', 'GET', httpbin('/get'), 'a=b', + r = http('--print=B', '--pretty=colors', + 'GET', httpbin.url + '/get', 'a=b', env=env) # Tests that the JSON data isn't formatted. assert not r.strip().count('\n') assert COLOR in r - def test_format_option(self): + def test_format_option(self, httpbin): env = TestEnvironment(colors=256) - r = http('--print=B', '--pretty=format', 'GET', httpbin('/get'), 'a=b', + r = http('--print=B', '--pretty=format', + 'GET', httpbin.url + '/get', 'a=b', env=env) # Tests that the JSON data is formatted. assert r.strip().count('\n') == 2 @@ -110,24 +113,24 @@ def _validate_crlf(self, msg): assert CRLF not in body return body - def test_CRLF_headers_only(self): - r = http('--headers', 'GET', httpbin('/get')) + def test_CRLF_headers_only(self, httpbin): + r = http('--headers', 'GET', httpbin.url + '/get') body = self._validate_crlf(r) assert not body, 'Garbage after headers: %r' % r - def test_CRLF_ugly_response(self): - r = http('--pretty=none', 'GET', httpbin('/get')) + def test_CRLF_ugly_response(self, httpbin): + r = http('--pretty=none', 'GET', httpbin.url + '/get') self._validate_crlf(r) - def test_CRLF_formatted_response(self): - r = http('--pretty=format', 'GET', httpbin('/get')) + def test_CRLF_formatted_response(self, httpbin): + r = http('--pretty=format', 'GET', httpbin.url + '/get') assert r.exit_status == ExitStatus.OK self._validate_crlf(r) - def test_CRLF_ugly_request(self): - r = http('--pretty=none', '--print=HB', 'GET', httpbin('/get')) + def test_CRLF_ugly_request(self, httpbin): + r = http('--pretty=none', '--print=HB', 'GET', httpbin.url + '/get') self._validate_crlf(r) - def test_CRLF_formatted_request(self): - r = http('--pretty=format', '--print=HB', 'GET', httpbin('/get')) + def test_CRLF_formatted_request(self, httpbin): + r = http('--pretty=format', '--print=HB', 'GET', httpbin.url + '/get') self._validate_crlf(r) diff --git a/tests/test_regressions.py b/tests/test_regressions.py index 8c21d1d338..b80fba38b4 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -4,14 +4,14 @@ from utils import http, HTTP_OK -def test_Host_header_overwrite(): +def test_Host_header_overwrite(httpbin): """ https://github.com/jakubroztocil/httpie/issues/235 """ host = 'httpbin.org' - url = 'http://{httpbin_ip}/get'.format( - httpbin_ip=socket.gethostbyname(host)) - r = http('--print=hH', url, 'host:{}'.format(host)) + url = httpbin.url + '/get' + r = http('--print=hH', url, 'host:{0}'.format(host)) assert HTTP_OK in r assert r.lower().count('host:') == 1 + assert 'host: {0}'.format(host) in r diff --git a/tests/test_sessions.py b/tests/test_sessions.py index c26e66edc0..6d5985843f 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -3,12 +3,14 @@ import shutil from httpie.plugins.builtin import HTTPBasicAuth -from utils import TestEnvironment, mk_config_dir, http, httpbin, HTTP_OK +from utils import TestEnvironment, mk_config_dir, http, HTTP_OK, \ + no_content_type from fixtures import UNICODE class SessionTestBase(object): - def setup_method(self, method): + + def start_session(self, httpbin): """Create and reuse a unique config dir for each test.""" self.config_dir = mk_config_dir() @@ -33,67 +35,70 @@ class TestSessionFlow(SessionTestBase): """ - def setup_method(self, method): + def start_session(self, httpbin): """ Start a full-blown session with a custom request header, authorization, and response cookies. """ - super(TestSessionFlow, self).setup_method(method) + super(TestSessionFlow, self).start_session(httpbin) r1 = http('--follow', '--session=test', '--auth=username:password', - 'GET', httpbin('/cookies/set?hello=world'), 'Hello:World', + 'GET', httpbin.url + '/cookies/set?hello=world', + 'Hello:World', env=self.env()) assert HTTP_OK in r1 - def test_session_created_and_reused(self): + def test_session_created_and_reused(self, httpbin): + self.start_session(httpbin) # Verify that the session created in setup_method() has been used. - r2 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) + r2 = http('--session=test', + 'GET', httpbin.url + '/get', env=self.env()) assert HTTP_OK in r2 assert r2.json['headers']['Hello'] == 'World' assert r2.json['headers']['Cookie'] == 'hello=world' assert 'Basic ' in r2.json['headers']['Authorization'] - def test_session_update(self): + def test_session_update(self, httpbin): + self.start_session(httpbin) # Get a response to a request from the original session. - r2 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) + r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) assert HTTP_OK in r2 # Make a request modifying the session data. r3 = http('--follow', '--session=test', '--auth=username:password2', - 'GET', httpbin('/cookies/set?hello=world2'), 'Hello:World2', + 'GET', httpbin.url + '/cookies/set?hello=world2', 'Hello:World2', env=self.env()) assert HTTP_OK in r3 # Get a response to a request from the updated session. - r4 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) + r4 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) 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']) - def test_session_read_only(self): + def test_session_read_only(self, httpbin): + self.start_session(httpbin) # Get a response from the original session. - r2 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) + r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) assert HTTP_OK in r2 # Make a request modifying the session data but # with --session-read-only. r3 = http('--follow', '--session-read-only=test', '--auth=username:password2', 'GET', - httpbin('/cookies/set?hello=world2'), 'Hello:World2', + httpbin.url + '/cookies/set?hello=world2', 'Hello:World2', env=self.env()) assert HTTP_OK in r3 # Get a response from the updated session. - r4 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) + r4 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) assert HTTP_OK in r4 # Origin can differ on Travis. del r2.json['origin'], r4.json['origin'] # Different for each request. - del r2.json['headers']['X-Request-Id'] - del r4.json['headers']['X-Request-Id'] # Should be the same as before r3. assert r2.json == r4.json @@ -102,51 +107,58 @@ def test_session_read_only(self): class TestSession(SessionTestBase): """Stand-alone session tests.""" - def test_session_ignored_header_prefixes(self): - r1 = http('--session=test', 'GET', httpbin('/get'), + def test_session_ignored_header_prefixes(self, httpbin): + self.start_session(httpbin) + r1 = http('--session=test', 'GET', httpbin.url + '/get', 'Content-Type: text/plain', 'If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT', env=self.env()) assert HTTP_OK in r1 - r2 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) + r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) assert HTTP_OK in r2 - assert 'Content-Type' not in r2.json['headers'] + assert no_content_type(r2.json['headers']) assert 'If-Unmodified-Since' not in r2.json['headers'] - def test_session_by_path(self): + def test_session_by_path(self, httpbin): + self.start_session(httpbin) session_path = os.path.join(self.config_dir, 'session-by-path.json') - r1 = http('--session=' + session_path, 'GET', httpbin('/get'), + r1 = http('--session=' + session_path, 'GET', httpbin.url + '/get', 'Foo:Bar', env=self.env()) assert HTTP_OK in r1 - r2 = http('--session=' + session_path, 'GET', httpbin('/get'), + r2 = http('--session=' + session_path, 'GET', httpbin.url + '/get', env=self.env()) assert HTTP_OK in r2 assert r2.json['headers']['Foo'] == 'Bar' - def test_session_unicode(self): - r1 = http('--session=test', '--auth', u'test:' + UNICODE, - 'GET', httpbin('/get'), - u'Test:%s' % UNICODE, + def test_session_unicode(self, httpbin): + self.start_session(httpbin) + + r1 = http('--session=test', u'--auth=test:' + UNICODE, + 'GET', httpbin.url + '/get', u'Test:%s' % UNICODE, env=self.env()) assert HTTP_OK in r1 r2 = http('--session=test', '--verbose', 'GET', - httpbin('/get'), env=self.env()) + httpbin.url + '/get', env=self.env()) assert HTTP_OK in r2 + + # FIXME: Authorization *sometimes* is not present on Python3 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): + def test_session_default_header_value_overwritten(self, httpbin): + self.start_session(httpbin) # https://github.com/jakubroztocil/httpie/issues/180 - r1 = http('--session=test', httpbin('/headers'), 'User-Agent:custom', + r1 = http('--session=test', + httpbin.url + '/headers', 'User-Agent:custom', env=self.env()) assert HTTP_OK in r1 assert r1.json['headers']['User-Agent'] == 'custom' - r2 = http('--session=test', httpbin('/headers'), env=self.env()) + r2 = http('--session=test', httpbin.url + '/headers', env=self.env()) assert HTTP_OK in r2 assert r2.json['headers']['User-Agent'] == 'custom' diff --git a/tests/test_stream.py b/tests/test_stream.py index d21e98efd2..9e96751908 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -2,7 +2,7 @@ from httpie.compat import is_windows from httpie.output.streams import BINARY_SUPPRESSED_NOTICE -from utils import http, httpbin, TestEnvironment +from utils import http, TestEnvironment from fixtures import BIN_FILE_CONTENT, BIN_FILE_PATH @@ -11,26 +11,26 @@ class TestStream: @pytest.mark.skipif(is_windows, reason='Pretty redirect not supported under Windows') - def test_pretty_redirected_stream(self): + def test_pretty_redirected_stream(self, httpbin): """Test that --stream works with prettified redirected output.""" with open(BIN_FILE_PATH, 'rb') as f: env = TestEnvironment(colors=256, stdin=f, stdin_isatty=False, stdout_isatty=False) r = http('--verbose', '--pretty=all', '--stream', 'GET', - httpbin('/get'), env=env) + httpbin.url + '/get', env=env) assert BINARY_SUPPRESSED_NOTICE.decode() in r - def test_encoded_stream(self): + def test_encoded_stream(self, 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) r = http('--pretty=none', '--stream', '--verbose', 'GET', - httpbin('/get'), env=env) + httpbin.url + '/get', env=env) assert BINARY_SUPPRESSED_NOTICE.decode() in r - def test_redirected_stream(self): + def test_redirected_stream(self, httpbin): """Test that --stream works with non-prettified redirected terminal output.""" with open(BIN_FILE_PATH, 'rb') as f: @@ -38,5 +38,5 @@ def test_redirected_stream(self): stdin_isatty=False, stdin=f) r = http('--pretty=none', '--stream', '--verbose', 'GET', - httpbin('/get'), env=env) + httpbin.url + '/get', env=env) assert BIN_FILE_CONTENT in r diff --git a/tests/test_unicode.py b/tests/test_unicode.py index 0932c9d4f2..abcd9ebd7a 100644 --- a/tests/test_unicode.py +++ b/tests/test_unicode.py @@ -3,85 +3,85 @@ Various unicode handling related tests. """ -from utils import http, httpbin, HTTP_OK +from utils import http, HTTP_OK from fixtures import UNICODE class TestUnicode: - def test_unicode_headers(self): + def test_unicode_headers(self, httpbin): # httpbin doesn't interpret utf8 headers - r = http(httpbin('/headers'), u'Test:%s' % UNICODE) + r = http(httpbin.url + '/headers', u'Test:%s' % UNICODE) assert HTTP_OK in r - def test_unicode_headers_verbose(self): + def test_unicode_headers_verbose(self, httpbin): # httpbin doesn't interpret utf8 headers - r = http('--verbose', httpbin('/headers'), u'Test:%s' % UNICODE) + r = http('--verbose', httpbin.url + '/headers', u'Test:%s' % UNICODE) assert HTTP_OK in r assert UNICODE in r - def test_unicode_form_item(self): - r = http('--form', 'POST', httpbin('/post'), u'test=%s' % UNICODE) + def test_unicode_form_item(self, httpbin): + r = http('--form', 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) assert HTTP_OK in r assert r.json['form'] == {'test': UNICODE} - def test_unicode_form_item_verbose(self): + def test_unicode_form_item_verbose(self, httpbin): r = http('--verbose', '--form', - 'POST', httpbin('/post'), u'test=%s' % UNICODE) + 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) assert HTTP_OK in r assert UNICODE in r - def test_unicode_json_item(self): - r = http('--json', 'POST', httpbin('/post'), u'test=%s' % UNICODE) + def test_unicode_json_item(self, httpbin): + r = http('--json', 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) assert HTTP_OK in r assert r.json['json'] == {'test': UNICODE} - def test_unicode_json_item_verbose(self): + def test_unicode_json_item_verbose(self, httpbin): r = http('--verbose', '--json', - 'POST', httpbin('/post'), u'test=%s' % UNICODE) + 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) assert HTTP_OK in r assert UNICODE in r - def test_unicode_raw_json_item(self): - r = http('--json', 'POST', httpbin('/post'), + def test_unicode_raw_json_item(self, httpbin): + r = http('--json', 'POST', httpbin.url + '/post', u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE)) assert HTTP_OK in r assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} - def test_unicode_raw_json_item_verbose(self): - r = http('--json', 'POST', httpbin('/post'), + def test_unicode_raw_json_item_verbose(self, httpbin): + r = http('--json', 'POST', httpbin.url + '/post', u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE)) assert HTTP_OK in r assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} - def test_unicode_url_query_arg_item(self): - r = http(httpbin('/get'), u'test==%s' % UNICODE) + def test_unicode_url_query_arg_item(self, httpbin): + r = http(httpbin.url + '/get', u'test==%s' % UNICODE) assert HTTP_OK in r assert r.json['args'] == {'test': UNICODE}, r - def test_unicode_url_query_arg_item_verbose(self): - r = http('--verbose', httpbin('/get'), u'test==%s' % UNICODE) + def test_unicode_url_query_arg_item_verbose(self, httpbin): + r = http('--verbose', httpbin.url + '/get', u'test==%s' % UNICODE) assert HTTP_OK in r assert UNICODE in r - def test_unicode_url(self): - r = http(httpbin(u'/get?test=' + UNICODE)) + def test_unicode_url(self, httpbin): + r = http(httpbin.url + u'/get?test=' + UNICODE) assert HTTP_OK in r assert r.json['args'] == {'test': UNICODE} # def test_unicode_url_verbose(self): - # r = http(httpbin('--verbose', u'/get?test=' + UNICODE)) + # r = http(httpbin.url + '--verbose', u'/get?test=' + UNICODE) # assert HTTP_OK in r - def test_unicode_basic_auth(self): + def test_unicode_basic_auth(self, httpbin): # it doesn't really authenticate us because httpbin # doesn't interpret the utf8-encoded auth http('--verbose', '--auth', u'test:%s' % UNICODE, - httpbin(u'/basic-auth/test/' + UNICODE)) + httpbin.url + u'/basic-auth/test/' + UNICODE) - def test_unicode_digest_auth(self): + def test_unicode_digest_auth(self, httpbin): # it doesn't really authenticate us because httpbin # doesn't interpret the utf8-encoded auth http('--auth-type=digest', '--auth', u'test:%s' % UNICODE, - httpbin(u'/digest-auth/auth/test/' + UNICODE)) + httpbin.url + u'/digest-auth/auth/test/' + UNICODE) diff --git a/tests/test_uploads.py b/tests/test_uploads.py index 073b98c968..f725c62d71 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -3,23 +3,25 @@ import pytest from httpie.input import ParseError -from utils import TestEnvironment, http, httpbin, HTTP_OK +from utils import TestEnvironment, http, HTTP_OK from fixtures import FILE_PATH_ARG, FILE_PATH, FILE_CONTENT class TestMultipartFormDataFileUpload: - def test_non_existent_file_raises_parse_error(self): + + def test_non_existent_file_raises_parse_error(self, httpbin): with pytest.raises(ParseError): - http('--form', 'POST', httpbin('/post'), 'foo@/__does_not_exist__') + http('--form', + 'POST', httpbin.url + '/post', 'foo@/__does_not_exist__') - def test_upload_ok(self): - r = http('--form', '--verbose', 'POST', httpbin('/post'), + def test_upload_ok(self, httpbin): + r = http('--form', '--verbose', 'POST', httpbin.url + '/post', 'test-file@%s' % FILE_PATH_ARG, 'foo=bar') assert HTTP_OK in r assert 'Content-Disposition: form-data; name="foo"' in r assert 'Content-Disposition: form-data; name="test-file";' \ ' filename="%s"' % os.path.basename(FILE_PATH) in r - assert r.count(FILE_CONTENT) == 2 + assert FILE_CONTENT in r assert '"foo": "bar"' in r @@ -29,27 +31,32 @@ class TestRequestBodyFromFilePath: """ - def test_request_body_from_file_by_path(self): - r = http('--verbose', 'POST', httpbin('/post'), '@' + FILE_PATH_ARG) + def test_request_body_from_file_by_path(self, httpbin): + r = http('--verbose', + 'POST', httpbin.url + '/post', '@' + FILE_PATH_ARG) assert HTTP_OK in r assert FILE_CONTENT in r, r assert '"Content-Type": "text/plain"' in r - def test_request_body_from_file_by_path_with_explicit_content_type(self): - r = http('POST', httpbin('/post'), '@' + FILE_PATH_ARG, - 'Content-Type:x-foo/bar') + def test_request_body_from_file_by_path_with_explicit_content_type( + self, httpbin): + r = http('--verbose', + 'POST', httpbin.url + '/post', '@' + FILE_PATH_ARG, + 'Content-Type:text/plain; charset=utf8') assert HTTP_OK in r assert FILE_CONTENT in r - assert '"Content-Type": "x-foo/bar"' in r + assert 'Content-Type: text/plain; charset=utf8' in r - def test_request_body_from_file_by_path_no_field_name_allowed(self): + def test_request_body_from_file_by_path_no_field_name_allowed( + self, httpbin): env = TestEnvironment(stdin_isatty=True) - r = http('POST', httpbin('/post'), 'field-name@' + FILE_PATH_ARG, + 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): + def test_request_body_from_file_by_path_no_data_items_allowed( + self, httpbin): env = TestEnvironment(stdin_isatty=False) - r = http('POST', httpbin('/post'), '@' + FILE_PATH_ARG, 'foo=bar', + r = http('POST', httpbin.url + '/post', '@' + FILE_PATH_ARG, 'foo=bar', env=env, error_exit_ok=True) assert 'cannot be mixed' in r.stderr diff --git a/tests/test_windows.py b/tests/test_windows.py index ad15fe5262..91669f5c30 100644 --- a/tests/test_windows.py +++ b/tests/test_windows.py @@ -4,7 +4,7 @@ import pytest from httpie.context import Environment -from utils import TestEnvironment, http, httpbin +from utils import TestEnvironment, http from httpie.compat import is_windows @@ -13,17 +13,17 @@ class TestWindowsOnly: @pytest.mark.skipif(True, reason='this test for some reason kills the process') - def test_windows_colorized_output(self): + def test_windows_colorized_output(self, httpbin): # Spits out the colorized output. - http(httpbin('/get'), env=Environment()) + http(httpbin.url + '/get', env=Environment()) class TestFakeWindows: - def test_output_file_pretty_not_allowed_on_windows(self): + def test_output_file_pretty_not_allowed_on_windows(self, httpbin): env = TestEnvironment(is_windows=True) output_file = os.path.join( tempfile.gettempdir(), '__httpie_test_output__') r = http('--output', output_file, - '--pretty=all', 'GET', httpbin('/get'), + '--pretty=all', 'GET', httpbin.url + '/get', env=env, error_exit_ok=True) assert 'Only terminal output can be colorized on Windows' in r.stderr diff --git a/tests/utils.py b/tests/utils.py index 1a9e5eb6ba..aad27395cd 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -20,7 +20,7 @@ CRLF = '\r\n' COLOR = '\x1b[' -HTTP_OK = 'HTTP/1.1 200' +HTTP_OK = '200 OK' HTTP_OK_COLOR = ( 'HTTP\x1b[39m\x1b[38;5;245m/\x1b[39m\x1b' '[38;5;37m1.1\x1b[39m\x1b[38;5;245m \x1b[39m\x1b[38;5;37m200' @@ -28,22 +28,19 @@ ) -def httpbin(path, auth=None, - base=os.environ.get('HTTPBIN_URL', 'http://httpbin.org')): - """ - Return a fully-qualified httpbin URL for `path`. - - >>> httpbin('/get') - 'http://httpbin.org/get' +def no_content_type(headers): + return ( + 'Content-Type' not in headers + # We need to do also this because of this issue: + # + # TODO: remove this function once the issue is if fixed + or headers['Content-Type'] == 'text/plain' + ) - >>> httpbin('/get', auth='user:password') - 'http://user:password@httpbin.org/get' - """ - if auth: - proto, rest = base.split('://', 1) - base = proto + '://' + auth + '@' + rest - return base.rstrip('/') + path +def add_auth(url, auth): + proto, rest = url.split('://', 1) + return proto + '://' + auth + '@' + rest class TestEnvironment(Environment): @@ -104,7 +101,7 @@ def http(*args, **kwargs): $ http --auth=user:password GET httpbin.org/basic-auth/user/password - >>> r = http('-a', 'user:pw', httpbin('/basic-auth/user/pw')) + >>> r = http('-a', 'user:pw', 'httpbin.org/basic-auth/user/pw') >>> type(r) == StrCLIResponse True >>> r.exit_status diff --git a/tox.ini b/tox.ini index 3e37c17873..d140537ad5 100644 --- a/tox.ini +++ b/tox.ini @@ -13,6 +13,7 @@ envlist = py26, py27, py34, pypy deps = pytest pytest-xdist + pytest-httpbin commands = py.test -n 8 --doctest-modules --basetemp={envtmpdir} {posargs:./tests ./httpie} From 529f3bd9b655cbae5e4d8b6fe9628edce48f2939 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 28 Jun 2014 19:52:10 +0200 Subject: [PATCH 0008/1182] Fixed `python setup.py test` --- setup.py | 4 +++- tests/test_regressions.py | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index a4cc27193a..3e2917c46e 100644 --- a/setup.py +++ b/setup.py @@ -25,8 +25,10 @@ def run_tests(self): tests_require = [ - 'pytest', + # Pytest needs to come last. + # 'pytest-httpbin', + 'pytest', ] diff --git a/tests/test_regressions.py b/tests/test_regressions.py index b80fba38b4..4c939ddd95 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -1,5 +1,4 @@ """Miscellaneous regression tests""" -import socket from utils import http, HTTP_OK From e3c83fca6f0dcada8830a531ef6bedf070756f1f Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Thu, 17 Jul 2014 00:48:56 +0200 Subject: [PATCH 0009/1182] Add the hawk plugin --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 006764c25c..4253b434ba 100644 --- a/README.rst +++ b/README.rst @@ -593,6 +593,7 @@ Auth Plugins * `httpie-oauth `_: OAuth * `httpie-ntlm `_: NTLM (NT LAN Manager) * `httpie-negotiate `_: SPNEGO (GSS Negotiate) +* `requests-hawk `_: Hawk ======= From 0f96348fd1f5435a36ce40f33357fb1872774880 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 28 Jun 2014 20:44:40 +0200 Subject: [PATCH 0010/1182] Cleanup --- README.rst | 1 + httpie/downloads.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index 4253b434ba..1e27a33f02 100644 --- a/README.rst +++ b/README.rst @@ -53,6 +53,7 @@ Main Features * Wget-like downloads * Python 2.6, 2.7 and 3.x support * Linux, Mac OS X and Windows support +* Plugins * Documentation * Test coverage diff --git a/httpie/downloads.py b/httpie/downloads.py index c88e298307..77a8de6775 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -135,12 +135,12 @@ def filename_from_url(url, content_type): return fn -def get_unique_filename(fn, exists=os.path.exists): +def get_unique_filename(filename, exists=os.path.exists): attempt = 0 while True: suffix = '-' + str(attempt) if attempt > 0 else '' - if not exists(fn + suffix): - return fn + suffix + if not exists(filename + suffix): + return filename + suffix attempt += 1 @@ -223,16 +223,16 @@ def start(self, response): else: # TODO: Should the filename be taken from response.history[0].url? # Output file not specified. Pick a name that doesn't exist yet. - fn = None + filename = None if 'Content-Disposition' in response.headers: - fn = filename_from_content_disposition( + filename = filename_from_content_disposition( response.headers['Content-Disposition']) - if not fn: - fn = filename_from_url( + if not filename: + filename = filename_from_url( url=response.url, content_type=response.headers.get('Content-Type'), ) - self._output_file = open(get_unique_filename(fn), mode='a+b') + self._output_file = open(get_unique_filename(filename), mode='a+b') self.status.started( resumed_from=self._resumed_from, From ca36f1de04310de644857ebbea9c94984971ab7c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 18 Jul 2014 13:38:33 +0200 Subject: [PATCH 0011/1182] Handle empty passwords in URL credentials Closes #242 --- README.rst | 3 ++- httpie/input.py | 3 ++- tests/test_auth.py | 18 +++++++++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 1e27a33f02..f20d557f13 100644 --- a/README.rst +++ b/README.rst @@ -1272,10 +1272,11 @@ Changelog * Added ``--cert`` and ``--certkey`` parameters to specify a client side certificate and private key for SSL * Improved unicode support. - * Fixed ``User-Agent`` overwriting when used within a session. * Switched from ``unittest`` to ``pytest``. * Various test suite improvements. * Added `CONTRIBUTING`_. + * Fixed ``User-Agent`` overwriting when used within a session. + * Fixed handling of empty passwords in URL credentials. * `0.8.0`_ (2014-01-25) * Added ``field=@file.txt`` and ``field:=@file.json`` for embedding the contents of text and JSON files into request data. diff --git a/httpie/input.py b/httpie/input.py index 3cb6416828..1efa4f41f4 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -211,7 +211,8 @@ def _process_auth(self): elif url.username is not None: # Handle http://username:password@hostname/ - username, password = url.username, url.password + username = url.username + password = url.password or '' self.args.auth = AuthCredentials( key=username, value=password, diff --git a/tests/test_auth.py b/tests/test_auth.py index 539626152f..5a94ad9409 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -2,8 +2,9 @@ import requests import pytest -from utils import http, add_auth, HTTP_OK +from utils import http, add_auth, HTTP_OK, TestEnvironment import httpie.input +import httpie.cli class TestAuth: @@ -44,3 +45,18 @@ def test_credentials_in_url_auth_flag_has_priority(self, httpbin): r = http('--auth=user:password', 'GET', url) assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} + + @pytest.mark.parametrize('url', [ + 'username@example.org', + 'username:@example.org', + ]) + def test_only_username_in_url(self, url): + """ + https://github.com/jakubroztocil/httpie/issues/242 + + """ + args = httpie.cli.parser.parse_args(args=[url], env=TestEnvironment()) + assert args.auth + assert args.auth.key == 'username' + assert args.auth.value == '' + From 5d2b3f5552b65a51c4df28a0f957f35b504d23c1 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 15 Aug 2014 00:03:27 -0700 Subject: [PATCH 0012/1182] Enable testing on PyPy 3 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 05a3b1556b..39804b6381 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ python: - pypy - 3.3 - 3.4 + - pypy3 script: - make after_success: From 10357109565fd5674fad1fe00defb7f31df51ca3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 5 Sep 2014 07:51:35 +0200 Subject: [PATCH 0013/1182] Added RequestItems named tuple for convenience. --- httpie/input.py | 7 ++++++- setup.py | 36 +++++++++++++++++++++++++++--------- tests/test_cli.py | 39 ++++++++++++++++++++------------------- 3 files changed, 53 insertions(+), 29 deletions(-) diff --git a/httpie/input.py b/httpie/input.py index 1efa4f41f4..c05fa9b8f9 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -8,6 +8,7 @@ import mimetypes import getpass from io import BytesIO +from collections import namedtuple #noinspection PyCompatibility from argparse import ArgumentParser, ArgumentTypeError, ArgumentError @@ -560,6 +561,10 @@ def __setitem__(self, key, value): self[key].append(value) +RequestItems = namedtuple('RequestItems', + ['headers', 'data', 'files', 'params']) + + def parse_items(items, data=None, headers=None, files=None, params=None): """Parse `KeyValue` `items` into `data`, `headers`, `files`, and `params`. @@ -617,7 +622,7 @@ def parse_items(items, data=None, headers=None, files=None, params=None): target[item.key] = value - return headers, data, files, params + return RequestItems(headers, data, files, params) def readable_file_arg(filename): diff --git a/setup.py b/setup.py index 3e2917c46e..4e93a6d588 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,5 @@ +# This is purely the result of trial and error. + import sys import codecs @@ -26,7 +28,7 @@ def run_tests(self): tests_require = [ # Pytest needs to come last. - # + # https://bitbucket.org/pypa/setuptools/issue/196/ 'pytest-httpbin', 'pytest', ] @@ -36,15 +38,30 @@ def run_tests(self): 'requests>=2.3.0', 'Pygments>=1.5' ] -try: - #noinspection PyUnresolvedReferences - import argparse -except ImportError: - install_requires.append('argparse>=1.2.1') -if 'win32' in str(sys.platform).lower(): - # Terminal colors for Windows - install_requires.append('colorama>=0.2.4') +### Conditional dependencies: + +# sdist +if not 'bdist_wheel' in sys.argv: + try: + #noinspection PyUnresolvedReferences + import argparse + except ImportError: + install_requires.append('argparse>=1.2.1') + + if 'win32' in str(sys.platform).lower(): + # Terminal colors for Windows + install_requires.append('colorama>=0.2.4') + + +# bdist_wheel +extras_require = { + # http://wheel.readthedocs.org/en/latest/#defining-conditional-dependencies + ':python_version == "2.6"' + ' or python_version == "3.0"' + ' or python_version == "3.1" ': ['argparse>=1.2.1'], + ':sys_platform == "win32"': ['colorama>=0.2.4'], +} def long_description(): @@ -67,6 +84,7 @@ def long_description(): 'http = httpie.__main__:main', ], }, + extras_require=extras_require, install_requires=install_requires, tests_require=tests_require, cmdclass={'test': PyTest}, diff --git a/tests/test_cli.py b/tests/test_cli.py index 103d954354..f8009153f5 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -27,32 +27,32 @@ def test_invalid_items(self): self.key_value_type, item) def test_escape(self): - headers, data, files, params = input.parse_items([ + items = input.parse_items([ # headers - self.key_value_type('foo\\:bar:baz'), - self.key_value_type('jack\\@jill:hill'), + self.key_value_type(r'foo\:bar:baz'), + self.key_value_type(r'jack\@jill:hill'), # data - self.key_value_type('baz\\=bar=foo'), + self.key_value_type(r'baz\=bar=foo'), # files - self.key_value_type('bar\\@baz@%s' % FILE_PATH_ARG) + self.key_value_type(r'bar\@baz@%s' % FILE_PATH_ARG) ]) # `requests.structures.CaseInsensitiveDict` => `dict` - headers = dict(headers._store.values()) + headers = dict(items.headers._store.values()) assert headers == { 'foo:bar': 'baz', 'jack@jill': 'hill', } - assert data == {'baz=bar': 'foo'} - assert 'bar@baz' in files + assert items.data == {'baz=bar': 'foo'} + assert 'bar@baz' in items.files def test_escape_longsep(self): - headers, data, files, params = input.parse_items([ - self.key_value_type('bob\\:==foo'), + items = input.parse_items([ + self.key_value_type(r'bob\:==foo'), ]) - assert params == {'bob:': 'foo'} + assert items.params == {'bob:': 'foo'} def test_valid_items(self): - headers, data, files, params = input.parse_items([ + items = input.parse_items([ self.key_value_type('string=value'), self.key_value_type('header:value'), self.key_value_type('list:=["a", 1, {}, false]'), @@ -68,14 +68,14 @@ def test_valid_items(self): # Parsed headers # `requests.structures.CaseInsensitiveDict` => `dict` - headers = dict(headers._store.values()) + headers = dict(items.headers._store.values()) assert headers == {'header': 'value', 'eh': ''} # Parsed data - raw_json_embed = data.pop('raw-json-embed') + raw_json_embed = items.data.pop('raw-json-embed') assert raw_json_embed == json.loads(JSON_FILE_CONTENT) - data['string-embed'] = data['string-embed'].strip() - assert dict(data) == { + items.data['string-embed'] = items.data['string-embed'].strip() + assert dict(items.data) == { "ed": "", "string": "value", "bool": True, @@ -85,11 +85,12 @@ def test_valid_items(self): } # Parsed query string parameters - assert params == {'query': 'value'} + assert items.params == {'query': 'value'} # Parsed file fields - assert 'file' in files - assert files['file'][1].read().strip().decode('utf8') == FILE_CONTENT + assert 'file' in items.files + assert (items.files['file'][1].read().strip().decode('utf8') + == FILE_CONTENT) class TestQuerystring: From 5084f18568ae58fe212d99546bfda8023073ac82 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 5 Sep 2014 18:33:46 +0200 Subject: [PATCH 0014/1182] '\' only escapes separator characters in req-items It makes easier to work with Windows paths. Closes #253, #254 --- README.rst | 3 +++ httpie/input.py | 23 +++++++++++++------- tests/test_cli.py | 53 +++++++++++++++++++++++++++++------------------ 3 files changed, 51 insertions(+), 28 deletions(-) diff --git a/README.rst b/README.rst index f20d557f13..6d37e8aea5 100644 --- a/README.rst +++ b/README.rst @@ -1277,6 +1277,9 @@ Changelog * Added `CONTRIBUTING`_. * Fixed ``User-Agent`` overwriting when used within a session. * Fixed handling of empty passwords in URL credentials. + * To make it easier to deal with Windows paths in request items, ``\`` + now only special characters (the ones that are used as key-value + separators). * `0.8.0`_ (2014-01-25) * Added ``field=@file.txt`` and ``field:=@file.json`` for embedding the contents of text and JSON files into request data. diff --git a/httpie/input.py b/httpie/input.py index c05fa9b8f9..44a96fa611 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -398,6 +398,9 @@ def __init__(self, key, value, sep, orig): def __eq__(self, other): return self.__dict__ == other.__dict__ + def __repr__(self): + return repr(self.__dict__) + class SessionNameValidator(object): @@ -424,6 +427,9 @@ class KeyValueArgType(object): def __init__(self, *separators): self.separators = separators + self.special_characters = set('\\') + for separator in separators: + self.special_characters.update(separator) def __call__(self, string): """Parse `string` and return `self.key_value_class()` instance. @@ -446,17 +452,18 @@ def tokenize(s): => ['foo', Escaped('='), 'bar', Escaped('\\'), 'baz'] """ + backslash = '\\' tokens = [''] - esc = False + s = iter(s) for c in s: - if esc: - tokens.extend([Escaped(c), '']) - esc = False - else: - if c == '\\': - esc = True + if c == backslash: + nc = next(s, '') + if nc in self.special_characters: + tokens.extend([Escaped(nc), '']) else: - tokens[-1] += c + tokens[-1] += c + nc + else: + tokens[-1] += c return tokens tokens = tokenize(string) diff --git a/tests/test_cli.py b/tests/test_cli.py index f8009153f5..d7e0c01e6f 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -18,26 +18,28 @@ class TestItemParsing: - key_value_type = KeyValueArgType(*input.SEP_GROUP_ALL_ITEMS) + key_value = KeyValueArgType(*input.SEP_GROUP_ALL_ITEMS) def test_invalid_items(self): items = ['no-separator'] for item in items: - pytest.raises(argparse.ArgumentTypeError, - self.key_value_type, item) + pytest.raises(argparse.ArgumentTypeError, self.key_value, item) - def test_escape(self): + def test_escape_separator(self): items = input.parse_items([ # headers - self.key_value_type(r'foo\:bar:baz'), - self.key_value_type(r'jack\@jill:hill'), + self.key_value(r'foo\:bar:baz'), + self.key_value(r'jack\@jill:hill'), + # data - self.key_value_type(r'baz\=bar=foo'), + self.key_value(r'baz\=bar=foo'), + # files - self.key_value_type(r'bar\@baz@%s' % FILE_PATH_ARG) + self.key_value(r'bar\@baz@%s' % FILE_PATH_ARG), ]) # `requests.structures.CaseInsensitiveDict` => `dict` headers = dict(items.headers._store.values()) + assert headers == { 'foo:bar': 'baz', 'jack@jill': 'hill', @@ -45,25 +47,36 @@ def test_escape(self): assert items.data == {'baz=bar': 'foo'} 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'), + ]) + def test_backslash_before_non_special_character_does_not_escape( + self, string, key, sep, value): + expected = KeyValue(orig=string, key=key, sep=sep, value=value) + actual = self.key_value(string) + assert actual == expected + def test_escape_longsep(self): items = input.parse_items([ - self.key_value_type(r'bob\:==foo'), + self.key_value(r'bob\:==foo'), ]) assert items.params == {'bob:': 'foo'} def test_valid_items(self): items = input.parse_items([ - self.key_value_type('string=value'), - self.key_value_type('header:value'), - self.key_value_type('list:=["a", 1, {}, false]'), - self.key_value_type('obj:={"a": "b"}'), - self.key_value_type('eh:'), - self.key_value_type('ed='), - self.key_value_type('bool:=true'), - self.key_value_type('file@' + FILE_PATH_ARG), - self.key_value_type('query==value'), - self.key_value_type('string-embed=@' + FILE_PATH_ARG), - self.key_value_type('raw-json-embed:=@' + JSON_FILE_PATH_ARG), + self.key_value('string=value'), + self.key_value('header:value'), + self.key_value('list:=["a", 1, {}, false]'), + self.key_value('obj:={"a": "b"}'), + self.key_value('eh:'), + self.key_value('ed='), + self.key_value('bool:=true'), + self.key_value('file@' + FILE_PATH_ARG), + self.key_value('query==value'), + self.key_value('string-embed=@' + FILE_PATH_ARG), + self.key_value('raw-json-embed:=@' + JSON_FILE_PATH_ARG), ]) # Parsed headers From af873effb6f79963696c8f2656e5df676546c54b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 5 Sep 2014 18:40:28 +0200 Subject: [PATCH 0015/1182] Changelog typo. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6d37e8aea5..e4bdfc2e39 100644 --- a/README.rst +++ b/README.rst @@ -1278,7 +1278,7 @@ Changelog * Fixed ``User-Agent`` overwriting when used within a session. * Fixed handling of empty passwords in URL credentials. * To make it easier to deal with Windows paths in request items, ``\`` - now only special characters (the ones that are used as key-value + now only escapes special characters (the ones that are used as key-value separators). * `0.8.0`_ (2014-01-25) * Added ``field=@file.txt`` and ``field:=@file.json`` for embedding From b0effe07d9db9a04f444773f082dd2c36d5215d9 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 7 Sep 2014 10:20:32 +0200 Subject: [PATCH 0016/1182] Fixed --output=/dev/null on Linux Closes #252 --- README.rst | 1 + httpie/input.py | 10 +++++++++- tests/test_regressions.py | 11 +++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e4bdfc2e39..b0e70e2a6b 100644 --- a/README.rst +++ b/README.rst @@ -1280,6 +1280,7 @@ Changelog * To make it easier to deal with Windows paths in request items, ``\`` now only escapes special characters (the ones that are used as key-value separators). + * Fixed ``--output=/dev/null`` on Linux. * `0.8.0`_ (2014-01-25) * Added ``field=@file.txt`` and ``field:=@file.json`` for embedding the contents of text and JSON files into request data. diff --git a/httpie/input.py b/httpie/input.py index 44a96fa611..6420921baf 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -5,6 +5,7 @@ import sys import re import json +import errno import mimetypes import getpass from io import BytesIO @@ -185,7 +186,14 @@ def _setup_standard_streams(self): # `stdout`. The file is opened for appending, which isn't what # we want in this case. self.args.output_file.seek(0) - self.args.output_file.truncate() + try: + self.args.output_file.truncate() + except IOError as e: + if e.errno == errno.EINVAL: + # E.g. /dev/null on Linux. + pass + else: + raise self.env.stdout = self.args.output_file self.env.stdout_isatty = False diff --git a/tests/test_regressions.py b/tests/test_regressions.py index 4c939ddd95..b22b140040 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -1,6 +1,8 @@ """Miscellaneous regression tests""" +import pytest from utils import http, HTTP_OK +from httpie.compat import is_windows def test_Host_header_overwrite(httpbin): @@ -14,3 +16,12 @@ def test_Host_header_overwrite(httpbin): assert HTTP_OK in r assert r.lower().count('host:') == 1 assert 'host: {0}'.format(host) in r + + +@pytest.mark.skipif(is_windows, reason='Unix-only') +def test_output_devnull(httpbin): + """ + https://github.com/jakubroztocil/httpie/issues/252 + + """ + http('--output=/dev/null', httpbin + '/get') From 6aa711c69f16fab005c487927a3ac750f94b6d19 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 8 Sep 2014 07:44:25 +0200 Subject: [PATCH 0017/1182] Removed pytest-xdist The test suite is much less IO-bound now with the local httpbin instance (via pytest-httpbin). Therefore, paralelization is not as helpful. --- Makefile | 4 ++-- requirements-dev.txt | 1 - tox.ini | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 1c8868bf3a..26b650838d 100644 --- a/Makefile +++ b/Makefile @@ -22,8 +22,8 @@ init: uninstall-httpie @echo test: init - @echo $(TAG)Running tests in on current Python in parallel and with coverage $(END) - py.test --cov ./httpie --cov ./tests -n 8 --doctest-modules --verbose ./httpie ./tests + @echo $(TAG)Running tests in on current Python with coverage $(END) + py.test --cov ./httpie --cov ./tests --doctest-modules --verbose ./httpie ./tests @echo test-tox: init diff --git a/requirements-dev.txt b/requirements-dev.txt index 1b0b06ae3e..7b50ea8b81 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,6 +1,5 @@ tox pytest -pytest-xdist pytest-cov pytest-httpbin docutils diff --git a/tox.ini b/tox.ini index d140537ad5..9a1911df9f 100644 --- a/tox.ini +++ b/tox.ini @@ -12,8 +12,7 @@ envlist = py26, py27, py34, pypy [testenv] deps = pytest - pytest-xdist pytest-httpbin commands = - py.test -n 8 --doctest-modules --basetemp={envtmpdir} {posargs:./tests ./httpie} + py.test --verbose --doctest-modules --basetemp={envtmpdir} {posargs:./tests ./httpie} From 58b51a82777b4ce435f6d6e4aa7e3af7cc2645f6 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 8 Sep 2014 07:46:53 +0200 Subject: [PATCH 0018/1182] Improved terminal color depth detection via curses Closes #244 --- httpie/context.py | 26 ++++++++++++++++++-------- httpie/output/formatters/colors.py | 2 +- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/httpie/context.py b/httpie/context.py index 13763475a8..ed7ff13ac7 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -1,4 +1,3 @@ -import os import sys from requests.compat import is_windows @@ -18,7 +17,6 @@ class Environment(object): """ is_windows = is_windows config_dir = DEFAULT_CONFIG_DIR - colors = 256 if '256color' in os.environ.get('TERM', '') else 88 stdin = sys.stdin stdin_isatty = stdin.isatty() stdin_encoding = None @@ -27,13 +25,24 @@ class Environment(object): stdout_encoding = None stderr = sys.stderr stderr_isatty = stderr.isatty() - if is_windows: + if not is_windows: + import curses + curses.setupterm() + colors = curses.tigetnum('colors') + del curses + else: + colors = 256 # noinspection PyUnresolvedReferences - from colorama.initialise import wrap_stream - stdout = wrap_stream(stdout, convert=None, strip=None, - autoreset=True, wrap=True) - stderr = wrap_stream(stderr, convert=None, strip=None, - autoreset=True, wrap=True) + import colorama.initialise + stdout = colorama.initialise.wrap_stream( + stdout, convert=None, strip=None, + autoreset=True, wrap=True + ) + stderr = colorama.initialise.wrap_stream( + stderr, convert=None, strip=None, + autoreset=True, wrap=True + ) + del colorama def __init__(self, **kwargs): """ @@ -51,6 +60,7 @@ def __init__(self, **kwargs): if self.stdout_encoding is None: actual_stdout = self.stdout if is_windows: + # noinspection PyUnresolvedReferences from colorama import AnsiToWin32 if isinstance(self.stdout, AnsiToWin32): actual_stdout = self.stdout.wrapped diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index bcec7ba116..d9276d6f9b 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -42,7 +42,7 @@ def __init__(self, env, color_scheme=DEFAULT_STYLE, **kwargs): except ClassNotFound: style_class = Solarized256Style - if env.is_windows or env.colors == 256: + if env.colors == 256: fmt_class = Terminal256Formatter else: fmt_class = TerminalFormatter From 24f46ff3efec43b2bd7a9048307e545b511f1d98 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 8 Sep 2014 07:50:41 +0200 Subject: [PATCH 0019/1182] Changelog --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index b0e70e2a6b..1141fa4203 100644 --- a/README.rst +++ b/README.rst @@ -1281,6 +1281,7 @@ Changelog now only escapes special characters (the ones that are used as key-value separators). * Fixed ``--output=/dev/null`` on Linux. + * Improved terminal color depth detection via ``curses``. * `0.8.0`_ (2014-01-25) * Added ``field=@file.txt`` and ``field:=@file.json`` for embedding the contents of text and JSON files into request data. From f1cd289d51f01004bcfdcd9d991ca54b6a8185fb Mon Sep 17 00:00:00 2001 From: Dennis Brakhane Date: Wed, 24 Sep 2014 23:35:14 +0200 Subject: [PATCH 0020/1182] Fallback to JSON highlighting if subtype contains json Some JSON based formats like JSON Home Documents[1] don't use a '+json' suffix, but simply contain json in their MIME type. Also, some servers might use (outdated) types like 'application/x-json'. The JSON formatter can already handle those cases, but the highlighter was ignoring them. This commit will let the highlighter choose the JSON lexer if no other lexer could be found and the MIME subtype contains 'json' [1] http://tools.ietf.org/html/draft-nottingham-json-home-03 --- AUTHORS.rst | 1 + httpie/output/formatters/colors.py | 4 ++++ tests/test_output.py | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 9d445427b2..a066f5a451 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -31,3 +31,4 @@ Patches and ideas * `Justin Bonnar `_ * `Nathan LaFreniere `_ * `Matthias Lehmann `_ +* `Dennis Brakhane `_ diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index d9276d6f9b..667ae91ad9 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -76,6 +76,10 @@ def get_lexer(mime): '%s/%s' % (type_, subtype_name), '%s/%s' % (type_, subtype_suffix) ]) + # as a last resort, if no lexer feels responsible, and + # the subtype contains 'json', take the JSON lexer + if 'json' in subtype: + lexer_names.append('json') lexer = None for mime_type in mime_types: try: diff --git a/tests/test_output.py b/tests/test_output.py index ad2dec041f..b4e2db3d2c 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -32,9 +32,13 @@ class TestColors: 'application/json', 'application/json+foo', 'application/foo+json', + 'application/json-foo', + 'application/x-json', 'foo/json', 'foo/json+bar', 'foo/bar+json', + 'foo/json-foo', + 'foo/x-json', ]) def test_get_lexer(self, mime): lexer = get_lexer(mime) From 2078ece95ac32442e316a6458338814957c6e0bd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 10 Sep 2014 13:08:39 +0200 Subject: [PATCH 0021/1182] Cleanup --- httpie/input.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/httpie/input.py b/httpie/input.py index 6420921baf..f2b95ca42b 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -452,8 +452,8 @@ def __call__(self, string): class Escaped(str): """Represents an escaped character.""" - def tokenize(s): - """Tokenize `s`. There are only two token types - strings + def tokenize(string): + """Tokenize `string`. There are only two token types - strings and escaped characters: tokenize(r'foo\=bar\\baz') @@ -462,16 +462,16 @@ def tokenize(s): """ backslash = '\\' tokens = [''] - s = iter(s) - for c in s: - if c == backslash: - nc = next(s, '') - if nc in self.special_characters: - tokens.extend([Escaped(nc), '']) + characters = iter(string) + for char in characters: + if char == backslash: + next_char = next(characters, '') + if next_char in self.special_characters: + tokens.extend([Escaped(next_char), '']) else: - tokens[-1] += c + nc + tokens[-1] += char + next_char else: - tokens[-1] += c + tokens[-1] += char return tokens tokens = tokenize(string) From c301305a59ddff7fc17c3fba1ce2b1418deddb28 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 16 Sep 2014 12:36:14 +0200 Subject: [PATCH 0022/1182] Cleanup. --- httpie/input.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/httpie/input.py b/httpie/input.py index f2b95ca42b..111775ac77 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -460,16 +460,15 @@ def tokenize(string): => ['foo', Escaped('='), 'bar', Escaped('\\'), 'baz'] """ - backslash = '\\' tokens = [''] characters = iter(string) for char in characters: - if char == backslash: - next_char = next(characters, '') - if next_char in self.special_characters: - tokens.extend([Escaped(next_char), '']) + if char == '\\': + char = next(characters, '') + if char not in self.special_characters: + tokens[-1] += '\\' + char else: - tokens[-1] += char + next_char + tokens.extend([Escaped(char), '']) else: tokens[-1] += char return tokens From 04819577154fc1b11fc20ae7ac584d67614eca25 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 20 Oct 2014 14:40:55 +0200 Subject: [PATCH 0023/1182] Fixed multiple uploads with the same field name Closes #267 --- README.rst | 1 + httpie/config.py | 2 +- httpie/context.py | 9 ++++-- httpie/input.py | 65 +++++++++++++++++++++++++++---------------- tests/test_cli.py | 24 ++++++++++++++-- tests/test_uploads.py | 11 ++++++++ tox.ini | 3 ++ 7 files changed, 85 insertions(+), 30 deletions(-) diff --git a/README.rst b/README.rst index 1141fa4203..d5815432b2 100644 --- a/README.rst +++ b/README.rst @@ -1277,6 +1277,7 @@ Changelog * Added `CONTRIBUTING`_. * Fixed ``User-Agent`` overwriting when used within a session. * Fixed handling of empty passwords in URL credentials. + * Fixed multiple file uploads with the same form field name. * To make it easier to deal with Windows paths in request items, ``\`` now only escapes special characters (the ones that are used as key-value separators). diff --git a/httpie/config.py b/httpie/config.py index e80aa89f3d..fa1f789a42 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -48,7 +48,7 @@ def load(self): except ValueError as e: raise ValueError( 'Invalid %s JSON: %s [%s]' % - (type(self).__name__, e.message, self.path) + (type(self).__name__, str(e), self.path) ) self.update(data) except IOError as e: diff --git a/httpie/context.py b/httpie/context.py index ed7ff13ac7..f9af362902 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -25,13 +25,16 @@ class Environment(object): stdout_encoding = None stderr = sys.stderr stderr_isatty = stderr.isatty() + colors = 256 if not is_windows: import curses - curses.setupterm() - colors = curses.tigetnum('colors') + try: + curses.setupterm() + colors = curses.tigetnum('colors') + except curses.error: + pass del curses else: - colors = 256 # noinspection PyUnresolvedReferences import colorama.initialise stdout = colorama.initialise.wrap_stream( diff --git a/httpie/input.py b/httpie/input.py index 111775ac77..fc4967f185 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -309,21 +309,20 @@ def _parse_items(self): and `args.files`. """ - self.args.headers = CaseInsensitiveDict() - self.args.data = ParamDict() if self.args.form else OrderedDict() - self.args.files = OrderedDict() - self.args.params = ParamDict() - try: - parse_items(items=self.args.items, - headers=self.args.headers, - data=self.args.data, - files=self.args.files, - params=self.args.params) + items = parse_items( + items=self.args.items, + data_class=ParamsDict if self.args.form else OrderedDict + ) except ParseError as e: if self.args.traceback: raise self.error(e.args[0]) + else: + self.args.headers = items.headers + self.args.data = items.data + self.args.files = items.files + self.args.params = items.params if self.args.files and not self.args.form: # `http url @/path/to/file` @@ -555,7 +554,7 @@ def __call__(self, string): ) -class ParamDict(OrderedDict): +class RequestItemsDict(OrderedDict): """Multi-value dict for URL parameters and form data.""" #noinspection PyMethodOverriding @@ -567,31 +566,46 @@ def __setitem__(self, key, value): data and URL params. """ + assert not isinstance(value, list) if key not in self: - super(ParamDict, self).__setitem__(key, value) + super(RequestItemsDict, self).__setitem__(key, value) else: if not isinstance(self[key], list): - super(ParamDict, self).__setitem__(key, [self[key]]) + super(RequestItemsDict, self).__setitem__(key, [self[key]]) self[key].append(value) +class ParamsDict(RequestItemsDict): + pass + + +class DataDict(RequestItemsDict): + + def items(self): + for key, values in super(RequestItemsDict, self).items(): + if not isinstance(values, list): + values = [values] + for value in values: + yield key, value + + RequestItems = namedtuple('RequestItems', ['headers', 'data', 'files', 'params']) -def parse_items(items, data=None, headers=None, files=None, params=None): +def parse_items(items, + headers_class=CaseInsensitiveDict, + data_class=OrderedDict, + files_class=DataDict, + params_class=ParamsDict): """Parse `KeyValue` `items` into `data`, `headers`, `files`, and `params`. """ - if headers is None: - headers = CaseInsensitiveDict() - if data is None: - data = OrderedDict() - if files is None: - files = OrderedDict() - if params is None: - params = ParamDict() + headers = [] + data = [] + files = [] + params = [] for item in items: value = item.value @@ -634,9 +648,12 @@ def parse_items(items, data=None, headers=None, files=None, params=None): else: raise TypeError(item) - target[item.key] = value + target.append((item.key, value)) - return RequestItems(headers, data, files, params) + return RequestItems(headers_class(headers), + data_class(data), + files_class(files), + params_class(params)) def readable_file_arg(filename): diff --git a/tests/test_cli.py b/tests/test_cli.py index d7e0c01e6f..f5754edc77 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,11 +2,12 @@ import json # noinspection PyCompatibility import argparse +import os import pytest from httpie import input -from httpie.input import KeyValue, KeyValueArgType +from httpie.input import KeyValue, KeyValueArgType, DataDict from httpie import ExitStatus from httpie.cli import parser from utils import TestEnvironment, http, HTTP_OK @@ -105,6 +106,25 @@ def test_valid_items(self): assert (items.files['file'][1].read().strip().decode('utf8') == FILE_CONTENT) + def test_multiple_file_fields_with_same_field_name(self): + items = input.parse_items([ + self.key_value('file_field@' + FILE_PATH_ARG), + self.key_value('file_field@' + FILE_PATH_ARG), + ]) + assert len(items.files['file_field']) == 2 + + def test_multiple_text_fields_with_same_field_name(self): + items = input.parse_items( + [self.key_value('text_field=a'), + self.key_value('text_field=b')], + data_class=DataDict + ) + assert items.data['text_field'] == ['a', 'b'] + assert list(items.data.items()) == [ + ('text_field', 'a'), + ('text_field', 'b'), + ] + class TestQuerystring: def test_query_string_params_in_url(self, httpbin): @@ -134,7 +154,7 @@ def test_query_string_params_in_url_and_items_with_duplicates(self, assert '"url": "%s"' % url in r -class TestCLIParser: +class TestURLshorthand: def test_expand_localhost_shorthand(self): args = parser.parse_args(args=[':'], env=TestEnvironment()) assert args.url == 'http://localhost' diff --git a/tests/test_uploads.py b/tests/test_uploads.py index f725c62d71..e97bdafb9f 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -24,6 +24,17 @@ def test_upload_ok(self, httpbin): assert FILE_CONTENT in r assert '"foo": "bar"' in r + def test_upload_multiple_fields_with_the_same_name(self, httpbin): + r = http('--form', '--verbose', 'POST', httpbin.url + '/post', + 'test-file@%s' % FILE_PATH_ARG, + 'test-file@%s' % FILE_PATH_ARG) + assert HTTP_OK in r + assert r.count('Content-Disposition: form-data; name="test-file";' + ' filename="%s"' % os.path.basename(FILE_PATH)) == 2 + # Should be 4, but is 3 because httpbin + # doesn't seem to support filed field lists + assert r.count(FILE_CONTENT) in [3, 4] + class TestRequestBodyFromFilePath: """ diff --git a/tox.ini b/tox.ini index 9a1911df9f..1b6ee19b47 100644 --- a/tox.ini +++ b/tox.ini @@ -16,3 +16,6 @@ deps = commands = py.test --verbose --doctest-modules --basetemp={envtmpdir} {posargs:./tests ./httpie} + +[pytest] +addopts = --tb=native From a2b12f75ea6fb010dac6fbf6e5e539ad0e69a2f4 Mon Sep 17 00:00:00 2001 From: Alexander Nelzin Date: Thu, 13 Nov 2014 23:56:05 +0300 Subject: [PATCH 0024/1182] Fixed and added test for JSON properties order. --- httpie/input.py | 2 +- tests/test_httpie.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/httpie/input.py b/httpie/input.py index fc4967f185..19bdd90480 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -640,7 +640,7 @@ def parse_items(items, if item.sep in SEP_GROUP_RAW_JSON_ITEMS: try: - value = json.loads(value) + value = json.loads(value, object_pairs_hook=OrderedDict) except ValueError as e: raise ParseError('"%s": %s' % (item.orig, e)) target = data diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 2ee647ea11..35150dcbd1 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -63,3 +63,8 @@ def test_headers(self, httpbin): assert HTTP_OK in r assert '"User-Agent": "HTTPie' in r, r assert '"Foo": "bar"' in r + + def test_json_order(self, httpbin): + r = http('PATCH', httpbin.url + '/patch', 'order:={"map":{"1":"first","2":"second"}}') + assert HTTP_OK in r + assert r.json['data'] == '{"order": {"map": {"1": "first", "2": "second"}}}' From b2ec4f797fabd95a87f0e966e6dc5a4f74751f36 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 19 Jan 2015 15:39:46 +0100 Subject: [PATCH 0025/1182] Exit with 0 for --version and --help (closes #293). --- httpie/core.py | 9 +++++++-- tests/test_httpie.py | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/httpie/core.py b/httpie/core.py index b9c4fe9b07..95f53abd55 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -163,12 +163,17 @@ def error(msg, *args, **kwargs): env.stderr.write('\n') else: raise - except (KeyboardInterrupt, SystemExit): + except KeyboardInterrupt: if traceback: raise env.stderr.write('\n') exit_status = ExitStatus.ERROR - + except SystemExit as e: + if e.code != ExitStatus.OK: + if traceback: + raise + env.stderr.write('\n') + exit_status = ExitStatus.ERROR except requests.Timeout: exit_status = ExitStatus.ERROR_TIMEOUT error('Request timed out (%ss).', args.timeout) diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 2ee647ea11..a5b9041fdd 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -14,12 +14,12 @@ def test_debug(self): def test_help(self): r = http('--help', error_exit_ok=True) - assert r.exit_status == httpie.ExitStatus.ERROR + assert r.exit_status == httpie.ExitStatus.OK assert 'https://github.com/jakubroztocil/httpie/issues' in r def test_version(self): r = http('--version', error_exit_ok=True) - assert r.exit_status == httpie.ExitStatus.ERROR + assert r.exit_status == httpie.ExitStatus.OK # FIXME: py3 has version in stdout, py2 in stderr assert httpie.__version__ == r.stderr.strip() + r.strip() From 25b1be7c8a09ba4f7bf60b2021aff5dde8da25c4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 23 Jan 2015 22:04:42 +0100 Subject: [PATCH 0026/1182] Work around missing `object_pairs_hook` in Python 2.6 --- httpie/compat.py | 14 +++++++------- httpie/input.py | 8 ++++---- httpie/utils.py | 9 +++++++++ tests/test_httpie.py | 15 ++++++++++++--- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/httpie/compat.py b/httpie/compat.py index bb222d91e1..45ccfe7a11 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -3,28 +3,28 @@ """ # Borrow these from requests: -#noinspection PyUnresolvedReferences +# noinspection PyUnresolvedReferences from requests.compat import is_windows, bytes, str, is_py3, is_py26 try: - #noinspection PyUnresolvedReferences,PyCompatibility + # noinspection PyUnresolvedReferences,PyCompatibility from urllib.parse import urlsplit except ImportError: - #noinspection PyUnresolvedReferences,PyCompatibility + # noinspection PyUnresolvedReferences,PyCompatibility from urlparse import urlsplit try: - #noinspection PyCompatibility + # noinspection PyCompatibility from urllib.request import urlopen except ImportError: - #noinspection PyCompatibility + # noinspection PyCompatibility from urllib2 import urlopen try: from collections import OrderedDict except ImportError: - ### Python 2.6 OrderedDict class, needed for headers, parameters, etc .### - ### + # Python 2.6 OrderedDict class, needed for headers, parameters, etc .### + # # noinspection PyCompatibility from UserDict import DictMixin diff --git a/httpie/input.py b/httpie/input.py index 19bdd90480..ff0bf03407 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -4,13 +4,12 @@ import os import sys import re -import json import errno import mimetypes import getpass from io import BytesIO from collections import namedtuple -#noinspection PyCompatibility +# noinspection PyCompatibility from argparse import ArgumentParser, ArgumentTypeError, ArgumentError # TODO: Use MultiDict for headers once added to `requests`. @@ -19,6 +18,7 @@ from httpie.compat import OrderedDict, urlsplit, str from httpie.sessions import VALID_SESSION_NAME_PATTERN +from httpie.utils import load_json_preserve_order HTTP_POST = 'POST' @@ -111,7 +111,7 @@ def __init__(self, *args, **kwargs): kwargs['add_help'] = False super(Parser, self).__init__(*args, **kwargs) - #noinspection PyMethodOverriding + # noinspection PyMethodOverriding def parse_args(self, env, args=None, namespace=None): self.env = env @@ -640,7 +640,7 @@ def parse_items(items, if item.sep in SEP_GROUP_RAW_JSON_ITEMS: try: - value = json.loads(value, object_pairs_hook=OrderedDict) + value = load_json_preserve_order(value) except ValueError as e: raise ParseError('"%s": %s' % (item.orig, e)) target = data diff --git a/httpie/utils.py b/httpie/utils.py index 0989372c98..ad2119aad8 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -1,4 +1,13 @@ from __future__ import division +import json + +from httpie.compat import is_py26, OrderedDict + + +def load_json_preserve_order(s): + if is_py26: + return json.loads(s) + return json.loads(s, object_pairs_hook=OrderedDict) def humanize_bytes(n, precision=2): diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 0dd0e9cca1..92cb193210 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -1,7 +1,10 @@ """High-level tests.""" +import pytest from utils import TestEnvironment, http, HTTP_OK from fixtures import FILE_PATH, FILE_CONTENT + import httpie +from httpie.compat import is_py26 class TestHTTPie: @@ -64,7 +67,13 @@ def test_headers(self, httpbin): assert '"User-Agent": "HTTPie' in r, r assert '"Foo": "bar"' in r - def test_json_order(self, httpbin): - r = http('PATCH', httpbin.url + '/patch', 'order:={"map":{"1":"first","2":"second"}}') + @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(self, httpbin): + r = http('PATCH', httpbin.url + '/patch', + 'order:={"map":{"1":"first","2":"second"}}') assert HTTP_OK in r - assert r.json['data'] == '{"order": {"map": {"1": "first", "2": "second"}}}' + assert r.json['data'] == \ + '{"order": {"map": {"1": "first", "2": "second"}}}' From d3d78afb6a84e4197651d24224ad3992e7f7ce1f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 23 Jan 2015 22:19:02 +0100 Subject: [PATCH 0027/1182] Pypy3 (2.4.0) curses bug workaround. --- httpie/context.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/httpie/context.py b/httpie/context.py index f9af362902..6be232c493 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -30,7 +30,11 @@ class Environment(object): import curses try: curses.setupterm() - colors = curses.tigetnum('colors') + try: + colors = curses.tigetnum('colors') + except TypeError: + # pypy3 (2.4.0) + colors = curses.tigetnum(b'colors') except curses.error: pass del curses From df07927843130815e3dc854a295e5c86ea4945ee Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 23 Jan 2015 23:54:27 +0100 Subject: [PATCH 0028/1182] --certkey is now --cert-key --- README.rst | 19 ++++++++++--------- httpie/cli.py | 4 ++-- httpie/client.py | 4 ++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/README.rst b/README.rst index d5815432b2..a15c3a8afd 100644 --- a/README.rst +++ b/README.rst @@ -640,7 +640,7 @@ path. The path can also be configured via the environment variable To use a client side certificate for the SSL communication, you can pass the path of the cert file with ``--cert``. If the private key is not contained -in the cert file you may pass the path of the key file with ``--certkey``. +in the cert file you may pass the path of the key file with ``--cert-key``. If you use Python 2.x and need to talk to servers that use **SNI (Server Name Indication)** you need to install some additional dependencies: @@ -1269,20 +1269,21 @@ Changelog *You can click a version name to see a diff with the previous one.* * `0.9.0-dev`_ - * Added ``--cert`` and ``--certkey`` parameters to specify a client side + * Added ``--cert`` and ``--cert-key`` parameters to specify a client side certificate and private key for SSL - * Improved unicode support. - * Switched from ``unittest`` to ``pytest``. - * Various test suite improvements. - * Added `CONTRIBUTING`_. * Fixed ``User-Agent`` overwriting when used within a session. * Fixed handling of empty passwords in URL credentials. * Fixed multiple file uploads with the same form field name. - * To make it easier to deal with Windows paths in request items, ``\`` - now only escapes special characters (the ones that are used as key-value - separators). * Fixed ``--output=/dev/null`` on Linux. + * Improved unicode support. * Improved terminal color depth detection via ``curses``. + * To make it easier to deal with Windows paths in request items, ``\`` + now only escapes special characters (the ones that are used as key-value + separators by HTTPie). + * Switched from ``unittest`` to ``pytest``. + * Various test suite improvements. + * Added `CONTRIBUTING`_. + * Miscellaneous bugfixes. * `0.8.0`_ (2014-01-25) * Added ``field=@file.txt`` and ``field:=@file.json`` for embedding the contents of text and JSON files into request data. diff --git a/httpie/cli.py b/httpie/cli.py index 9b7a454e27..575683cec7 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -471,13 +471,13 @@ def _split_lines(self, text, width): help=""" You can specify a local cert to use as client side SSL certificate. This file may either contain both private key and certificate or you may - specify --certkey separately. + specify --cert-key separately. """ ) network.add_argument( - '--certkey', + '--cert-key', default=None, type=readable_file_arg, help=""" diff --git a/httpie/client.py b/httpie/client.py index 6444c17ec7..1073c63ce2 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -98,8 +98,8 @@ def get_requests_kwargs(args, base_headers=None): cert = None if args.cert: cert = args.cert - if args.certkey: - cert = cert, args.certkey + if args.cert_key: + cert = cert, args.cert_key kwargs = { 'stream': True, From 5fbafc18bc55e18e3e9b254e2f4effbdbd13c1d7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 23 Jan 2015 23:55:03 +0100 Subject: [PATCH 0029/1182] Added tests for client as well as server SSL certificate handling. --- tests/test_ssl.py | 79 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/test_ssl.py diff --git a/tests/test_ssl.py b/tests/test_ssl.py new file mode 100644 index 0000000000..0fda410635 --- /dev/null +++ b/tests/test_ssl.py @@ -0,0 +1,79 @@ +import os + +import pytest +import pytest_httpbin.certs +from requests.exceptions import SSLError + +from httpie import ExitStatus +from utils import http, HTTP_OK, TESTS_ROOT + + +CLIENT_CERT = os.path.join(TESTS_ROOT, 'client_certs', 'client.crt') +CLIENT_KEY = os.path.join(TESTS_ROOT, 'client_certs', 'client.key') +CLIENT_PEM = os.path.join(TESTS_ROOT, 'client_certs', 'client.pem') + +# We test against a local httpbin instance which uses a self-signed cert. +# Requests without --verify= will fail with a verification error. +# See: https://github.com/kevin1024/pytest-httpbin#https-support +CA_BUNDLE = pytest_httpbin.certs.where() + + +class TestClientSSLCertHandling(object): + + def test_cert_file_not_found(self, httpbin_secure): + r = http(httpbin_secure + '/get', + '--verify', CA_BUNDLE, + '--cert', '/__not_found__', + error_exit_ok=True) + assert r.exit_status == ExitStatus.ERROR + assert 'No such file or directory' in r.stderr + + def test_cert_file_invalid(self, httpbin_secure): + with pytest.raises(SSLError): + http(httpbin_secure + '/get', + '--verify', CA_BUNDLE, + '--cert', __file__) + + def test_cert_ok_but_missing_key(self, httpbin_secure): + with pytest.raises(SSLError): + http(httpbin_secure + '/get', + '--verify', CA_BUNDLE, + '--cert', CLIENT_CERT) + + def test_cert_and_key(self, httpbin_secure): + r = http(httpbin_secure + '/get', + '--verify', CA_BUNDLE, + '--cert', CLIENT_CERT, + '--cert-key', CLIENT_KEY) + assert HTTP_OK in r + + def test_cert_pem(self, httpbin_secure): + r = http(httpbin_secure + '/get', + '--verify', CA_BUNDLE, + '--cert', CLIENT_PEM) + assert HTTP_OK in r + + +class TestServerSSLCertHandling(object): + + def test_self_signed_server_cert_by_default_raises_ssl_error( + self, httpbin_secure): + with pytest.raises(SSLError): + http(httpbin_secure.url + '/get') + + def test_verify_no_OK(self, httpbin_secure): + r = http(httpbin_secure.url + '/get', '--verify=no') + assert HTTP_OK in r + + def test_verify_custom_ca_bundle_path( + self, httpbin_secure): + r = http(httpbin_secure.url + '/get', '--verify', CA_BUNDLE) + assert HTTP_OK in r + + def test_verify_custom_ca_bundle_invalid_path(self, httpbin_secure): + with pytest.raises(SSLError): + http(httpbin_secure.url + '/get', '--verify', '/__not_found__') + + def test_verify_custom_ca_bundle_invalid_bundle(self, httpbin_secure): + with pytest.raises(SSLError): + http(httpbin_secure.url + '/get', '--verify', __file__) From 12f2d99bfd49c0197c44ce0876b693df983c50ea Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 23 Jan 2015 23:56:08 +0100 Subject: [PATCH 0030/1182] Added test client SSL certs --- httpie/__init__.py | 2 +- tests/client_certs/client.crt | 29 ++++++++++++ tests/client_certs/client.key | 51 ++++++++++++++++++++ tests/client_certs/client.pem | 87 +++++++++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 tests/client_certs/client.crt create mode 100644 tests/client_certs/client.key create mode 100644 tests/client_certs/client.pem diff --git a/httpie/__init__.py b/httpie/__init__.py index 4971499970..6927924dd3 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '0.9.0-dev' +__version__ = '0.9.0' __licence__ = 'BSD' diff --git a/tests/client_certs/client.crt b/tests/client_certs/client.crt new file mode 100644 index 0000000000..2677d47af6 --- /dev/null +++ b/tests/client_certs/client.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIFAjCCAuoCAQEwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCVVMxCzAJBgNV +BAgTAkNBMQswCQYDVQQHEwJTRjEPMA0GA1UEChMGSFRUUGllMQ8wDQYDVQQDEwZI +VFRQaWUwHhcNMTUwMTIzMjIyNTM2WhcNMTYwMTIzMjIyNTM2WjBFMQswCQYDVQQG +EwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lk +Z2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAu6aP +iR3TpPESWKTS969fxNRoSxl8P4osjhIaUuwblFNZc8/Rn5mCMKmD506JrFV8fktQ +M6JRL7QuDC9vCw0ycr2HCV1sYX/ICgPCXYgmyigH535lb9V9hHjAgy60QgJBgSE7 +lmMYaPpX6OKbT7UlzSwYtfHomXEBFA18Rlc9GwMXH8Et0RQiWIi7S6vpDRpZFxRi +gtXMceK1X8kut2ODv9B5ZwiuXh7+AMSCUkO58bXJTewQI6JadczU0JyVVjJVTny3 +ta0x4SyXn8/ibylOalIsmTd/CAXJRfhV0Umb34LwaWrZ2nc+OrJwYLvOp1cG/zYl +GHkFCViRfuwwSkL4iKjVeHx2o0DxJ4bc2Z7k1ig2fTJK3gEbMz3y+YTlVNPo108H +JI77DPbkBUqLPeF7PMaN/zDqmdH0yNCW+WiHZlf6h7kZdVH3feAhTfDZbpSxhpRo +Ja84OAVCNqAuNjnZs8pMIW/iRixwP8p84At7VsS4yQQFTCjN22UhPP0PrqY3ngEj +1lbfhHC1FNZvCMxrkUAUQbeYRqLrIwB4KdDMkRJixv5Vr89NO08QtnLwQduusVkc +4Zg9HXtJTKjgQTHxHtn+OrTbpx0ogaUuYpVcQOsBT3b0EyV2z6pZiH6HK1r5Xwaq +0+nvFwpCHe58PlaI3Geihxejkv+85ZgDqXSGt7ECAwEAATANBgkqhkiG9w0BAQUF +AAOCAgEAQgIicN/uWtaYYBVEVeMGMdxzpp2pv3AaCfQMoVGaQu9VLydK/GBlYOqj +AGPjdmQ7p4ISlduXqslu646+RxZ+H6TSSj0NTF4FyR8LPckRPiePNlsGp3u6ffix +PX0554Ks+JYyFJ7qyMhsilqCYtw8prX9lj8fjzbWWXlgJFH/SRZw4xdcJ1yYA9sQ +fBHxveCWFS1ibX5+QGy/+7jPb99MP38HEIt9vTMW5aiwXeIbipXohWqcJhxL9GXz +KPsrt9a++rLjqsquhZL4uCksGmI4Gv0FQQswgSyHSSQzagee5VRB68WYSAyYdvzi +YCfkNcbQtOOQWGx4rsEdENViPs1GEZkWJJ1h9pmWzZl0U9c3cnABffK7o9v6ap2F +NrnU5H/7jLuBiUJFzqwkgAjANLRZ6hLj6h/grcnIIThJwg6KaXvpEh4UkHuqHYBF +Fq1BWZIWU25ASggEVIsCPXC2+I1oGhxK1DN/J+wIht9MBWWlQWVMZAQsBkszNZrh +nzdfMoQZTG5bT4Bf0bI5LmPaY0xBxXA1f4TLuqrEAziOjRX3vIQV4i33nZZJvPcC +mCoyhAUpTJm+OI90ePll+vBO1ENAx7EMHqNe6eCChZ/9DUsVxxtaorVq1l0xWons +ynOCgx46hGE12/oiRIKq/wGMpv6ClfJhW1N5nJahDqoIMEvnNaQ= +-----END CERTIFICATE----- diff --git a/tests/client_certs/client.key b/tests/client_certs/client.key new file mode 100644 index 0000000000..e80562b2c3 --- /dev/null +++ b/tests/client_certs/client.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/tests/client_certs/client.pem b/tests/client_certs/client.pem new file mode 100644 index 0000000000..923bf16795 --- /dev/null +++ b/tests/client_certs/client.pem @@ -0,0 +1,87 @@ +Bag Attributes + localKeyID: 93 0C 3E A7 82 62 36 37 5E 73 9B 05 C4 98 DF DC 04 5C B4 C9 +subject=/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd +issuer=/C=US/ST=CA/L=SF/O=HTTPie/CN=HTTPie +-----BEGIN CERTIFICATE----- +MIIFAjCCAuoCAQEwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCVVMxCzAJBgNV +BAgTAkNBMQswCQYDVQQHEwJTRjEPMA0GA1UEChMGSFRUUGllMQ8wDQYDVQQDEwZI +VFRQaWUwHhcNMTUwMTIzMjIyNTM2WhcNMTYwMTIzMjIyNTM2WjBFMQswCQYDVQQG +EwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lk +Z2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAu6aP +iR3TpPESWKTS969fxNRoSxl8P4osjhIaUuwblFNZc8/Rn5mCMKmD506JrFV8fktQ +M6JRL7QuDC9vCw0ycr2HCV1sYX/ICgPCXYgmyigH535lb9V9hHjAgy60QgJBgSE7 +lmMYaPpX6OKbT7UlzSwYtfHomXEBFA18Rlc9GwMXH8Et0RQiWIi7S6vpDRpZFxRi +gtXMceK1X8kut2ODv9B5ZwiuXh7+AMSCUkO58bXJTewQI6JadczU0JyVVjJVTny3 +ta0x4SyXn8/ibylOalIsmTd/CAXJRfhV0Umb34LwaWrZ2nc+OrJwYLvOp1cG/zYl +GHkFCViRfuwwSkL4iKjVeHx2o0DxJ4bc2Z7k1ig2fTJK3gEbMz3y+YTlVNPo108H +JI77DPbkBUqLPeF7PMaN/zDqmdH0yNCW+WiHZlf6h7kZdVH3feAhTfDZbpSxhpRo +Ja84OAVCNqAuNjnZs8pMIW/iRixwP8p84At7VsS4yQQFTCjN22UhPP0PrqY3ngEj +1lbfhHC1FNZvCMxrkUAUQbeYRqLrIwB4KdDMkRJixv5Vr89NO08QtnLwQduusVkc +4Zg9HXtJTKjgQTHxHtn+OrTbpx0ogaUuYpVcQOsBT3b0EyV2z6pZiH6HK1r5Xwaq +0+nvFwpCHe58PlaI3Geihxejkv+85ZgDqXSGt7ECAwEAATANBgkqhkiG9w0BAQUF +AAOCAgEAQgIicN/uWtaYYBVEVeMGMdxzpp2pv3AaCfQMoVGaQu9VLydK/GBlYOqj +AGPjdmQ7p4ISlduXqslu646+RxZ+H6TSSj0NTF4FyR8LPckRPiePNlsGp3u6ffix +PX0554Ks+JYyFJ7qyMhsilqCYtw8prX9lj8fjzbWWXlgJFH/SRZw4xdcJ1yYA9sQ +fBHxveCWFS1ibX5+QGy/+7jPb99MP38HEIt9vTMW5aiwXeIbipXohWqcJhxL9GXz +KPsrt9a++rLjqsquhZL4uCksGmI4Gv0FQQswgSyHSSQzagee5VRB68WYSAyYdvzi +YCfkNcbQtOOQWGx4rsEdENViPs1GEZkWJJ1h9pmWzZl0U9c3cnABffK7o9v6ap2F +NrnU5H/7jLuBiUJFzqwkgAjANLRZ6hLj6h/grcnIIThJwg6KaXvpEh4UkHuqHYBF +Fq1BWZIWU25ASggEVIsCPXC2+I1oGhxK1DN/J+wIht9MBWWlQWVMZAQsBkszNZrh +nzdfMoQZTG5bT4Bf0bI5LmPaY0xBxXA1f4TLuqrEAziOjRX3vIQV4i33nZZJvPcC +mCoyhAUpTJm+OI90ePll+vBO1ENAx7EMHqNe6eCChZ/9DUsVxxtaorVq1l0xWons +ynOCgx46hGE12/oiRIKq/wGMpv6ClfJhW1N5nJahDqoIMEvnNaQ= +-----END CERTIFICATE----- +Bag Attributes + localKeyID: 93 0C 3E A7 82 62 36 37 5E 73 9B 05 C4 98 DF DC 04 5C B4 C9 +Key Attributes: +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- From 59b6020105568fbc797e4fa698926791c862a72c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 24 Jan 2015 00:22:31 +0100 Subject: [PATCH 0031/1182] Extended SSL documentation. --- README.rst | 60 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index a15c3a8afd..dea495b064 100644 --- a/README.rst +++ b/README.rst @@ -633,17 +633,59 @@ In your ``~/.bash_profile``: HTTPS ===== -To skip the host's SSL certificate verification, you can pass ``--verify=no`` -(default is ``yes``). You can also use ``--verify`` to set a custom CA bundle -path. The path can also be configured via the environment variable -``REQUESTS_CA_BUNDLE``. +----------------------------------- +Server SSL certificate verification +----------------------------------- -To use a client side certificate for the SSL communication, you can pass the -path of the cert file with ``--cert``. If the private key is not contained -in the cert file you may pass the path of the key file with ``--cert-key``. +To skip the **host's SSL certificate verification,** you can pass +``--verify=no`` (default is ``yes``): -If you use Python 2.x and need to talk to servers that use **SNI (Server Name -Indication)** you need to install some additional dependencies: +.. code-block:: bash + + $ http --verify=no https://example.org + + +You can also use ``--verify=`` to set a custom CA bundle path: + +.. code-block:: bash + + $ http --verify=/ssl/custom_ca_bundle https://example.org + + +The path can also be configured via the environment variable +``REQUESTS_CA_BUNDLE`` (picked up by the underlying python-requests library): + +.. code-block:: bash + + $ REQUESTS_CA_BUNDLE=/ssl/custom_ca_bundle http https://example.org + + +--------------------------- +Client side SSL certificate +--------------------------- +To use a **client side certificate** for the SSL communication, you can pass +the path of the cert file with ``--cert``: + +.. code-block:: bash + + $ http --cert=client.pem https://example.org + + +If the private key is not contained in the cert file you may pass the +path of the key file with ``--cert-key``: + +.. code-block:: bash + + $ http --cert=client.crt --cert-key=client.key https://example.org + + +---------------------------- +SNI (Server Name Indication) +---------------------------- + +If you use HTTPie with Python < 2.7.9 and need to talk to servers that use +**SNI (Server Name Indication)** you need to install some additional +dependencies: .. code-block:: bash From ed6485498bdea89d27b1985e130f8b4ee0d70d62 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 24 Jan 2015 00:41:22 +0100 Subject: [PATCH 0032/1182] README --- README.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index dea495b064..4c910b1120 100644 --- a/README.rst +++ b/README.rst @@ -645,7 +645,8 @@ To skip the **host's SSL certificate verification,** you can pass $ http --verify=no https://example.org -You can also use ``--verify=`` to set a custom CA bundle path: +You can also use ``--verify=`` to set a **custom CA bundle** +path: .. code-block:: bash @@ -671,7 +672,7 @@ the path of the cert file with ``--cert``: $ http --cert=client.pem https://example.org -If the private key is not contained in the cert file you may pass the +If the **private key** is not contained in the cert file you may pass the path of the key file with ``--cert-key``: .. code-block:: bash @@ -683,8 +684,9 @@ path of the key file with ``--cert-key``: SNI (Server Name Indication) ---------------------------- -If you use HTTPie with Python < 2.7.9 and need to talk to servers that use -**SNI (Server Name Indication)** you need to install some additional +If you use HTTPie with Python < 2.7.9 +(can be verified with ``python --version``) and need to talk to servers that +use **SNI (Server Name Indication)** you need to install some additional dependencies: .. code-block:: bash From 6c66d91f5940ed6b1ee077f742272b6a153ce6dc Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Jan 2015 13:21:45 +0100 Subject: [PATCH 0033/1182] v0.0.9 --- README.rst | 15 +++++++++------ requirements-dev.txt | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 4c910b1120..9135270f4b 100644 --- a/README.rst +++ b/README.rst @@ -1312,21 +1312,23 @@ Changelog *You can click a version name to see a diff with the previous one.* -* `0.9.0-dev`_ + +* `0.9.0`_ (2015-01-31) * Added ``--cert`` and ``--cert-key`` parameters to specify a client side certificate and private key for SSL - * Fixed ``User-Agent`` overwriting when used within a session. - * Fixed handling of empty passwords in URL credentials. - * Fixed multiple file uploads with the same form field name. - * Fixed ``--output=/dev/null`` on Linux. * Improved unicode support. * Improved terminal color depth detection via ``curses``. * To make it easier to deal with Windows paths in request items, ``\`` now only escapes special characters (the ones that are used as key-value separators by HTTPie). * Switched from ``unittest`` to ``pytest``. + * Added Python `wheel` suppor. * Various test suite improvements. * Added `CONTRIBUTING`_. + * Fixed ``User-Agent`` overwriting when used within a session. + * Fixed handling of empty passwords in URL credentials. + * Fixed multiple file uploads with the same form field name. + * Fixed ``--output=/dev/null`` on Linux. * Miscellaneous bugfixes. * `0.8.0`_ (2014-01-25) * Added ``field=@file.txt`` and ``field:=@file.json`` for embedding @@ -1454,7 +1456,8 @@ Changelog .. _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-dev: https://github.com/jakubroztocil/httpie/compare/0.8.0...master +.. _0.9.0: https://github.com/jakubroztocil/httpie/compare/0.9.0...master +.. _1.0.0-dev: https://github.com/jakubroztocil/httpie/compare/0.9.0...master .. _LICENSE: https://github.com/jakubroztocil/httpie/blob/master/LICENSE .. _Tox: http://tox.testrun.org .. _CONTRIBUTING: https://github.com/jakubroztocil/httpie/blob/master/CONTRIBUTING.rst diff --git a/requirements-dev.txt b/requirements-dev.txt index 7b50ea8b81..16fcc9cb45 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,3 +3,4 @@ pytest pytest-cov pytest-httpbin docutils +wheel From 530d6c5e277ad45eed0beeabc65115df859b8114 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Jan 2015 13:22:17 +0100 Subject: [PATCH 0034/1182] 1.0.0-dev --- README.rst | 2 +- httpie/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 9135270f4b..afa5b0c176 100644 --- a/README.rst +++ b/README.rst @@ -1312,7 +1312,7 @@ Changelog *You can click a version name to see a diff with the previous one.* - +* `1.0.0-dev`_ * `0.9.0`_ (2015-01-31) * Added ``--cert`` and ``--cert-key`` parameters to specify a client side certificate and private key for SSL diff --git a/httpie/__init__.py b/httpie/__init__.py index 6927924dd3..7ae07c9ee2 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '0.9.0' +__version__ = '1.0.0-dev' __licence__ = 'BSD' From 338d39c841b2984c16ec187e1b9b2e55b09f1927 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Jan 2015 13:23:52 +0100 Subject: [PATCH 0035/1182] Fixed version link --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index afa5b0c176..f516d400d6 100644 --- a/README.rst +++ b/README.rst @@ -1456,7 +1456,7 @@ Changelog .. _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.9.0...master +.. _0.9.0: https://github.com/jakubroztocil/httpie/compare/0.8.0...0.9.0 .. _1.0.0-dev: https://github.com/jakubroztocil/httpie/compare/0.9.0...master .. _LICENSE: https://github.com/jakubroztocil/httpie/blob/master/LICENSE .. _Tox: http://tox.testrun.org From 17358be1ae1fb5d23b4a13849be2dde094ea8fd4 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Sat, 31 Jan 2015 07:01:54 -0800 Subject: [PATCH 0036/1182] README.rst: suppor => support --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f516d400d6..1d656b3652 100644 --- a/README.rst +++ b/README.rst @@ -1322,7 +1322,7 @@ Changelog now only escapes special characters (the ones that are used as key-value separators by HTTPie). * Switched from ``unittest`` to ``pytest``. - * Added Python `wheel` suppor. + * Added Python `wheel` support. * Various test suite improvements. * Added `CONTRIBUTING`_. * Fixed ``User-Agent`` overwriting when used within a session. From 92a4352f10685c308e04edc88ee3c02aee20ac5d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Jan 2015 17:49:23 +0100 Subject: [PATCH 0037/1182] Added a coveralls badge. --- README.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 1d656b3652..34707c2371 100644 --- a/README.rst +++ b/README.rst @@ -98,10 +98,10 @@ If the above fails, please use ``easy_install`` instead (``$ easy_install httpie Development version ------------------- -============= ============= -Mac/Linux Windows -|unix| |windows| -============= ============= +=========== ============= ============= +Tests Mac/Linux Windows +|coverage| |unix| |windows| +=========== ============= ============= The **latest development version** can be installed directly from GitHub: @@ -1466,6 +1466,9 @@ Changelog .. |version| image:: https://badge.fury.io/py/httpie.svg :target: http://badge.fury.io/py/httpie +.. |coverage| image:: https://coveralls.io/repos/jakubroztocil/httpie/badge.svg?branch=master + :target: https://coveralls.io/r/jakubroztocil/httpie?branch=master + .. |unix| image:: https://api.travis-ci.org/jakubroztocil/httpie.svg :target: http://travis-ci.org/jakubroztocil/httpie :alt: Build Status of the master branch on Mac/Linux From b125ce5eae60c681f9f5944537b66ea7ca14d651 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 5 Feb 2015 14:35:05 +0100 Subject: [PATCH 0038/1182] Allow custom URL schemes Closes #299 See also #276 --- httpie/input.py | 6 +++++- tests/test_cli.py | 11 ++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/httpie/input.py b/httpie/input.py index ff0bf03407..88bc3c87e6 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -21,6 +21,10 @@ from httpie.utils import load_json_preserve_order +# ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) +# +URL_SCHEME_RE = re.compile(r'^[a-z][a-z0-9.+-]*://', re.IGNORECASE) + HTTP_POST = 'POST' HTTP_GET = 'GET' HTTP = 'http://' @@ -132,7 +136,7 @@ def parse_args(self, env, args=None, namespace=None): self._parse_items() if not self.args.ignore_stdin and not env.stdin_isatty: self._body_from_file(self.env.stdin) - if not (self.args.url.startswith((HTTP, HTTPS))): + if not URL_SCHEME_RE.match(self.args.url): scheme = HTTP # See if we're using curl style shorthand for localhost (:3000/foo) diff --git a/tests/test_cli.py b/tests/test_cli.py index f5754edc77..73f68f7138 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,9 +2,9 @@ import json # noinspection PyCompatibility import argparse -import os import pytest +from requests.exceptions import InvalidSchema from httpie import input from httpie.input import KeyValue, KeyValueArgType, DataDict @@ -321,3 +321,12 @@ def test_ignore_stdin_cannot_prompt_password(self, httpbin): error_exit_ok=True) assert r.exit_status == ExitStatus.ERROR assert 'because --ignore-stdin' in r.stderr + + +class TestSchemes: + + def test_custom_scheme(self): + # InvalidSchema is expected because HTTPie + # shouldn't touch a formally valid scheme. + with pytest.raises(InvalidSchema): + http('foo+bar-BAZ.123://bah') From 687a6a734de9a27f04563feb11aa1112eb8a21d8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 5 Feb 2015 15:25:00 +0100 Subject: [PATCH 0039/1182] Added support for transport adapter plugins #276, #298 --- httpie/client.py | 19 ++++++++++++++++--- httpie/plugins/__init__.py | 10 +++++++++- httpie/plugins/base.py | 21 ++++++++++++++++++++- httpie/plugins/manager.py | 7 +++++++ httpie/sessions.py | 19 ++++++++++--------- 5 files changed, 62 insertions(+), 14 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 1073c63ce2..79e01ba670 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -15,16 +15,29 @@ DEFAULT_UA = 'HTTPie/%s' % __version__ +def get_requests_session(): + + requests_session = requests.Session() + for adapter_plugin_cls in plugin_manager.get_adapter_plugins(): + adapter_plugin = adapter_plugin_cls() + requests_session.mount(prefix=adapter_plugin.prefix, + adapter=adapter_plugin.get_adapter()) + return requests_session + + def get_response(args, config_dir): """Send the request and return a `request.Response`.""" + requests_session = get_requests_session() + if not args.session and not args.session_read_only: - requests_kwargs = get_requests_kwargs(args) + kwargs = get_requests_kwargs(args) if args.debug: - dump_request(requests_kwargs) - response = requests.request(**requests_kwargs) + dump_request(kwargs) + response = requests_session.request(**kwargs) else: response = sessions.get_response( + requests_session=requests_session, args=args, config_dir=config_dir, session_name=args.session or args.session_read_only, diff --git a/httpie/plugins/__init__.py b/httpie/plugins/__init__.py index d822de183d..4be81e7a30 100644 --- a/httpie/plugins/__init__.py +++ b/httpie/plugins/__init__.py @@ -1,4 +1,12 @@ -from httpie.plugins.base import AuthPlugin, FormatterPlugin, ConverterPlugin +""" +WARNING: The plugin API is still work in progress and will + probably be completely reworked by v1.0.0. + +""" +from httpie.plugins.base import ( + AuthPlugin, FormatterPlugin, + ConverterPlugin, TransportPlugin +) from httpie.plugins.manager import PluginManager from httpie.plugins.builtin import BasicAuthPlugin, DigestAuthPlugin from httpie.output.formatters.headers import HeadersFormatter diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index 187c874b98..d1211540db 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -15,7 +15,7 @@ class AuthPlugin(BasePlugin): """ Base auth plugin class. - See for an example auth plugin. + See for an example auth plugin. """ # The value that should be passed to --auth-type @@ -30,6 +30,25 @@ def get_auth(self, username, password): raise NotImplementedError() +class TransportPlugin(BasePlugin): + """ + + http://docs.python-requests.org/en/latest/user/advanced/#transport-adapters + + """ + + # The URL prefix the adapter should be mount to. + prefix = None + + def get_adapter(self): + """ + Return a ``requests.adapters.BaseAdapter`` subclass instance to be + mounted to ``self.prefix``. + + """ + raise NotImplementedError() + + class ConverterPlugin(object): def __init__(self, mime): diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index 82bfcb8193..957b8a6c49 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -1,12 +1,14 @@ from itertools import groupby from pkg_resources import iter_entry_points from httpie.plugins import AuthPlugin, FormatterPlugin, ConverterPlugin +from httpie.plugins.base import TransportPlugin ENTRY_POINT_NAMES = [ 'httpie.plugins.auth.v1', 'httpie.plugins.formatter.v1', 'httpie.plugins.converter.v1', + 'httpie.plugins.transport.v1', ] @@ -56,3 +58,8 @@ def get_formatters_grouped(self): def get_converters(self): return [plugin for plugin in self if issubclass(plugin, ConverterPlugin)] + + # Adapters + def get_adapter_plugins(self): + return [plugin for plugin in self + if issubclass(plugin, TransportPlugin)] diff --git a/httpie/sessions.py b/httpie/sessions.py index 4c42a0855d..5280146cf6 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -4,7 +4,6 @@ import re import os -import requests from requests.cookies import RequestsCookieJar, create_cookie from httpie.compat import urlsplit @@ -21,7 +20,8 @@ SESSION_IGNORED_HEADER_PREFIXES = ['Content-', 'If-'] -def get_response(session_name, config_dir, args, read_only=False): +def get_response(requests_session, session_name, + config_dir, args, read_only=False): """Like `client.get_response`, but applies permanent aspects of the session to the request. @@ -32,7 +32,9 @@ def get_response(session_name, config_dir, args, read_only=False): else: hostname = (args.headers.get('Host', None) or urlsplit(args.url).netloc.split('@')[-1]) - assert re.match('^[a-zA-Z0-9_.:-]+$', hostname) + if not hostname: + # HACK/FIXME: httpie-unixsocket's URLs have no hostname. + hostname = 'localhost' # host:port => host_port hostname = hostname.replace(':', '_') @@ -44,10 +46,10 @@ def get_response(session_name, config_dir, args, read_only=False): session = Session(path) session.load() - requests_kwargs = get_requests_kwargs(args, base_headers=session.headers) + kwargs = get_requests_kwargs(args, base_headers=session.headers) if args.debug: - dump_request(requests_kwargs) - session.update_headers(requests_kwargs['headers']) + dump_request(kwargs) + session.update_headers(kwargs['headers']) if args.auth: session.auth = { @@ -56,13 +58,12 @@ def get_response(session_name, config_dir, args, read_only=False): 'password': args.auth.value, } elif session.auth: - requests_kwargs['auth'] = session.auth + kwargs['auth'] = session.auth - requests_session = requests.Session() requests_session.cookies = session.cookies try: - response = requests_session.request(**requests_kwargs) + response = requests_session.request(**kwargs) except Exception: raise else: From 996e31448209b6a77eac89f6793200def52a730c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 5 Feb 2015 15:55:20 +0100 Subject: [PATCH 0040/1182] Cleanup --- httpie/client.py | 9 ++++----- httpie/plugins/manager.py | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 79e01ba670..0aa2666d8c 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -16,12 +16,11 @@ def get_requests_session(): - requests_session = requests.Session() - for adapter_plugin_cls in plugin_manager.get_adapter_plugins(): - adapter_plugin = adapter_plugin_cls() - requests_session.mount(prefix=adapter_plugin.prefix, - adapter=adapter_plugin.get_adapter()) + for cls in plugin_manager.get_trasnsport_plugins(): + transport_plugin = cls() + requests_session.mount(prefix=transport_plugin.prefix, + adapter=transport_plugin.get_adapter()) return requests_session diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index 957b8a6c49..2c4092d5c7 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -60,6 +60,6 @@ def get_converters(self): if issubclass(plugin, ConverterPlugin)] # Adapters - def get_adapter_plugins(self): + def get_trasnsport_plugins(self): return [plugin for plugin in self if issubclass(plugin, TransportPlugin)] From 0d21ff022e7ed65259ef743f14d705baabf621ff Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 6 Feb 2015 20:06:50 +0100 Subject: [PATCH 0041/1182] Added a link to @pd's httpie-api-auth plugin --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 34707c2371..0fa40b39f2 100644 --- a/README.rst +++ b/README.rst @@ -595,6 +595,7 @@ Auth Plugins * `httpie-ntlm `_: NTLM (NT LAN Manager) * `httpie-negotiate `_: SPNEGO (GSS Negotiate) * `requests-hawk `_: Hawk +* `httpie-api-auth `_: ApiAuth ======= From 9682f955b5808585429e5cf64a6096ceac445999 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 6 Feb 2015 21:13:57 +0100 Subject: [PATCH 0042/1182] Handle HTTP/2 responses https://github.com/jakubroztocil/httpie-http2/issues/1#issuecomment-73301801 --- httpie/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/models.py b/httpie/models.py index d7c5414f8e..20619a7b57 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -52,7 +52,7 @@ def iter_lines(self, chunk_size): @property def headers(self): original = self._orig.raw._original_response - version = {9: '0.9', 10: '1.0', 11: '1.1'}[original.version] + version = {9: '0.9', 10: '1.0', 11: '1.1', 20: '2.0'}[original.version] status_line = 'HTTP/{version} {status} {reason}'.format( version=version, status=original.status, From a5a83c5b777db9b0bdf0a904087df9607ce7bb4f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 7 Feb 2015 16:29:17 +0100 Subject: [PATCH 0043/1182] Prevent a circular import issue. --- tests/test_output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_output.py b/tests/test_output.py index b4e2db3d2c..ef97886794 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -1,8 +1,8 @@ import pytest +from utils import TestEnvironment, http, HTTP_OK, COLOR, CRLF from httpie import ExitStatus from httpie.output.formatters.colors import get_lexer -from utils import TestEnvironment, http, HTTP_OK, COLOR, CRLF class TestVerboseFlag: From 3ff03524ff0f906e53fe680bb2dc8bb87b974e4f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 7 Feb 2015 16:29:27 +0100 Subject: [PATCH 0044/1182] HTTP/2 has no minor versions. https://github.com/jakubroztocil/httpie-http2/issues/1 --- httpie/models.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/httpie/models.py b/httpie/models.py index 20619a7b57..3f273b4eab 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -52,7 +52,14 @@ def iter_lines(self, chunk_size): @property def headers(self): original = self._orig.raw._original_response - version = {9: '0.9', 10: '1.0', 11: '1.1', 20: '2.0'}[original.version] + + version = { + 9: '0.9', + 10: '1.0', + 11: '1.1', + 20: '2', + }[original.version] + status_line = 'HTTP/{version} {status} {reason}'.format( version=version, status=original.status, From 753a8d04e4499505140a67442ae3e21f608b377f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 7 Feb 2015 17:04:13 +0100 Subject: [PATCH 0045/1182] v0.9.1 --- README.rst | 7 +++++++ httpie/__init__.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 0fa40b39f2..c9db11492d 100644 --- a/README.rst +++ b/README.rst @@ -1314,6 +1314,12 @@ Changelog *You can click a version name to see a diff with the previous one.* * `1.0.0-dev`_ +* `0.9.1`_ (2015-02-07) + * Added support for Requests transport adapter plugins + to enable plugin-provided features such as + `unix socket `_ + communication and + `HTTP/2 `_. * `0.9.0`_ (2015-01-31) * Added ``--cert`` and ``--cert-key`` parameters to specify a client side certificate and private key for SSL @@ -1458,6 +1464,7 @@ Changelog .. _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 .. _1.0.0-dev: https://github.com/jakubroztocil/httpie/compare/0.9.0...master .. _LICENSE: https://github.com/jakubroztocil/httpie/blob/master/LICENSE .. _Tox: http://tox.testrun.org diff --git a/httpie/__init__.py b/httpie/__init__.py index 7ae07c9ee2..ace69851be 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '1.0.0-dev' +__version__ = '0.9.1' __licence__ = 'BSD' From a786f17997751c16805a31944ea4a31185d1d9ef Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 7 Feb 2015 17:04:33 +0100 Subject: [PATCH 0046/1182] 1.0.0-dev --- httpie/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/__init__.py b/httpie/__init__.py index ace69851be..7ae07c9ee2 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '0.9.1' +__version__ = '1.0.0-dev' __licence__ = 'BSD' From 337c05f95cc3b5435f9a7718bbd62debbf282d31 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 7 Feb 2015 18:06:49 +0100 Subject: [PATCH 0047/1182] README --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index c9db11492d..0fd828d066 100644 --- a/README.rst +++ b/README.rst @@ -11,7 +11,7 @@ colorized responses. HTTPie can be used for **testing, debugging**, and generally **interacting** with HTTP servers. -.. image:: https://github.com/jakubroztocil/httpie/raw/master/httpie.png +.. image:: httpie.png :alt: HTTPie compared to cURL :width: 835 :height: 835 @@ -1465,7 +1465,7 @@ Changelog .. _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 -.. _1.0.0-dev: https://github.com/jakubroztocil/httpie/compare/0.9.0...master +.. _1.0.0-dev: https://github.com/jakubroztocil/httpie/compare/0.9.1...master .. _LICENSE: https://github.com/jakubroztocil/httpie/blob/master/LICENSE .. _Tox: http://tox.testrun.org .. _CONTRIBUTING: https://github.com/jakubroztocil/httpie/blob/master/CONTRIBUTING.rst From 873102d5ebd98d811c5f1247ef267e554e4da7b8 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 9 Feb 2015 18:15:22 -0800 Subject: [PATCH 0048/1182] Mark test_session_unicode as xfail There are known problems with unicode in headers. See https://github.com/jakubroztocil/httpie/issues/282 --- tests/test_sessions.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 6d5985843f..210f9d954c 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -1,6 +1,9 @@ # coding=utf-8 import os import shutil +import sys + +import pytest from httpie.plugins.builtin import HTTPBasicAuth from utils import TestEnvironment, mk_config_dir, http, HTTP_OK, \ @@ -132,6 +135,10 @@ def test_session_by_path(self, httpbin): assert HTTP_OK in r2 assert r2.json['headers']['Foo'] == 'Bar' + @pytest.mark.skipif( + sys.version_info >= (3,), + reason="This test fails intermittently on Python 3 - " + "see https://github.com/jakubroztocil/httpie/issues/282") def test_session_unicode(self, httpbin): self.start_session(httpbin) From 86ebb9b741b9e22547570840f4027f317c1ef3c5 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 9 Feb 2015 17:05:05 -0800 Subject: [PATCH 0049/1182] compat.py: Add pragma no covers Cuz this is a lot of version-specific stuff and it can be confusing to have different coverage per version, especially with coveralls. --- httpie/compat.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/httpie/compat.py b/httpie/compat.py index 45ccfe7a11..518ad17f2d 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -6,23 +6,23 @@ # noinspection PyUnresolvedReferences from requests.compat import is_windows, bytes, str, is_py3, is_py26 -try: +try: # pragma: no cover # noinspection PyUnresolvedReferences,PyCompatibility from urllib.parse import urlsplit -except ImportError: +except ImportError: # pragma: no cover # noinspection PyUnresolvedReferences,PyCompatibility from urlparse import urlsplit -try: +try: # pragma: no cover # noinspection PyCompatibility from urllib.request import urlopen -except ImportError: +except ImportError: # pragma: no cover # noinspection PyCompatibility from urllib2 import urlopen -try: +try: # pragma: no cover from collections import OrderedDict -except ImportError: +except ImportError: # pragma: no cover # Python 2.6 OrderedDict class, needed for headers, parameters, etc .### # # noinspection PyCompatibility From fbd44640e6a44df0b6705e78b642eb0aa511584f Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 9 Feb 2015 16:29:46 -0800 Subject: [PATCH 0050/1182] .travis.yml: Only do coveralls on newest python Testing theory that it has to do with different python version subjobs completing in different orders and the last one wins. --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 39804b6381..8516305646 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,9 @@ os: - linux - osx +env: + global: + - NEWEST_PYTHON=3.4 language: python python: - 2.6 @@ -13,5 +16,4 @@ python: script: - make after_success: - - pip install python-coveralls - - coveralls + - if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON ]]; then pip install python-coveralls && coveralls; fi From 55fa975ae5e84083a7fccc4c4d5ecc45a04f37b4 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Mon, 9 Feb 2015 20:20:50 -0800 Subject: [PATCH 0051/1182] .travis.yml: sudo false for Docker containers Enables new Docker container infrastructure. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 8516305646..e2b6f1683d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ # https://travis-ci.org/jakubroztocil/httpie +sudo: false os: - linux - osx From 6e7e2f2eeaf5d07060303735d8f183e526447f25 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 14 Feb 2015 17:44:47 +0100 Subject: [PATCH 0052/1182] Changed the default JSON `Content-Type` to `application/json`. --- README.rst | 11 +++++++---- httpie/client.py | 2 +- tests/test_defaults.py | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 0fd828d066..4860470a95 100644 --- a/README.rst +++ b/README.rst @@ -362,7 +362,7 @@ object by default. HTTPie also automatically sets the following headers, both of which can be overwritten: ================ ======================================= -``Content-Type`` ``application/json; charset=utf-8`` +``Content-Type`` ``application/json`` ``Accept`` ``application/json`` ================ ======================================= @@ -382,7 +382,7 @@ Simple example: PUT / HTTP/1.1 Accept: application/json Accept-Encoding: identity, deflate, compress, gzip - Content-Type: application/json; charset=utf-8 + Content-Type: application/json Host: example.org { @@ -408,7 +408,7 @@ fields using ``=@`` and ``:=@``: PUT /person/1 HTTP/1.1 Accept: application/json - Content-Type: application/json; charset=utf-8 + Content-Type: application/json Host: api.example.com { @@ -727,7 +727,7 @@ documentation examples: PUT /put HTTP/1.1 Accept: application/json Accept-Encoding: identity, deflate, compress, gzip - Content-Type: application/json; charset=utf-8 + Content-Type: application/json Host: httpbin.org User-Agent: HTTPie/0.2.7dev @@ -1314,6 +1314,9 @@ Changelog *You can click a version name to see a diff with the previous one.* * `1.0.0-dev`_ + * Changed the default JSON ``Content-Type`` + from ``application/json; charset=utf-8`` to ``application/json`` + as UTF-8 is the default encoding for JSON. * `0.9.1`_ (2015-02-07) * Added support for Requests transport adapter plugins to enable plugin-provided features such as diff --git a/httpie/client.py b/httpie/client.py index 0aa2666d8c..83b22f90b4 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -11,7 +11,7 @@ FORM = 'application/x-www-form-urlencoded; charset=utf-8' -JSON = 'application/json; charset=utf-8' +JSON = 'application/json' DEFAULT_UA = 'HTTPie/%s' % __version__ diff --git a/tests/test_defaults.py b/tests/test_defaults.py index 652a272b9f..ce3e1d26f4 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -59,14 +59,14 @@ def test_POST_with_data_auto_JSON_headers(self, httpbin): r = http('POST', httpbin.url + '/post', 'a=b') assert HTTP_OK in r assert '"Accept": "application/json"' in r - assert '"Content-Type": "application/json; charset=utf-8' in r + assert '"Content-Type": "application/json' in r def test_GET_with_data_auto_JSON_headers(self, httpbin): # JSON headers should automatically be set also for GET with data. r = http('POST', httpbin.url + '/post', 'a=b') assert HTTP_OK in r assert '"Accept": "application/json"' in r, r - assert '"Content-Type": "application/json; charset=utf-8' in r + assert '"Content-Type": "application/json' in r def test_POST_explicit_JSON_auto_JSON_accept(self, httpbin): r = http('--json', 'POST', httpbin.url + '/post') From 596fdc8c7e76f01197a128649dbb91bbca46f7b1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 14 Feb 2015 17:55:34 +0100 Subject: [PATCH 0053/1182] Update README examples with the new default `Accept-Encoding` value used by Requests. --- README.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 4860470a95..b72a842719 100644 --- a/README.rst +++ b/README.rst @@ -381,7 +381,7 @@ Simple example: PUT / HTTP/1.1 Accept: application/json - Accept-Encoding: identity, deflate, compress, gzip + Accept-Encoding: gzip, deflate Content-Type: application/json Host: example.org @@ -504,7 +504,7 @@ To set custom headers you can use the ``Header:Value`` notation: GET / HTTP/1.1 Accept: */* - Accept-Encoding: identity, deflate, compress, gzip + Accept-Encoding: gzip, deflate Cookie: valued-visitor=yes;foo=bar Host: example.org Referer: http://httpie.org/ @@ -518,7 +518,7 @@ There are a couple of default headers that HTTPie sets: GET / HTTP/1.1 Accept: */* - Accept-Encoding: identity, deflate, compress, gzip + Accept-Encoding: gzip, deflate User-Agent: HTTPie/ Host: @@ -726,7 +726,7 @@ documentation examples: $ http --verbose PUT httpbin.org/put hello=world PUT /put HTTP/1.1 Accept: application/json - Accept-Encoding: identity, deflate, compress, gzip + Accept-Encoding: gzip, deflate Content-Type: application/json Host: httpbin.org User-Agent: HTTPie/0.2.7dev From 419ca85e625bc13d8934998e3f311d3f05e00ecd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 14 Feb 2015 18:18:04 +0100 Subject: [PATCH 0054/1182] The default color --style is now "fruity" It's experimental - please let me know should you dislike this change. To make Solarized default again, add this to your ~/.config.json: "default_options": [ "--style=solarized" ], --- README.rst | 1 + httpie/output/formatters/colors.py | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index b72a842719..def1158d8d 100644 --- a/README.rst +++ b/README.rst @@ -1314,6 +1314,7 @@ Changelog *You can click a version name to see a diff with the previous one.* * `1.0.0-dev`_ + * The default color ``--style`` is now ``fruity`` (was ``solarized``). * Changed the default JSON ``Content-Type`` from ``application/json; charset=utf-8`` to ``application/json`` as UTF-8 is the default encoding for JSON. diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 667ae91ad9..1fe1c41329 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -7,7 +7,6 @@ from pygments.formatters.terminal256 import Terminal256Formatter from pygments.util import ClassNotFound -from httpie.compat import is_windows from httpie.plugins import FormatterPlugin @@ -15,7 +14,7 @@ # great and fruity seems to give the best result there. AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys()) AVAILABLE_STYLES.add('solarized') -DEFAULT_STYLE = 'solarized' if not is_windows else 'fruity' +DEFAULT_STYLE = 'fruity' class ColorFormatter(FormatterPlugin): @@ -144,6 +143,8 @@ class HTTPLexer(pygments.lexer.RegexLexer): } +# TODO: As Solarized is not the default theme any longer, it should be removed +# or bundled directly with Pygments so that we don't need to support it. class Solarized256Style(pygments.style.Style): """ solarized256 From 07aaefa2328ece4e94d7a900c4ec95653550624b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 14 Feb 2015 18:18:43 +0100 Subject: [PATCH 0055/1182] Updated screenshot --- httpie.png | Bin 457047 -> 187774 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/httpie.png b/httpie.png index 0430ab8016588b627ac5c2a4b9b39289d2f5e350..36dabed947f5e0819f36e14e996f9615e8dd47d6 100644 GIT binary patch literal 187774 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 z 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%0A&4YY!q_&u6IMZlo^*T-n=oa|>C+ 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 JCC^Pi{U7B?Rx|(r literal 457047 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
  • ~yZ>53RsE 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�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%0DW<-2$krJsq1gdZlz@`uzD;qq9o%%>2U9AcxbXk8 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

    @;vYR)98zWr7t}~%T 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 OeDt-Av_5IrMExH)iSz^j From dd0a4ab87a5121da7ed63fa453a7d65a6285b3eb Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 14 Feb 2015 22:51:31 +0100 Subject: [PATCH 0056/1182] Default --style to "monokai" 419ca85 --- README.rst | 2 +- httpie.png | Bin 187774 -> 186489 bytes httpie/output/formatters/colors.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index def1158d8d..746115085d 100644 --- a/README.rst +++ b/README.rst @@ -1314,7 +1314,7 @@ Changelog *You can click a version name to see a diff with the previous one.* * `1.0.0-dev`_ - * The default color ``--style`` is now ``fruity`` (was ``solarized``). + * The default color ``--style`` is now ``monokai`` (was ``solarized``). * Changed the default JSON ``Content-Type`` from ``application/json; charset=utf-8`` to ``application/json`` as UTF-8 is the default encoding for JSON. diff --git a/httpie.png b/httpie.png index 36dabed947f5e0819f36e14e996f9615e8dd47d6..803dc538b2853f7f79537b7b73796478542f5e49 100644 GIT binary patch delta 163585 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∨l$n}0_)`PJ3A)0kHZsyj+A}e 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

      W^@fnh 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 K&Hu;d$^QdYBdBEn delta 164881 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�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�k-10*|8&41r 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 diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 1fe1c41329..65a57d7bc5 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -14,7 +14,7 @@ # great and fruity seems to give the best result there. AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys()) AVAILABLE_STYLES.add('solarized') -DEFAULT_STYLE = 'fruity' +DEFAULT_STYLE = 'monokai' class ColorFormatter(FormatterPlugin): From 985f65ef52991796afeb41be146605d7a1c8ed48 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 14 Feb 2015 23:14:06 +0100 Subject: [PATCH 0057/1182] Temporarily skip SSL tests on PyPy due to #308 --- httpie/compat.py | 2 +- tests/test_ssl.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/httpie/compat.py b/httpie/compat.py index 518ad17f2d..eb26c2be8f 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -4,7 +4,7 @@ """ # Borrow these from requests: # noinspection PyUnresolvedReferences -from requests.compat import is_windows, bytes, str, is_py3, is_py26 +from requests.compat import is_windows, bytes, str, is_py3, is_py26, is_pypy try: # pragma: no cover # noinspection PyUnresolvedReferences,PyCompatibility diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 0fda410635..2e303555cf 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -5,6 +5,7 @@ from requests.exceptions import SSLError from httpie import ExitStatus +from httpie.compat import is_pypy from utils import http, HTTP_OK, TESTS_ROOT @@ -18,6 +19,9 @@ CA_BUNDLE = pytest_httpbin.certs.where() +@pytest.mark.skipif( + is_pypy, + reason='https://github.com/jakubroztocil/httpie/issues/308') class TestClientSSLCertHandling(object): def test_cert_file_not_found(self, httpbin_secure): @@ -54,6 +58,9 @@ def test_cert_pem(self, httpbin_secure): assert HTTP_OK in r +@pytest.mark.skipif( + is_pypy, + reason='https://github.com/jakubroztocil/httpie/issues/308') class TestServerSSLCertHandling(object): def test_self_signed_server_cert_by_default_raises_ssl_error( From bc0d17c04c0624c5223a67b769bd29a78da9a407 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 15 Feb 2015 00:36:55 +0100 Subject: [PATCH 0058/1182] Added a PyPy incompatibility workaround. --- httpie/compat.py | 5 ++++- httpie/input.py | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/httpie/compat.py b/httpie/compat.py index eb26c2be8f..6de0261698 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -4,7 +4,10 @@ """ # Borrow these from requests: # noinspection PyUnresolvedReferences -from requests.compat import is_windows, bytes, str, is_py3, is_py26, is_pypy +from requests.compat import ( + is_windows, bytes, str, + is_py3, is_py26, is_pypy, is_py27 +) try: # pragma: no cover # noinspection PyUnresolvedReferences,PyCompatibility diff --git a/httpie/input.py b/httpie/input.py index 88bc3c87e6..e21d2a4275 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -8,7 +8,7 @@ import mimetypes import getpass from io import BytesIO -from collections import namedtuple +from collections import namedtuple, Iterable # noinspection PyCompatibility from argparse import ArgumentParser, ArgumentTypeError, ArgumentError @@ -16,7 +16,7 @@ # https://github.com/jakubroztocil/httpie/issues/130 from requests.structures import CaseInsensitiveDict -from httpie.compat import OrderedDict, urlsplit, str +from httpie.compat import OrderedDict, urlsplit, str, is_pypy, is_py27 from httpie.sessions import VALID_SESSION_NAME_PATTERN from httpie.utils import load_json_preserve_order @@ -561,6 +561,17 @@ def __call__(self, string): class RequestItemsDict(OrderedDict): """Multi-value dict for URL parameters and form data.""" + if is_pypy and is_py27: + # Manually set keys when initialized with an iterable as PyPy + # doesn't call __setitem__ in such case (pypy3 does). + def __init__(self, *args, **kwargs): + if len(args) == 1 and isinstance(args[0], Iterable): + super(RequestItemsDict, self).__init__(**kwargs) + for k, v in args[0]: + self[k] = v + else: + super(RequestItemsDict, self).__init__(*args, **kwargs) + #noinspection PyMethodOverriding def __setitem__(self, key, value): """ If `key` is assigned more than once, `self[key]` holds a From 40d95b650c0c97b043c6d57844075cce04b7c4ff Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 15 Feb 2015 00:42:41 +0100 Subject: [PATCH 0059/1182] README --- README.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 746115085d..5cf3a42a80 100644 --- a/README.rst +++ b/README.rst @@ -13,17 +13,18 @@ generally **interacting** with HTTP servers. .. image:: httpie.png :alt: HTTPie compared to cURL - :width: 835 - :height: 835 + :width: 679 + :height: 781 :align: center ------- +.. + + .. image:: https://raw.github.com/claudiatd/httpie-artwork/master/images/httpie_logo_simple.png + :alt: HTTPie logo + :align: center -.. image:: https://raw.github.com/claudiatd/httpie-artwork/master/images/httpie_logo_simple.png - :alt: HTTPie logo - :align: center HTTPie is written in Python, and under the hood it uses the excellent `Requests`_ and `Pygments`_ libraries. From 42f454eb6b2072f5f7045b96bab2f51363285542 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 15 Feb 2015 00:43:24 +0100 Subject: [PATCH 0060/1182] README --- README.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/README.rst b/README.rst index 5cf3a42a80..4771b2bdbe 100644 --- a/README.rst +++ b/README.rst @@ -18,14 +18,6 @@ generally **interacting** with HTTP servers. :align: center - -.. - - .. image:: https://raw.github.com/claudiatd/httpie-artwork/master/images/httpie_logo_simple.png - :alt: HTTPie logo - :align: center - - HTTPie is written in Python, and under the hood it uses the excellent `Requests`_ and `Pygments`_ libraries. From 3b3eff01b7abd0c6a86e4fdc6a3ebe618645ff53 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 15 Feb 2015 00:51:58 +0100 Subject: [PATCH 0061/1182] Use shields.io badges --- README.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 4771b2bdbe..424cd1792b 100644 --- a/README.rst +++ b/README.rst @@ -1468,16 +1468,16 @@ Changelog .. _CONTRIBUTING: https://github.com/jakubroztocil/httpie/blob/master/CONTRIBUTING.rst -.. |version| image:: https://badge.fury.io/py/httpie.svg - :target: http://badge.fury.io/py/httpie +.. |version| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat + :target: https://pypi.python.org/pypi/httpie -.. |coverage| image:: https://coveralls.io/repos/jakubroztocil/httpie/badge.svg?branch=master +.. |coverage| image:: https://img.shields.io/coveralls/jakubroztocil/httpie/master.svg?style=flat :target: https://coveralls.io/r/jakubroztocil/httpie?branch=master -.. |unix| image:: https://api.travis-ci.org/jakubroztocil/httpie.svg +.. |unix| image:: https://img.shields.io/travis/jakubroztocil/httpie/master.svg?style=flat :target: http://travis-ci.org/jakubroztocil/httpie :alt: Build Status of the master branch on Mac/Linux -.. |windows| image:: https://ci.appveyor.com/api/projects/status/f7b5dogxuseq8srw +.. |windows| image:: https://img.shields.io/appveyor/ci/jakubroztocil/httpie.svg?style=flat :target: https://ci.appveyor.com/project/jakubroztocil/httpie :alt: Build Status of the master branch on Windows From 2e5d14238f5676f01d3c8db6eef020c39c151074 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 15 Feb 2015 00:54:49 +0100 Subject: [PATCH 0062/1182] Tweak badge style --- README.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 424cd1792b..e2254a56ff 100644 --- a/README.rst +++ b/README.rst @@ -1468,16 +1468,16 @@ Changelog .. _CONTRIBUTING: https://github.com/jakubroztocil/httpie/blob/master/CONTRIBUTING.rst -.. |version| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat +.. |version| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square :target: https://pypi.python.org/pypi/httpie -.. |coverage| image:: https://img.shields.io/coveralls/jakubroztocil/httpie/master.svg?style=flat +.. |coverage| image:: https://img.shields.io/coveralls/jakubroztocil/httpie/master.svg?style=flat-square :target: https://coveralls.io/r/jakubroztocil/httpie?branch=master -.. |unix| image:: https://img.shields.io/travis/jakubroztocil/httpie/master.svg?style=flat +.. |unix| image:: https://img.shields.io/travis/jakubroztocil/httpie/master.svg?style=flat-square :target: http://travis-ci.org/jakubroztocil/httpie :alt: Build Status of the master branch on Mac/Linux -.. |windows| image:: https://img.shields.io/appveyor/ci/jakubroztocil/httpie.svg?style=flat +.. |windows| image:: https://img.shields.io/appveyor/ci/jakubroztocil/httpie.svg?style=flat-square :target: https://ci.appveyor.com/project/jakubroztocil/httpie :alt: Build Status of the master branch on Windows From 5760b780a03c2a2ed501720033c3b6fbc947da36 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 15 Feb 2015 11:28:53 +0100 Subject: [PATCH 0063/1182] README --- README.rst | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/README.rst b/README.rst index e2254a56ff..2504760ebc 100644 --- a/README.rst +++ b/README.rst @@ -3,6 +3,9 @@ HTTPie: a CLI, cURL-like tool for humans **************************************** +|pypi| |unix_build| |windows_build| |coverage| + + HTTPie (pronounced *aych-tee-tee-pie*) is a **command line HTTP client**. Its goal is to make CLI interaction with web services as **human-friendly** as possible. It provides a simple ``http`` command that allows for sending @@ -57,9 +60,9 @@ Installation ------------------------- -Stable version |version| ------------------------- +-------------- +Stable version +-------------- On **Mac OS X**, HTTPie can be installed via `Homebrew `_: @@ -91,12 +94,6 @@ If the above fails, please use ``easy_install`` instead (``$ easy_install httpie Development version ------------------- -=========== ============= ============= -Tests Mac/Linux Windows -|coverage| |unix| |windows| -=========== ============= ============= - - The **latest development version** can be installed directly from GitHub: .. code-block:: bash @@ -1468,16 +1465,18 @@ Changelog .. _CONTRIBUTING: https://github.com/jakubroztocil/httpie/blob/master/CONTRIBUTING.rst -.. |version| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square +.. |pypi| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square&label=latest%20version :target: https://pypi.python.org/pypi/httpie + :alt: Latest version released on PyPi .. |coverage| image:: https://img.shields.io/coveralls/jakubroztocil/httpie/master.svg?style=flat-square :target: https://coveralls.io/r/jakubroztocil/httpie?branch=master + :alt: Test coverage -.. |unix| image:: https://img.shields.io/travis/jakubroztocil/httpie/master.svg?style=flat-square +.. |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 + :alt: Build status of the master branch on Mac/Linux -.. |windows| image:: https://img.shields.io/appveyor/ci/jakubroztocil/httpie.svg?style=flat-square +.. |windows_build| image:: https://img.shields.io/appveyor/ci/jakubroztocil/httpie.svg?style=flat-square&label=windows%20build :target: https://ci.appveyor.com/project/jakubroztocil/httpie - :alt: Build Status of the master branch on Windows + :alt: Build status of the master branch on Windows From 868baaba4ec0818990db05bade3dcb303b7b3c4e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 15 Feb 2015 12:53:57 +0100 Subject: [PATCH 0064/1182] README --- README.rst | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 2504760ebc..76c25895b4 100644 --- a/README.rst +++ b/README.rst @@ -1,16 +1,17 @@ + + **************************************** HTTPie: a CLI, cURL-like tool for humans **************************************** -|pypi| |unix_build| |windows_build| |coverage| HTTPie (pronounced *aych-tee-tee-pie*) is a **command line HTTP client**. Its goal is to make CLI interaction with web services as **human-friendly** as possible. It provides a simple ``http`` command that allows for sending arbitrary HTTP requests using a simple and natural syntax, and displays -colorized responses. HTTPie can be used for **testing, debugging**, and +colorized output. HTTPie can be used for **testing, debugging**, and generally **interacting** with HTTP servers. @@ -25,7 +26,16 @@ HTTPie is written in Python, and under the hood it uses the excellent `Requests`_ and `Pygments`_ libraries. -**Table of Contents** +----- + +|pypi| |unix_build| |windows_build| |coverage| + +----- + + +================= +Table of Contents +================= .. contents:: @@ -71,9 +81,16 @@ On **Mac OS X**, HTTPie can be installed via `Homebrew `_: $ brew install httpie -Most **Linux** distributions provide a package that can be installed via -system package manager, e.g. ``yum install httpie`` or ``apt-get install httpie``. -Note that the package might include a slightly older version of HTTPie. +Most **Linux** distributions provide a package that can be installed using the +the system package manager, e.g.: + +.. code-block:: bash + + # Debian-based distributions such as Ubuntu: + $ apt-get install httpie + + # RPM-based distributions: + $ yum install httpie A **universal installation method** (that works on **Windows**, Mac OS X, Linux, …, @@ -82,12 +99,14 @@ and provides the latest version) is to use `pip`_: .. code-block:: bash - $ pip install --upgrade httpie - + # Make sure we have an up-to-date version of pip and setuptools: + $ pip install --upgrade pip setuptools -If the above fails, please use ``easy_install`` instead (``$ easy_install httpie``). + $ pip install --upgrade httpie +(If ``pip`` installation fails for some reason, you can try +``easy_install httpie`` as a fallback.) ------------------- From 45784c7260460be24fbe3170a316a5db72cc104b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 15 Feb 2015 12:57:57 +0100 Subject: [PATCH 0065/1182] Fixed TOC --- README.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.rst b/README.rst index 76c25895b4..f9056ce588 100644 --- a/README.rst +++ b/README.rst @@ -33,11 +33,6 @@ HTTPie is written in Python, and under the hood it uses the excellent ----- -================= -Table of Contents -================= - - .. contents:: :local: :depth: 1 From dd7f1c4cce61bfa4c41dd05113a28c98d2f0de61 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Sun, 15 Feb 2015 20:33:57 -0800 Subject: [PATCH 0066/1182] tox.ini: Use pytest-httpbin>=0.0.6 This hopefully fixes SSL timeout errors. Fixes #308 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 1b6ee19b47..600ba3f118 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,7 @@ envlist = py26, py27, py34, pypy [testenv] deps = pytest - pytest-httpbin + pytest-httpbin>=0.0.6 commands = py.test --verbose --doctest-modules --basetemp={envtmpdir} {posargs:./tests ./httpie} From 51c19cfe10af1f93453e90ccb6ea2efda6c04fab Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Sun, 15 Feb 2015 21:42:34 -0800 Subject: [PATCH 0067/1182] test_ssl.py: Remove skip failures on PyPy Revert 985f65e which skipped SSL tests that failed on PyPy because @kevin1024 fixed the problem in pytest-httpbin 0.0.6 (commit https://github.com/kevin1024/pytest-httpbin/commit/f38a3124465925d9a2cf8d07c43a597f109d11ea) --- tests/test_ssl.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 2e303555cf..0fda410635 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -5,7 +5,6 @@ from requests.exceptions import SSLError from httpie import ExitStatus -from httpie.compat import is_pypy from utils import http, HTTP_OK, TESTS_ROOT @@ -19,9 +18,6 @@ CA_BUNDLE = pytest_httpbin.certs.where() -@pytest.mark.skipif( - is_pypy, - reason='https://github.com/jakubroztocil/httpie/issues/308') class TestClientSSLCertHandling(object): def test_cert_file_not_found(self, httpbin_secure): @@ -58,9 +54,6 @@ def test_cert_pem(self, httpbin_secure): assert HTTP_OK in r -@pytest.mark.skipif( - is_pypy, - reason='https://github.com/jakubroztocil/httpie/issues/308') class TestServerSSLCertHandling(object): def test_self_signed_server_cert_by_default_raises_ssl_error( From 7f8adad313999775992396fc39f6ccb5bdfd5af4 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Wed, 4 Feb 2015 10:34:43 -0800 Subject: [PATCH 0068/1182] Print info about request on error This can help in diagnosing certain issues. For example, if I were trying to use a "http+unix" URL but I don't have #299, then I'll get the following: [marca@marca-mac2 httpie]$ http http+unix://%2Ftmp%2Fprofilesvc.sock/status/pid http: error: ConnectionError: ('Connection aborted.', gaierror(8, 'nodename nor servname provided, or not known')) while doing GET request to URL: http://http+unix//%2Ftmp%2Fprofilesvc.sock/status/pid Having the URL in the error message is super useful here so that I know an extra `http://` is getting prepended and it's not doing what I expected. --- httpie/core.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/httpie/core.py b/httpie/core.py index 95f53abd55..83910ec7f0 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -183,7 +183,13 @@ def error(msg, *args, **kwargs): # Network errors vs. bugs, etc. if traceback: raise - error('%s: %s', type(e).__name__, str(e)) + msg = str(e) + if hasattr(e, 'request'): + request = e.request + if hasattr(request, 'url'): + msg += ' while doing %s request to URL: %s' % ( + request.method, request.url) + error('%s: %s', type(e).__name__, msg) exit_status = ExitStatus.ERROR finally: From f855de16c2c763241abc04594a89f4dfc6db3485 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Sun, 8 Feb 2015 08:17:35 -0800 Subject: [PATCH 0069/1182] Increase test coverage for error handling --- httpie/core.py | 7 +++++-- requirements-dev.txt | 1 + tests/test_errors.py | 48 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 tests/test_errors.py diff --git a/httpie/core.py b/httpie/core.py index 83910ec7f0..1660b93bc8 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -67,7 +67,7 @@ def decode_args(args, stdin_encoding): ] -def main(args=sys.argv[1:], env=Environment()): +def main(args=sys.argv[1:], env=Environment(), error=None): """Run the main program and write the output to ``env.stdout``. Return exit status code. @@ -81,11 +81,14 @@ def main(args=sys.argv[1:], env=Environment()): if env.config.default_options: args = env.config.default_options + args - def error(msg, *args, **kwargs): + def _error(msg, *args, **kwargs): msg = msg % args level = kwargs.get('level', 'error') env.stderr.write('\nhttp: %s: %s\n' % (level, msg)) + if error is None: + error = _error + debug = '--debug' in args traceback = debug or '--traceback' in args exit_status = ExitStatus.OK diff --git a/requirements-dev.txt b/requirements-dev.txt index 16fcc9cb45..9e132deba4 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,5 @@ tox +mock pytest pytest-cov pytest-httpbin diff --git a/tests/test_errors.py b/tests/test_errors.py new file mode 100644 index 0000000000..1d7cf24c82 --- /dev/null +++ b/tests/test_errors.py @@ -0,0 +1,48 @@ +import mock +from pytest import raises +from requests import Request, Timeout +from requests.exceptions import ConnectionError + +from httpie.core import main + +error_msg = None + + +@mock.patch('httpie.core.get_response') +def test_error(get_response): + def error(msg, *args, **kwargs): + global error_msg + error_msg = msg % args + + exc = ConnectionError('Connection aborted') + exc.request = Request(method='GET', url='http://www.google.com') + get_response.side_effect = exc + ret = main(['--ignore-stdin', 'www.google.com'], error=error) + assert ret == 1 + assert error_msg == ( + 'ConnectionError: ' + 'Connection aborted while doing GET request to URL: ' + 'http://www.google.com') + + +@mock.patch('httpie.core.get_response') +def test_error_traceback(get_response): + exc = ConnectionError('Connection aborted') + exc.request = Request(method='GET', url='http://www.google.com') + get_response.side_effect = exc + with raises(ConnectionError): + ret = main(['--ignore-stdin', '--traceback', 'www.google.com']) + + +@mock.patch('httpie.core.get_response') +def test_timeout(get_response): + def error(msg, *args, **kwargs): + global error_msg + error_msg = msg % args + + exc = Timeout('Request timed out') + exc.request = Request(method='GET', url='http://www.google.com') + get_response.side_effect = exc + ret = main(['--ignore-stdin', 'www.google.com'], error=error) + assert ret == 2 + assert error_msg == 'Request timed out (30s).' From ecc59591f182f14501be51cd6d1ffd429b17a3a6 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 16 Feb 2015 19:36:02 +0100 Subject: [PATCH 0070/1182] Disable urllib3's "Unverified HTTPS request is being made" warnings --- httpie/client.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/httpie/client.py b/httpie/client.py index 83b22f90b4..d54e93350a 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -3,6 +3,7 @@ from pprint import pformat import requests +from requests.packages import urllib3 from httpie import sessions from httpie import __version__ @@ -10,6 +11,10 @@ from httpie.plugins import plugin_manager +# https://urllib3.readthedocs.org/en/latest/security.html +urllib3.disable_warnings() + + FORM = 'application/x-www-form-urlencoded; charset=utf-8' JSON = 'application/json' DEFAULT_UA = 'HTTPie/%s' % __version__ From 2e88aa53cf70b9fa5f4bc2bcd832cfa4314d947f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 16 Feb 2015 21:16:39 +0100 Subject: [PATCH 0071/1182] Extracted changes from README into a proper CHANGELOG file Inspired by keepachangelog.com --- CHANGELOG.rst | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++ MANIFEST.in | 2 +- README.rst | 150 +----------------------------- 3 files changed, 248 insertions(+), 150 deletions(-) create mode 100644 CHANGELOG.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100644 index 0000000000..27af1b43ee --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,246 @@ +========== +Change Log +========== + +This document records all notable changes to `HTTPie `_. +This project adheres to `Semantic Versioning `_. + + +`1.0.0-dev`_ (Unreleased) +------------------------- + +* Changed the default color ``--style`` from ``solarized`` to ``monokai`` +* Changed the default JSON ``Content-Type`` to ``application/json`` as UTF-8 + is the default JSON encoding + + +`0.9.1`_ (2015-02-07) +--------------------- + +* Added support for Requests transport adapter plugins + (see `httpie-unixsocket `_ + and `httpie-http2 `_) + + +`0.9.0`_ (2015-01-31) +--------------------- + +* Added ``--cert`` and ``--cert-key`` parameters to specify a client side + certificate and private key for SSL +* Improved unicode support +* Improved terminal color depth detection via ``curses`` +* To make it easier to deal with Windows paths in request items, ``\`` + now only escapes special characters (the ones that are used as key-value + separators by HTTPie) +* Switched from ``unittest`` to ``pytest`` +* Added Python `wheel` support +* Various test suite improvements +* Added ``CONTRIBUTING`` +* Fixed ``User-Agent`` overwriting when used within a session +* Fixed handling of empty passwords in URL credentials +* Fixed multiple file uploads with the same form field name +* Fixed ``--output=/dev/null`` on Linux +* Miscellaneous bugfixes + + +`0.8.0`_ (2014-01-25) +--------------------- + +* Added ``field=@file.txt`` and ``field:=@file.json`` for embedding + the contents of text and JSON files into request data +* Added curl-style shorthand for localhost +* Fixed request ``Host`` header value output so that it doesn't contain + credentials, if included in the URL + + +`0.7.1`_ (2013-09-24) +--------------------- + +* Added ``--ignore-stdin`` +* Added support for auth plugins +* Improved ``--help`` output +* Improved ``Content-Disposition`` parsing for ``--download`` mode +* Update to Requests 2.0.0 + + +`0.6.0`_ (2013-06-03) +--------------------- + +* XML data is now formatted +* ``--session`` and ``--session-read-only`` now also accept paths to + session files (eg. ``http --session=/tmp/session.json example.org``) + + +`0.5.1`_ (2013-05-13) +--------------------- + +* ``Content-*`` and ``If-*`` request headers are not stored in sessions + anymore as they are request-specific + + +`0.5.0`_ (2013-04-27) +--------------------- + +* Added a download mode via ``--download`` +* Fixes miscellaneous bugs + + +`0.4.1`_ (2013-02-26) +--------------------- + +* Fixed ``setup.py`` + + +`0.4.0`_ (2013-02-22) +--------------------- + +* Added Python 3.3 compatibility +* Added Requests >= v1.0.4 compatibility +* Added support for credentials in URL +* Added ``--no-option`` for every ``--option`` to be config-friendly +* Mutually exclusive arguments can be specified multiple times. The + last value is used + + +`0.3.0`_ (2012-09-21) +--------------------- + +* Allow output redirection on Windows +* Added configuration file +* Added persistent session support +* Renamed ``--allow-redirects`` to ``--follow`` +* Improved the usability of ``http --help`` +* Fixed installation on Windows with Python 3 +* Fixed colorized output on Windows with Python 3 +* CRLF HTTP header field separation in the output +* Added exit status code ``2`` for timed-out requests +* Added the option to separate colorizing and formatting + (``--pretty=all``, ``--pretty=colors`` and ``--pretty=format``) + ``--ugly`` has bee removed in favor of ``--pretty=none`` + + +`0.2.7`_ (2012-08-07) +--------------------- + +* Added compatibility with Requests 0.13.6 +* Added streamed terminal output. ``--stream, -S`` can be used to enable + streaming also with ``--pretty`` and to ensure a more frequent output + flushing +* Added support for efficient large file downloads +* Sort headers by name (unless ``--pretty=none``) +* Response body is fetched only when needed (e.g., not with ``--headers``) +* Improved content type matching +* Updated Solarized color scheme +* Windows: Added ``--output FILE`` to store output into a file + (piping results in corrupted data on Windows) +* Proper handling of binary requests and responses +* Fixed printing of ``multipart/form-data`` requests +* Renamed ``--traceback`` to ``--debug`` + + +`0.2.6`_ (2012-07-26) +--------------------- + +* The short option for ``--headers`` is now ``-h`` (``-t`` has been + removed, for usage use ``--help``) +* Form data and URL parameters can have multiple fields with the same name + (e.g.,``http -f url a=1 a=2``) +* Added ``--check-status`` to exit with an error on HTTP 3xx, 4xx and + 5xx (3, 4, and 5, respectively) +* If the output is piped to another program or redirected to a file, + the default behaviour is to only print the response body + (It can still be overwritten via the ``--print`` flag.) +* Improved highlighting of HTTP headers +* Added query string parameters (``param==value``) +* Added support for terminal colors under Windows + + +`0.2.5`_ (2012-07-17) +--------------------- + +* Unicode characters in prettified JSON now don't get escaped for + improved readability +* --auth now prompts for a password if only a username provided +* Added support for request payloads from a file path with automatic + ``Content-Type`` (``http URL @/path``) +* Fixed missing query string when displaying the request headers via + ``--verbose`` +* Fixed Content-Type for requests with no data + + +`0.2.2`_ (2012-06-24) +--------------------- + +* The ``METHOD`` positional argument can now be omitted (defaults to + ``GET``, or to ``POST`` with data) +* Fixed --verbose --form +* Added support for Tox + + +`0.2.1`_ (2012-06-13) +--------------------- + +* Added compatibility with ``requests-0.12.1`` +* Dropped custom JSON and HTTP lexers in favor of the ones newly included + in ``pygments-1.5`` + + +`0.2.0`_ (2012-04-25) +--------------------- + +* Added Python 3 support +* Added the ability to print the HTTP request as well as the response + (see ``--print`` and ``--verbose``) +* Added support for Digest authentication +* Added file upload support + (``http -f POST file_field_name@/path/to/file``) +* Improved syntax highlighting for JSON +* Added support for field name escaping +* Many bug fixes + + +`0.1.6`_ (2012-03-04) +--------------------- + +* Fixed ``setup.py`` + + +`0.1.5`_ (2012-03-04) +--------------------- + +* Many improvements and bug fixes + + +`0.1.4`_ (2012-02-28) +--------------------- + +* Many improvements and bug fixes + + +`0.1`_ (2012-02-25) +------------------- + +* Initial public release + + +.. _`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 +.. _1.0.0-dev: https://github.com/jakubroztocil/httpie/compare/0.9.1...master diff --git a/MANIFEST.in b/MANIFEST.in index 0c738421d6..2bc8bb46e5 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1 @@ -include README.rst LICENSE +include LICENSE README.rst CHANGELOG.rst diff --git a/README.rst b/README.rst index f9056ce588..ba33aca057 100644 --- a/README.rst +++ b/README.rst @@ -1315,137 +1315,7 @@ Please see `LICENSE`_. Changelog ========= -*You can click a version name to see a diff with the previous one.* - -* `1.0.0-dev`_ - * The default color ``--style`` is now ``monokai`` (was ``solarized``). - * Changed the default JSON ``Content-Type`` - from ``application/json; charset=utf-8`` to ``application/json`` - as UTF-8 is the default encoding for JSON. -* `0.9.1`_ (2015-02-07) - * Added support for Requests transport adapter plugins - to enable plugin-provided features such as - `unix socket `_ - communication and - `HTTP/2 `_. -* `0.9.0`_ (2015-01-31) - * Added ``--cert`` and ``--cert-key`` parameters to specify a client side - certificate and private key for SSL - * Improved unicode support. - * Improved terminal color depth detection via ``curses``. - * To make it easier to deal with Windows paths in request items, ``\`` - now only escapes special characters (the ones that are used as key-value - separators by HTTPie). - * Switched from ``unittest`` to ``pytest``. - * Added Python `wheel` support. - * Various test suite improvements. - * Added `CONTRIBUTING`_. - * Fixed ``User-Agent`` overwriting when used within a session. - * Fixed handling of empty passwords in URL credentials. - * Fixed multiple file uploads with the same form field name. - * Fixed ``--output=/dev/null`` on Linux. - * Miscellaneous bugfixes. -* `0.8.0`_ (2014-01-25) - * Added ``field=@file.txt`` and ``field:=@file.json`` for embedding - the contents of text and JSON files into request data. - * Added curl-style shorthand for localhost. - * Fixed request ``Host`` header value output so that it doesn't contain - credentials, if included in the URL. -* `0.7.1`_ (2013-09-24) - * Added ``--ignore-stdin``. - * Added support for auth plugins. - * Improved ``--help`` output. - * Improved ``Content-Disposition`` parsing for ``--download`` mode. - * Update to Requests 2.0.0 -* `0.6.0`_ (2013-06-03) - * XML data is now formatted. - * ``--session`` and ``--session-read-only`` now also accept paths to - session files (eg. ``http --session=/tmp/session.json example.org``). -* `0.5.1`_ (2013-05-13) - * ``Content-*`` and ``If-*`` request headers are not stored in sessions - anymore as they are request-specific. -* `0.5.0`_ (2013-04-27) - * Added a `download mode`_ via ``--download``. - * Bugfixes. -* `0.4.1`_ (2013-02-26) - * Fixed ``setup.py``. -* `0.4.0`_ (2013-02-22) - * Python 3.3 compatibility. - * Requests >= v1.0.4 compatibility. - * Added support for credentials in URL. - * Added ``--no-option`` for every ``--option`` to be config-friendly. - * Mutually exclusive arguments can be specified multiple times. The - last value is used. -* `0.3.0`_ (2012-09-21) - * Allow output redirection on Windows. - * Added configuration file. - * Added persistent session support. - * Renamed ``--allow-redirects`` to ``--follow``. - * Improved the usability of ``http --help``. - * Fixed installation on Windows with Python 3. - * Fixed colorized output on Windows with Python 3. - * CRLF HTTP header field separation in the output. - * Added exit status code ``2`` for timed-out requests. - * Added the option to separate colorizing and formatting - (``--pretty=all``, ``--pretty=colors`` and ``--pretty=format``). - ``--ugly`` has bee removed in favor of ``--pretty=none``. -* `0.2.7`_ (2012-08-07) - * Compatibility with Requests 0.13.6. - * Streamed terminal output. ``--stream, -S`` can be used to enable - streaming also with ``--pretty`` and to ensure a more frequent output - flushing. - * Support for efficient large file downloads. - * Sort headers by name (unless ``--pretty=none``). - * Response body is fetched only when needed (e.g., not with ``--headers``). - * Improved content type matching. - * Updated Solarized color scheme. - * Windows: Added ``--output FILE`` to store output into a file - (piping results in corrupted data on Windows). - * Proper handling of binary requests and responses. - * Fixed printing of ``multipart/form-data`` requests. - * Renamed ``--traceback`` to ``--debug``. -* `0.2.6`_ (2012-07-26) - * The short option for ``--headers`` is now ``-h`` (``-t`` has been - removed, for usage use ``--help``). - * Form data and URL parameters can have multiple fields with the same name - (e.g.,``http -f url a=1 a=2``). - * Added ``--check-status`` to exit with an error on HTTP 3xx, 4xx and - 5xx (3, 4, and 5, respectively). - * If the output is piped to another program or redirected to a file, - the default behaviour is to only print the response body. - (It can still be overwritten via the ``--print`` flag.) - * Improved highlighting of HTTP headers. - * Added query string parameters (``param==value``). - * Added support for terminal colors under Windows. -* `0.2.5`_ (2012-07-17) - * Unicode characters in prettified JSON now don't get escaped for - improved readability. - * --auth now prompts for a password if only a username provided. - * Added support for request payloads from a file path with automatic - ``Content-Type`` (``http URL @/path``). - * Fixed missing query string when displaying the request headers via - ``--verbose``. - * Fixed Content-Type for requests with no data. -* `0.2.2`_ (2012-06-24) - * The ``METHOD`` positional argument can now be omitted (defaults to - ``GET``, or to ``POST`` with data). - * Fixed --verbose --form. - * Added support for `Tox`_. -* `0.2.1`_ (2012-06-13) - * Added compatibility with ``requests-0.12.1``. - * Dropped custom JSON and HTTP lexers in favor of the ones newly included - in ``pygments-1.5``. -* `0.2.0`_ (2012-04-25) - * Added Python 3 support. - * Added the ability to print the HTTP request as well as the response - (see ``--print`` and ``--verbose``). - * Added support for Digest authentication. - * Added file upload support - (``http -f POST file_field_name@/path/to/file``). - * Improved syntax highlighting for JSON. - * Added support for field name escaping. - * Many bug fixes. -* `0.1.6`_ (2012-03-04) +Please see `CHANGELOG `_. .. _Requests: http://python-requests.org @@ -1456,24 +1326,6 @@ Changelog .. _Jakub Roztocil: http://subtleapps.com .. _@jakubroztocil: https://twitter.com/jakubroztocil .. _claudiatd/httpie-artwork: https://github.com/claudiatd/httpie-artwork -.. _0.1.6: https://github.com/jakubroztocil/httpie/compare/0.1.4...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 -.. _1.0.0-dev: https://github.com/jakubroztocil/httpie/compare/0.9.1...master .. _LICENSE: https://github.com/jakubroztocil/httpie/blob/master/LICENSE .. _Tox: http://tox.testrun.org .. _CONTRIBUTING: https://github.com/jakubroztocil/httpie/blob/master/CONTRIBUTING.rst From b7fc89acdc38fe050eead416bbe2db098d87a504 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 16 Feb 2015 21:29:40 +0100 Subject: [PATCH 0072/1182] README fixes --- README.rst | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/README.rst b/README.rst index ba33aca057..eca7a45e19 100644 --- a/README.rst +++ b/README.rst @@ -1281,14 +1281,17 @@ and usage from scripts, where HTTPie serves as a generic HTTP client. As HTTPie is still under heavy development, the existing command line syntax and some of the ``--OPTIONS`` may change slightly before HTTPie reaches its final version ``1.0``. All changes are recorded in the -`changelog`_. +`change log`_. + + + ========== Contribute ========== -Please see `CONTRIBUTING`_. +Please see `CONTRIBUTING `_. ==== @@ -1297,6 +1300,7 @@ Logo Please see `claudiatd/httpie-artwork`_ + ======= Authors ======= @@ -1304,18 +1308,20 @@ Authors `Jakub Roztocil`_ (`@jakubroztocil`_) created HTTPie and `these fine people`_ have contributed. + +========== +Change Log +========== + +Please see `CHANGELOG `_. + + ======= Licence ======= -Please see `LICENSE`_. - +Please see `LICENSE `_. -========= -Changelog -========= - -Please see `CHANGELOG `_. .. _Requests: http://python-requests.org @@ -1326,9 +1332,6 @@ Please see `CHANGELOG `_. .. _Jakub Roztocil: http://subtleapps.com .. _@jakubroztocil: https://twitter.com/jakubroztocil .. _claudiatd/httpie-artwork: https://github.com/claudiatd/httpie-artwork -.. _LICENSE: https://github.com/jakubroztocil/httpie/blob/master/LICENSE -.. _Tox: http://tox.testrun.org -.. _CONTRIBUTING: https://github.com/jakubroztocil/httpie/blob/master/CONTRIBUTING.rst .. |pypi| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square&label=latest%20version From fb437591dae366a9bcd9366d6b32481a8ab4316e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 16 Feb 2015 21:42:09 +0100 Subject: [PATCH 0073/1182] Include AUTHORS.rst in dist; metadata cleanup --- LICENSE | 2 +- MANIFEST.in | 5 ++++- README.rst | 26 +++++++++----------------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/LICENSE b/LICENSE index 027da677e9..329f42ace7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright © 2012 Jakub Roztocil +Copyright © 2012 Jakub Roztocil Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/MANIFEST.in b/MANIFEST.in index 2bc8bb46e5..3d6d0baba9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,4 @@ -include LICENSE README.rst CHANGELOG.rst +include LICENSE +include README.rst +include CHANGELOG.rst +include AUTHORS.rst diff --git a/README.rst b/README.rst index eca7a45e19..2e1ec128b6 100644 --- a/README.rst +++ b/README.rst @@ -1,12 +1,7 @@ - - **************************************** HTTPie: a CLI, cURL-like tool for humans **************************************** - - - HTTPie (pronounced *aych-tee-tee-pie*) is a **command line HTTP client**. Its goal is to make CLI interaction with web services as **human-friendly** as possible. It provides a simple ``http`` command that allows for sending @@ -63,8 +58,6 @@ Main Features Installation ============ - - -------------- Stable version -------------- @@ -1285,13 +1278,13 @@ HTTPie reaches its final version ``1.0``. All changes are recorded in the +======= +Authors +======= -========== -Contribute -========== - -Please see `CONTRIBUTING `_. +`Jakub Roztocil`_ (`@jakubroztocil`_) created HTTPie and `these fine people`_ +have contributed. ==== @@ -1301,12 +1294,11 @@ Logo Please see `claudiatd/httpie-artwork`_ -======= -Authors -======= +========== +Contribute +========== -`Jakub Roztocil`_ (`@jakubroztocil`_) created HTTPie and `these fine people`_ -have contributed. +Please see `CONTRIBUTING `_. ========== From 24957e3b611d7d9c642bf9396c30e0e07cd62cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Mon, 16 Feb 2015 21:55:40 +0100 Subject: [PATCH 0074/1182] Update requirements-dev.txt dd7f1c4 --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 16fcc9cb45..359dad65bc 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,6 +1,6 @@ tox pytest pytest-cov -pytest-httpbin +pytest-httpbin>=0.0.6 docutils wheel From e4bc363f9ec0440eca26c1d3f865e3036f6ceea4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 24 Feb 2015 07:39:26 +0100 Subject: [PATCH 0075/1182] Don't depend on `requests.compat` #314 --- httpie/compat.py | 26 ++++++++++++++++++++------ httpie/context.py | 3 +-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/httpie/compat.py b/httpie/compat.py index 6de0261698..d78d94f311 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -2,12 +2,26 @@ Python 2.6, 2.7, and 3.x compatibility. """ -# Borrow these from requests: -# noinspection PyUnresolvedReferences -from requests.compat import ( - is_windows, bytes, str, - is_py3, is_py26, is_pypy, is_py27 -) +import sys + + +# Taken from `requests.compat` +_ver = sys.version_info +is_py2 = (_ver[0] == 2) +is_py26 = (is_py2 and _ver[1] == 6) +is_py27 = (is_py2 and _ver[1] == 7) +is_py3 = (_ver[0] == 3) +is_pypy = ('pypy' in _ver) +is_windows = 'win32' in str(sys.platform).lower() + + +if is_py2: + bytes = str + str = unicode +elif is_py3: + str = str + bytes = bytes + try: # pragma: no cover # noinspection PyUnresolvedReferences,PyCompatibility diff --git a/httpie/context.py b/httpie/context.py index 6be232c493..cd97831d7c 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -1,7 +1,6 @@ import sys -from requests.compat import is_windows - +from httpie.compat import is_windows from httpie.config import DEFAULT_CONFIG_DIR, Config From bada3b45f1aad1615a423543990982bbde31f90b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 24 Feb 2015 07:47:25 +0100 Subject: [PATCH 0076/1182] Use absolute links to LICENCE, etc. --- CHANGELOG.rst | 9 ++++++++- README.rst | 6 +++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 27af1b43ee..958fb28249 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,12 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (Unreleased) ------------------------- + + +`0.9.2`_ (2015-02-24) +--------------------- + +* Fixed compatibility with Requests 2.5.1 * Changed the default color ``--style`` from ``solarized`` to ``monokai`` * Changed the default JSON ``Content-Type`` to ``application/json`` as UTF-8 is the default JSON encoding @@ -243,4 +249,5 @@ This project adheres to `Semantic Versioning `_. .. _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 -.. _1.0.0-dev: https://github.com/jakubroztocil/httpie/compare/0.9.1...master +.. _0.9.2: https://github.com/jakubroztocil/httpie/compare/0.9.1...0.9.2 +.. _1.0.0-dev: https://github.com/jakubroztocil/httpie/compare/0.9.2...master diff --git a/README.rst b/README.rst index 2e1ec128b6..cce333d8bc 100644 --- a/README.rst +++ b/README.rst @@ -1298,21 +1298,21 @@ Please see `claudiatd/httpie-artwork`_ Contribute ========== -Please see `CONTRIBUTING `_. +Please see `CONTRIBUTING `_. ========== Change Log ========== -Please see `CHANGELOG `_. +Please see `CHANGELOG `_. ======= Licence ======= -Please see `LICENSE `_. +Please see `LICENSE `_. From a228399801e25ee6d3a9f80cde778d13fe00c25d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 24 Feb 2015 07:49:24 +0100 Subject: [PATCH 0077/1182] 0.9.2 --- CHANGELOG.rst | 1 - httpie/__init__.py | 2 +- httpie/output/formatters/colors.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 958fb28249..e195107f6c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,7 +15,6 @@ This project adheres to `Semantic Versioning `_. --------------------- * Fixed compatibility with Requests 2.5.1 -* Changed the default color ``--style`` from ``solarized`` to ``monokai`` * Changed the default JSON ``Content-Type`` to ``application/json`` as UTF-8 is the default JSON encoding diff --git a/httpie/__init__.py b/httpie/__init__.py index 7ae07c9ee2..80709335b6 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '1.0.0-dev' +__version__ = '0.9.2' __licence__ = 'BSD' diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 65a57d7bc5..45cd0d9561 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -14,7 +14,7 @@ # great and fruity seems to give the best result there. AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys()) AVAILABLE_STYLES.add('solarized') -DEFAULT_STYLE = 'monokai' +DEFAULT_STYLE = 'solarized' class ColorFormatter(FormatterPlugin): From 1c181a5d25e4c36fa39cae277fc46e44dfc73d1e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 24 Feb 2015 07:52:34 +0100 Subject: [PATCH 0078/1182] 1.0.0-dev --- CHANGELOG.rst | 1 + httpie/__init__.py | 2 +- httpie/output/formatters/colors.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e195107f6c..59a2a745bd 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,7 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (Unreleased) ------------------------- +* Changed the default color ``--style`` from ``solarized`` to ``monokai`` `0.9.2`_ (2015-02-24) diff --git a/httpie/__init__.py b/httpie/__init__.py index 80709335b6..7ae07c9ee2 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '0.9.2' +__version__ = '1.0.0-dev' __licence__ = 'BSD' diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 45cd0d9561..65a57d7bc5 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -14,7 +14,7 @@ # great and fruity seems to give the best result there. AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys()) AVAILABLE_STYLES.add('solarized') -DEFAULT_STYLE = 'solarized' +DEFAULT_STYLE = 'monokai' class ColorFormatter(FormatterPlugin): From fdae686e12c07fa6af1b2904513faa747d252afd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 24 Feb 2015 08:18:03 +0100 Subject: [PATCH 0079/1182] Clean up `compat` and fix `is_pypy`. --- httpie/compat.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/httpie/compat.py b/httpie/compat.py index d78d94f311..2e9e329148 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -5,13 +5,11 @@ import sys -# Taken from `requests.compat` -_ver = sys.version_info -is_py2 = (_ver[0] == 2) -is_py26 = (is_py2 and _ver[1] == 6) -is_py27 = (is_py2 and _ver[1] == 7) -is_py3 = (_ver[0] == 3) -is_pypy = ('pypy' in _ver) +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() is_windows = 'win32' in str(sys.platform).lower() From 5f3de558cb661562ade85016eac38d88bc9ddc07 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 24 Feb 2015 10:18:17 +0100 Subject: [PATCH 0080/1182] README --- README.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.rst b/README.rst index cce333d8bc..02ea52ac41 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,7 @@ colorized output. HTTPie can be used for **testing, debugging**, and generally **interacting** with HTTP servers. -.. image:: httpie.png +.. image:: https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.png :alt: HTTPie compared to cURL :width: 679 :height: 781 @@ -58,9 +58,6 @@ Main Features Installation ============ --------------- -Stable version --------------- On **Mac OS X**, HTTPie can be installed via `Homebrew `_: From fdabbc6048e4f1df736e989770e26f4c96cb83ca Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 24 Feb 2015 16:50:02 +0100 Subject: [PATCH 0081/1182] Typo --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 02ea52ac41..eb2a7248a4 100644 --- a/README.rst +++ b/README.rst @@ -67,7 +67,7 @@ On **Mac OS X**, HTTPie can be installed via `Homebrew `_: Most **Linux** distributions provide a package that can be installed using the -the system package manager, e.g.: +system package manager, e.g.: .. code-block:: bash From 1a43c0e5f74fdae39a34aa76f94aa7be4015a367 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 28 Feb 2015 17:02:05 +0100 Subject: [PATCH 0082/1182] Fixed --debug output --- httpie/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/client.py b/httpie/client.py index d54e93350a..ec9e33f293 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -52,7 +52,7 @@ def get_response(args, config_dir): def dump_request(kwargs): - sys.stderr.write('\n>>> requests.request(%s)\n\n' + sys.stderr.write('\n>>> requests.request(**%s)\n\n' % pformat(kwargs)) From 798cd4f0ec85020d5997f466322ddb888c9f633b Mon Sep 17 00:00:00 2001 From: Willson Mock Date: Sun, 8 Mar 2015 11:29:33 -0700 Subject: [PATCH 0083/1182] Update license with up-to-date year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 329f42ace7..e3b1fc8256 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright © 2012 Jakub Roztocil +Copyright © 2012-2015 Jakub Roztocil Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From ece85c0f0c7dbe747ca1c79bea30e8c2c092469f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrew=20Marcinkevi=C4=8Dius?= Date: Tue, 10 Mar 2015 10:05:13 +0200 Subject: [PATCH 0084/1182] Fix typos, improve readability --- README.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index eb2a7248a4..59b5d6ac2b 100644 --- a/README.rst +++ b/README.rst @@ -277,7 +277,7 @@ If the port is omitted, then port 80 is assumed. GET / HTTP/1.1 Host: localhost -If find yourself manually constructing URLs with **querystring parameters** +If you find yourself manually constructing URLs with **querystring parameters** on the terminal, you may appreciate the ``param==value`` syntax for appending URL parameters so that you don't have to worry about escaping the ``&`` separators. To search for ``HTTPie`` on Google Images you could use this @@ -315,7 +315,7 @@ their type is distinguished only by the separator used: +-----------------------+-----------------------------------------------------+ | URL parameters | Appends the given name/value pair as a query | | ``name==value`` | string parameter to the URL. | -| | The ``==`` separator is used | +| | The ``==`` separator is used. | +-----------------------+-----------------------------------------------------+ | Data Fields | Request data fields to be serialized as a JSON | | ``field=value``, | object (default), or to be form-encoded | @@ -446,7 +446,8 @@ Regular Forms .. code-block:: bash - $ http --form POST api.example.org/person/1 name='John Smith' email=john@example.org cv=@~/Documents/cv.txt + $ http --form POST api.example.org/person/1 name='John Smith' \ + email=john@example.org cv=@~/Documents/cv.txt .. code-block:: http @@ -491,7 +492,8 @@ To set custom headers you can use the ``Header:Value`` notation: .. code-block:: bash - $ http example.org User-Agent:Bacon/1.0 'Cookie:valued-visitor=yes;foo=bar' X-Foo:Bar Referer:http://httpie.org/ + $ http example.org User-Agent:Bacon/1.0 'Cookie:valued-visitor=yes;foo=bar' \ + X-Foo:Bar Referer:http://httpie.org/ .. code-block:: http @@ -532,7 +534,7 @@ The currently supported authentication schemes are Basic and Digest the argument. Or, if you only specify a username (``-a username``), you'll be prompted for the password before the request is sent. - To send a an empty password, pass ``username:``. + To send an empty password, pass ``username:``. The ``username:password@hostname`` URL syntax is supported as well (but credentials passed via ``-a`` have higher priority). From ab0d1fd8d09e048fd34c71076b7c79389b29fc70 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 13 Mar 2015 17:17:03 +0100 Subject: [PATCH 0085/1182] Added .editorconfig. --- .editorconfig | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..532b12b6de --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.yml] +indent_size = 2 + +[Makefile] +indent_style = tab +indent_size = 8 From 29a0147dd573de54dd5c9c1fb3babc60cf00eaa9 Mon Sep 17 00:00:00 2001 From: Mihir Joshi Date: Tue, 24 Mar 2015 22:26:10 -0400 Subject: [PATCH 0086/1182] See #326 Adds bash completion to http command line interface. Installing the script: You can copy it to /etc/bash_completion.d/ (or something else on your machine) and source it using following command $ source /etc/profile Now whenever you encounter a "-*" on your CLI, it presents you with the options specified. Couple of things that are still under work: 1) Adding this bash script to setup, so that user won't need manual installation 2) Adding more options for HTTP (GET, PUT and so on) and other options --- httpie-completion.bash | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 httpie-completion.bash diff --git a/httpie-completion.bash b/httpie-completion.bash new file mode 100644 index 0000000000..fdb4c67fe0 --- /dev/null +++ b/httpie-completion.bash @@ -0,0 +1,22 @@ +#!/bin/env bash + +_http_complete() { + local cur_word=${COMP_WORDS[COMP_CWORD]} + local prev_word=${COMP_WORDS[COMP_CWORD - 1]} + + if [[ "$cur_word" == -* ]]; then + _http_complete_options "$cur_word" + fi +} + +complete -o default -F _http_complete http + +_http_complete_options() { + local cur_word=$1 + local options="-j --json -f --form --pretty -s --style -p --print + -v --verbose -h --headers -b --body -S --stream -o --output -d --download + -c --continue --session --session-read-only -a --auth --auth-type --proxy + --follow --verify --cert --cert-key --timeout --check-status --ignore-stdin + --help --version --traceback --debug" + COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) ) +} From 62407f781fefed51ec0702d0e2238d194f2c07e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Wed, 25 Mar 2015 22:35:36 +0100 Subject: [PATCH 0087/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 59a2a745bd..575ce5d9e2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,7 @@ This project adheres to `Semantic Versioning `_. ------------------------- * Changed the default color ``--style`` from ``solarized`` to ``monokai`` +* Added Bash auto complete support `0.9.2`_ (2015-02-24) From daf35739081e3f014ab05a783c0c8e9282f93f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Wed, 25 Mar 2015 22:37:48 +0100 Subject: [PATCH 0088/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 575ce5d9e2..37d0793e19 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,7 @@ This project adheres to `Semantic Versioning `_. * Changed the default color ``--style`` from ``solarized`` to ``monokai`` * Added Bash auto complete support +* Added request details to connection error messages `0.9.2`_ (2015-02-24) From 483546d781a9c26779953de74f0911b279da7550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Wed, 25 Mar 2015 22:52:49 +0100 Subject: [PATCH 0089/1182] Added mock to tests_require --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 4e93a6d588..1e52ba8d8a 100644 --- a/setup.py +++ b/setup.py @@ -31,6 +31,7 @@ def run_tests(self): # https://bitbucket.org/pypa/setuptools/issue/196/ 'pytest-httpbin', 'pytest', + 'mock', ] From 6fd0f23f399e51065d63c2dcf33b1c75d7bf7055 Mon Sep 17 00:00:00 2001 From: Joao Delgado Date: Sat, 11 Apr 2015 02:11:22 +0100 Subject: [PATCH 0090/1182] Only serialize json if data is a dict instance --- httpie/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/client.py b/httpie/client.py index ec9e33f293..ad258f241b 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -92,7 +92,7 @@ def get_requests_kwargs(args, base_headers=None): # Serialize JSON data, if needed. data = args.data auto_json = data and not args.form - if args.json or auto_json and isinstance(data, dict): + if (args.json or auto_json) and isinstance(data, dict): if data: data = json.dumps(data) else: From ced0838598944c3555275545a718689faf2ba25b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 26 Jun 2015 16:25:53 +0200 Subject: [PATCH 0091/1182] Converted tabs to spaces. --- httpie-completion.bash | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/httpie-completion.bash b/httpie-completion.bash index fdb4c67fe0..6201954bad 100644 --- a/httpie-completion.bash +++ b/httpie-completion.bash @@ -1,22 +1,23 @@ -#!/bin/env bash +#!/usr/bin/env bash + _http_complete() { - local cur_word=${COMP_WORDS[COMP_CWORD]} - local prev_word=${COMP_WORDS[COMP_CWORD - 1]} + local cur_word=${COMP_WORDS[COMP_CWORD]} + local prev_word=${COMP_WORDS[COMP_CWORD - 1]} - if [[ "$cur_word" == -* ]]; then - _http_complete_options "$cur_word" - fi + if [[ "$cur_word" == -* ]]; then + _http_complete_options "$cur_word" + fi } complete -o default -F _http_complete http _http_complete_options() { - local cur_word=$1 - local options="-j --json -f --form --pretty -s --style -p --print - -v --verbose -h --headers -b --body -S --stream -o --output -d --download - -c --continue --session --session-read-only -a --auth --auth-type --proxy - --follow --verify --cert --cert-key --timeout --check-status --ignore-stdin - --help --version --traceback --debug" - COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) ) + local cur_word=$1 + local options="-j --json -f --form --pretty -s --style -p --print + -v --verbose -h --headers -b --body -S --stream -o --output -d --download + -c --continue --session --session-read-only -a --auth --auth-type --proxy + --follow --verify --cert --cert-key --timeout --check-status --ignore-stdin + --help --version --traceback --debug" + COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) ) } From be9d9281b7b54375027de7d2afb89385298fce7f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 30 Jun 2015 11:50:11 +0200 Subject: [PATCH 0092/1182] Added a link to the httpie-edgegrid plugin. --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 59b5d6ac2b..5ec25c26f6 100644 --- a/README.rst +++ b/README.rst @@ -592,6 +592,7 @@ Auth Plugins * `httpie-negotiate `_: SPNEGO (GSS Negotiate) * `requests-hawk `_: Hawk * `httpie-api-auth `_: ApiAuth +* `httpie-edgegrid` : EdgeGrid ======= From f8c1104429ac7f6018d5bd3898a40dd3df32b7c9 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 30 Jun 2015 11:51:40 +0200 Subject: [PATCH 0093/1182] Fixed link to httpie-edgegrid --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 5ec25c26f6..63e023e3e8 100644 --- a/README.rst +++ b/README.rst @@ -592,7 +592,7 @@ Auth Plugins * `httpie-negotiate `_: SPNEGO (GSS Negotiate) * `requests-hawk `_: Hawk * `httpie-api-auth `_: ApiAuth -* `httpie-edgegrid` : EdgeGrid +* `httpie-edgegrid `_: EdgeGrid ======= From fa4bd033effac1f8e77df33521a94048c153102b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Fri, 3 Jul 2015 03:40:38 +0200 Subject: [PATCH 0094/1182] Updated links. --- README.rst | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/README.rst b/README.rst index 63e023e3e8..b8d3c952f1 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,7 @@ colorized output. HTTPie can be used for **testing, debugging**, and generally **interacting** with HTTP servers. -.. image:: https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.png +.. image:: https://raw.githubusercontent.com/jkbrzt/httpie/master/httpie.png :alt: HTTPie compared to cURL :width: 679 :height: 781 @@ -106,7 +106,7 @@ The **latest development version** can be installed directly from GitHub: $ brew install httpie --HEAD # Universal - $ pip install --upgrade https://github.com/jakubroztocil/httpie/tarball/master + $ pip install --upgrade https://github.com/jkbrzt/httpie/tarball/master @@ -159,12 +159,12 @@ See the request that is being sent using one of the `output options`_: Use `Github API`_ to post a comment on an -`issue `_ +`issue `_ with `authentication`_: .. code-block:: bash - $ http -a USERNAME POST https://api.github.com/repos/jakubroztocil/httpie/issues/83/comments body='HTTPie is awesome!' + $ http -a USERNAME POST https://api.github.com/repos/jkbrzt/httpie/issues/83/comments body='HTTPie is awesome!' Upload a file using `redirected input`_: @@ -587,8 +587,8 @@ Authorization information from your ``~/.netrc`` file is honored as well: Auth Plugins ------------ -* `httpie-oauth `_: OAuth -* `httpie-ntlm `_: NTLM (NT LAN Manager) +* `httpie-oauth `_: OAuth +* `httpie-ntlm `_: NTLM (NT LAN Manager) * `httpie-negotiate `_: SPNEGO (GSS Negotiate) * `requests-hawk `_: Hawk * `httpie-api-auth `_: ApiAuth @@ -824,7 +824,7 @@ You can even pipe web services together using HTTPie: .. code-block:: bash - $ http GET https://api.github.com/repos/jakubroztocil/httpie | http POST httpbin.org/post + $ http GET https://api.github.com/repos/jkbrzt/httpie | http POST httpbin.org/post You can use ``cat`` to enter multiline data on the terminal: @@ -1008,19 +1008,19 @@ is being saved to a file. .. code-block:: bash - $ http --download https://github.com/jakubroztocil/httpie/tarball/master + $ http --download https://github.com/jkbrzt/httpie/tarball/master .. code-block:: http HTTP/1.1 200 OK Connection: keep-alive - Content-Disposition: attachment; filename=jakubroztocil-httpie-0.4.1-33-gfc4f70a.tar.gz + Content-Disposition: attachment; filename=jkbrzt-httpie-0.4.1-33-gfc4f70a.tar.gz Content-Length: 505530 Content-Type: application/x-gzip Server: GitHub.com Vary: Accept-Encoding - Downloading 494.89 kB to "jakubroztocil-httpie-0.4.1-33-gfc4f70a.tar.gz" + Downloading 494.89 kB to "jkbrzt-httpie-0.4.1-33-gfc4f70a.tar.gz" / 21.01% 104.00 kB 47.55 kB/s 0:00:08 ETA @@ -1034,7 +1034,7 @@ headers and progress are still shown in the terminal: .. code-block:: bash - $ http -d https://github.com/jakubroztocil/httpie/tarball/master | tar zxf - + $ http -d https://github.com/jkbrzt/httpie/tarball/master | tar zxf - If ``--output, -o`` is specified, you can resume a partial download using the @@ -1283,7 +1283,7 @@ Authors ======= -`Jakub Roztocil`_ (`@jakubroztocil`_) created HTTPie and `these fine people`_ +`Jakub Roztocil`_ (`@jkbrzt`_) created HTTPie and `these fine people`_ have contributed. @@ -1298,21 +1298,21 @@ Please see `claudiatd/httpie-artwork`_ Contribute ========== -Please see `CONTRIBUTING `_. +Please see `CONTRIBUTING `_. ========== Change Log ========== -Please see `CHANGELOG `_. +Please see `CHANGELOG `_. ======= Licence ======= -Please see `LICENSE `_. +Please see `LICENSE `_. @@ -1320,9 +1320,9 @@ Please see `LICENSE Date: Fri, 3 Jul 2015 18:55:45 +0200 Subject: [PATCH 0095/1182] Updated links II. --- .travis.yml | 2 +- AUTHORS.rst | 2 +- CHANGELOG.rst | 46 +++++++++++++++++++-------------------- CONTRIBUTING.rst | 8 +++---- appveyor.yml | 2 +- httpie/cli.py | 2 +- httpie/client.py | 2 +- httpie/config.py | 2 +- httpie/downloads.py | 2 +- httpie/input.py | 2 +- httpie/plugins/base.py | 2 +- httpie/plugins/builtin.py | 2 +- httpie/sessions.py | 2 +- setup.py | 4 ++-- tests/README.rst | 2 +- tests/test_auth.py | 2 +- tests/test_defaults.py | 4 ++-- tests/test_httpie.py | 2 +- tests/test_output.py | 2 +- tests/test_regressions.py | 4 ++-- tests/test_sessions.py | 4 ++-- 21 files changed, 50 insertions(+), 50 deletions(-) diff --git a/.travis.yml b/.travis.yml index e2b6f1683d..e3c02ea7b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -# https://travis-ci.org/jakubroztocil/httpie +# https://travis-ci.org/jkbrzt/httpie sudo: false os: - linux diff --git a/AUTHORS.rst b/AUTHORS.rst index a066f5a451..0dceb04c23 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -2,7 +2,7 @@ HTTPie authors ============== -* `Jakub Roztocil `_ +* `Jakub Roztocil `_ Patches and ideas diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 37d0793e19..5730923227 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,7 +27,7 @@ This project adheres to `Semantic Versioning `_. * Added support for Requests transport adapter plugins (see `httpie-unixsocket `_ - and `httpie-http2 `_) + and `httpie-http2 `_) `0.9.0`_ (2015-01-31) @@ -231,25 +231,25 @@ This project adheres to `Semantic Versioning `_. * Initial public release -.. _`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 -.. _1.0.0-dev: https://github.com/jakubroztocil/httpie/compare/0.9.2...master +.. _`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 +.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.2...master diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index e63cbb8b88..b5052b310e 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -87,9 +87,9 @@ Don't forget to add yourself to `AUTHORS.rst`_. .. _Tox: http://tox.testrun.org -.. _supported Python environments: https://github.com/jakubroztocil/httpie/blob/master/tox.ini -.. _existing issues: https://github.com/jakubroztocil/httpie/issues?state=open -.. _AUTHORS.rst: https://github.com/jakubroztocil/httpie/blob/master/AUTHORS.rst +.. _supported Python environments: https://github.com/jkbrzt/httpie/blob/master/tox.ini +.. _existing issues: https://github.com/jkbrzt/httpie/issues?state=open +.. _AUTHORS.rst: https://github.com/jkbrzt/httpie/blob/master/AUTHORS.rst .. _pytest: http://pytest.org/ .. _Style Guide for Python Code: http://python.org/dev/peps/pep-0008/ -.. _test suite: https://github.com/jakubroztocil/httpie/tree/master/tests +.. _test suite: https://github.com/jkbrzt/httpie/tree/master/tests diff --git a/appveyor.yml b/appveyor.yml index 81e9ce88f0..1e73b258e0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -# https://ci.appveyor.com/project/jakubroztocil/httpie +# https://ci.appveyor.com/project/jkbrzt/httpie build: false environment: matrix: diff --git a/httpie/cli.py b/httpie/cli.py index 575683cec7..2b05a88380 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -49,7 +49,7 @@ def _split_lines(self, text, width): Suggestions and bug reports are greatly appreciated: - https://github.com/jakubroztocil/httpie/issues + https://github.com/jkbrzt/httpie/issues """) ) diff --git a/httpie/client.py b/httpie/client.py index ad258f241b..5f24a049f7 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -58,7 +58,7 @@ def dump_request(kwargs): def encode_headers(headers): # This allows for unicode headers which is non-standard but practical. - # See: https://github.com/jakubroztocil/httpie/issues/212 + # See: https://github.com/jkbrzt/httpie/issues/212 return dict( (name, value.encode('utf8') if isinstance(value, str) else value) for name, value in headers.items() diff --git a/httpie/config.py b/httpie/config.py index fa1f789a42..9f28da175f 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -80,7 +80,7 @@ def delete(self): class Config(BaseConfigDict): name = 'config' - helpurl = 'https://github.com/jakubroztocil/httpie#config' + helpurl = 'https://github.com/jkbrzt/httpie#config' about = 'HTTPie configuration file' DEFAULTS = { diff --git a/httpie/downloads.py b/httpie/downloads.py index 77a8de6775..122a3b3d0f 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -104,7 +104,7 @@ def filename_from_content_disposition(content_disposition): :return: the filename if present and valid, otherwise `None` """ - # attachment; filename=jakubroztocil-httpie-0.4.1-20-g40bd8f6.tar.gz + # attachment; filename=jkbrzt-httpie-0.4.1-20-g40bd8f6.tar.gz msg = Message('Content-Disposition: %s' % content_disposition) filename = msg.get_filename() diff --git a/httpie/input.py b/httpie/input.py index e21d2a4275..da3cc5255f 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -13,7 +13,7 @@ from argparse import ArgumentParser, ArgumentTypeError, ArgumentError # TODO: Use MultiDict for headers once added to `requests`. -# https://github.com/jakubroztocil/httpie/issues/130 +# https://github.com/jkbrzt/httpie/issues/130 from requests.structures import CaseInsensitiveDict from httpie.compat import OrderedDict, urlsplit, str, is_pypy, is_py27 diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index d1211540db..ff6e6a2044 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -15,7 +15,7 @@ class AuthPlugin(BasePlugin): """ Base auth plugin class. - See for an example auth plugin. + See for an example auth plugin. """ # The value that should be passed to --auth-type diff --git a/httpie/plugins/builtin.py b/httpie/plugins/builtin.py index 08efe660bc..0f1a806b73 100644 --- a/httpie/plugins/builtin.py +++ b/httpie/plugins/builtin.py @@ -16,7 +16,7 @@ def __call__(self, r): """ Override username/password serialization to allow unicode. - See https://github.com/jakubroztocil/httpie/issues/212 + See https://github.com/jkbrzt/httpie/issues/212 """ r.headers['Authorization'] = type(self).make_header( diff --git a/httpie/sessions.py b/httpie/sessions.py index 5280146cf6..e61a8e3e2a 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -75,7 +75,7 @@ def get_response(requests_session, session_name, class Session(BaseConfigDict): - helpurl = 'https://github.com/jakubroztocil/httpie#sessions' + helpurl = 'https://github.com/jkbrzt/httpie#sessions' about = 'HTTPie session file' def __init__(self, path, *args, **kwargs): diff --git a/setup.py b/setup.py index 1e52ba8d8a..cab89c7c06 100644 --- a/setup.py +++ b/setup.py @@ -75,9 +75,9 @@ def long_description(): description=httpie.__doc__.strip(), long_description=long_description(), url='http://httpie.org/', - download_url='https://github.com/jakubroztocil/httpie', + download_url='https://github.com/jkbrzt/httpie', author=httpie.__author__, - author_email='jakub@roztocil.name', + author_email='jakub@roztocil.co', license=httpie.__licence__, packages=find_packages(), entry_points={ diff --git a/tests/README.rst b/tests/README.rst index 6fbf97e65f..0f7cdc00f8 100644 --- a/tests/README.rst +++ b/tests/README.rst @@ -5,4 +5,4 @@ HTTPie Test Suite Please see `CONTRIBUTING`_. -.. _CONTRIBUTING: https://github.com/jakubroztocil/httpie/blob/master/CONTRIBUTING.rst +.. _CONTRIBUTING: https://github.com/jkbrzt/httpie/blob/master/CONTRIBUTING.rst diff --git a/tests/test_auth.py b/tests/test_auth.py index 5a94ad9409..6d7cbb491e 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -52,7 +52,7 @@ def test_credentials_in_url_auth_flag_has_priority(self, httpbin): ]) def test_only_username_in_url(self, url): """ - https://github.com/jakubroztocil/httpie/issues/242 + https://github.com/jkbrzt/httpie/issues/242 """ args = httpie.cli.parser.parse_args(args=[url], env=TestEnvironment()) diff --git a/tests/test_defaults.py b/tests/test_defaults.py index ce3e1d26f4..30039df690 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -42,7 +42,7 @@ class TestAutoContentTypeAndAcceptHeaders: """ def test_GET_no_data_no_auto_headers(self, httpbin): - # https://github.com/jakubroztocil/httpie/issues/62 + # https://github.com/jkbrzt/httpie/issues/62 r = http('GET', httpbin.url + '/headers') assert HTTP_OK in r assert r.json['headers']['Accept'] == '*/*' @@ -73,7 +73,7 @@ def test_POST_explicit_JSON_auto_JSON_accept(self, httpbin): assert HTTP_OK in r assert r.json['headers']['Accept'] == 'application/json' # Make sure Content-Type gets set even with no data. - # https://github.com/jakubroztocil/httpie/issues/137 + # https://github.com/jkbrzt/httpie/issues/137 assert 'application/json' in r.json['headers']['Content-Type'] def test_GET_explicit_JSON_explicit_headers(self, httpbin): diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 92cb193210..6fb47bf61e 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -18,7 +18,7 @@ def test_debug(self): def test_help(self): r = http('--help', error_exit_ok=True) assert r.exit_status == httpie.ExitStatus.OK - assert 'https://github.com/jakubroztocil/httpie/issues' in r + assert 'https://github.com/jkbrzt/httpie/issues' in r def test_version(self): r = http('--version', error_exit_ok=True) diff --git a/tests/test_output.py b/tests/test_output.py index ef97886794..20ea7b41bb 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -13,7 +13,7 @@ def test_verbose(self, httpbin): assert r.count('__test__') == 2 def test_verbose_form(self, httpbin): - # https://github.com/jakubroztocil/httpie/issues/53 + # https://github.com/jkbrzt/httpie/issues/53 r = http('--verbose', '--form', 'POST', httpbin.url + '/post', 'A=B', 'C=D') assert HTTP_OK in r diff --git a/tests/test_regressions.py b/tests/test_regressions.py index b22b140040..3ad441307f 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -7,7 +7,7 @@ def test_Host_header_overwrite(httpbin): """ - https://github.com/jakubroztocil/httpie/issues/235 + https://github.com/jkbrzt/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/jakubroztocil/httpie/issues/252 + https://github.com/jkbrzt/httpie/issues/252 """ http('--output=/dev/null', httpbin + '/get') diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 210f9d954c..6a0d4b60f1 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -138,7 +138,7 @@ def test_session_by_path(self, httpbin): @pytest.mark.skipif( sys.version_info >= (3,), reason="This test fails intermittently on Python 3 - " - "see https://github.com/jakubroztocil/httpie/issues/282") + "see https://github.com/jkbrzt/httpie/issues/282") def test_session_unicode(self, httpbin): self.start_session(httpbin) @@ -159,7 +159,7 @@ def test_session_unicode(self, httpbin): def test_session_default_header_value_overwritten(self, httpbin): self.start_session(httpbin) - # https://github.com/jakubroztocil/httpie/issues/180 + # https://github.com/jkbrzt/httpie/issues/180 r1 = http('--session=test', httpbin.url + '/headers', 'User-Agent:custom', env=self.env()) From bebeb2100d5571e6392c02ff1eaa9b7863da7ee7 Mon Sep 17 00:00:00 2001 From: hoatle Date: Mon, 24 Aug 2015 01:58:00 +0700 Subject: [PATCH 0096/1182] mention httpie-jwt-auth plugin on README --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index b8d3c952f1..b231b9bda1 100644 --- a/README.rst +++ b/README.rst @@ -593,6 +593,7 @@ Auth Plugins * `requests-hawk `_: Hawk * `httpie-api-auth `_: ApiAuth * `httpie-edgegrid `_: EdgeGrid +* `httpie-jwt-auth `_: JWTAuth ======= From 9ea89ffefea114973513c8269a0f3c7c8e46c50a Mon Sep 17 00:00:00 2001 From: Matt Layman Date: Sun, 30 Aug 2015 21:37:47 -0400 Subject: [PATCH 0097/1182] Fix typo in method name of plugin manager. --- httpie/client.py | 2 +- httpie/plugins/manager.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 5f24a049f7..190737d2e3 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -22,7 +22,7 @@ def get_requests_session(): requests_session = requests.Session() - for cls in plugin_manager.get_trasnsport_plugins(): + for cls in plugin_manager.get_transport_plugins(): transport_plugin = cls() requests_session.mount(prefix=transport_plugin.prefix, adapter=transport_plugin.get_adapter()) diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index 2c4092d5c7..239d32ae96 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -60,6 +60,6 @@ def get_converters(self): if issubclass(plugin, ConverterPlugin)] # Adapters - def get_trasnsport_plugins(self): + def get_transport_plugins(self): return [plugin for plugin in self if issubclass(plugin, TransportPlugin)] From d60a04da2ddc51ad169e590c45808d8e56accd81 Mon Sep 17 00:00:00 2001 From: Matt Layman Date: Sun, 30 Aug 2015 21:41:14 -0400 Subject: [PATCH 0098/1182] Add Matt Layman to AUTHORS. --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 0dceb04c23..1d7437d6c6 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -32,3 +32,4 @@ Patches and ideas * `Nathan LaFreniere `_ * `Matthias Lehmann `_ * `Dennis Brakhane `_ +* `Matt Layman `_ From 5fe5958b06c982c311419fcfbe2eb2fe55e44677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Tue, 1 Sep 2015 15:11:36 +0200 Subject: [PATCH 0099/1182] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index b231b9bda1..8a59d6d3ba 100644 --- a/README.rst +++ b/README.rst @@ -593,7 +593,7 @@ Auth Plugins * `requests-hawk `_: Hawk * `httpie-api-auth `_: ApiAuth * `httpie-edgegrid `_: EdgeGrid -* `httpie-jwt-auth `_: JWTAuth +* `httpie-jwt-auth `_: JWTAuth (JSON Web Tokens) ======= From 8eb460a6f3925a6020020bf412ccec7342294a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Fri, 11 Sep 2015 16:24:42 +0200 Subject: [PATCH 0100/1182] Disable OSX travis builds for now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OSX/Python support isn't probably not ready on Travis' side yet. https://travis-ci.org/jkbrzt/httpie/jobs/78219565#L27 // cc @msabramo — any idea? --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e3c02ea7b7..5c44d61161 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ sudo: false os: - linux - - osx + # - osx env: global: - NEWEST_PYTHON=3.4 From aec0f04f5da6786cdb12a5515c96af20c0478835 Mon Sep 17 00:00:00 2001 From: Lukasz Konopski Date: Mon, 21 Sep 2015 16:30:46 +0200 Subject: [PATCH 0101/1182] [#381] --auth fails on windows --- httpie/input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/input.py b/httpie/input.py index da3cc5255f..e57af3596d 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -521,7 +521,7 @@ class AuthCredentials(KeyValue): def _getpass(self, prompt): # To allow mocking. - return getpass.getpass(prompt) + return getpass.getpass(prompt.__str__()) def has_password(self): return self.value is not None From ed484c278bb4434fefe31d1f497f497e3c9567b6 Mon Sep 17 00:00:00 2001 From: honorabrutroll Date: Sun, 4 Oct 2015 17:06:00 -0500 Subject: [PATCH 0102/1182] Change pretty option processor to only raise error when using output file --- httpie/input.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/httpie/input.py b/httpie/input.py index da3cc5255f..4d8af82e2d 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -378,7 +378,8 @@ def _process_pretty_options(self): 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: + 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 From b1cc069fced514112e9ac9bd68400cbbdeb5e979 Mon Sep 17 00:00:00 2001 From: honorabrutroll Date: Sun, 4 Oct 2015 17:06:54 -0500 Subject: [PATCH 0103/1182] Add Edward Yang to AUTHORS.rst --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 1d7437d6c6..7fdf304587 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -33,3 +33,4 @@ Patches and ideas * `Matthias Lehmann `_ * `Dennis Brakhane `_ * `Matt Layman `_ +* `Edward Yang Date: Sun, 4 Oct 2015 17:16:41 -0500 Subject: [PATCH 0104/1182] Fixed AUTHORS.rst --- AUTHORS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index 7fdf304587..684fe8be9c 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -33,4 +33,4 @@ Patches and ideas * `Matthias Lehmann `_ * `Dennis Brakhane `_ * `Matt Layman `_ -* `Edward Yang `_ From 69bd72ce95433e0a6e3942b068828492bbb8ac27 Mon Sep 17 00:00:00 2001 From: Yuri Malheiros Date: Wed, 7 Oct 2015 14:17:53 -0300 Subject: [PATCH 0105/1182] Update README.rst Fix a simple typo --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 8a59d6d3ba..2c68568ebc 100644 --- a/README.rst +++ b/README.rst @@ -895,7 +895,7 @@ Colors and Formatting --------------------- Syntax highlighting is applied to HTTP headers and bodies (where it makes -sense). You can choose your prefered color scheme via the ``--style`` option +sense). You can choose your preferred color scheme via the ``--style`` option if you don't like the default one (see ``$ http --help`` for the possible values). From 277da1ff9388053787e5948b71af0e94fa75d30b Mon Sep 17 00:00:00 2001 From: Lukasz Konopski Date: Wed, 21 Oct 2015 21:57:06 +0200 Subject: [PATCH 0106/1182] str conversion --- httpie/input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/input.py b/httpie/input.py index e57af3596d..1bc9acff2d 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -521,7 +521,7 @@ class AuthCredentials(KeyValue): def _getpass(self, prompt): # To allow mocking. - return getpass.getpass(prompt.__str__()) + return getpass.getpass(str(prompt)) def has_password(self): return self.value is not None From 45df86012480a1f73d909f8f49d177008a4d15dc Mon Sep 17 00:00:00 2001 From: Luis San Martin Date: Thu, 22 Oct 2015 14:32:16 -0300 Subject: [PATCH 0107/1182] PEP8 errors --- httpie/cli.py | 2 +- httpie/input.py | 6 +++--- httpie/utils.py | 1 - setup.py | 6 +++--- tests/fixtures.py | 1 - tests/test_auth.py | 1 - tests/test_docs.py | 6 +++--- tests/test_sessions.py | 19 ++++++++++++------- tests/test_uploads.py | 2 +- 9 files changed, 23 insertions(+), 21 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 2b05a88380..9a4d92acac 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -4,7 +4,7 @@ """ from textwrap import dedent, wrap -#noinspection PyCompatibility +# noinspection PyCompatibility from argparse import (RawDescriptionHelpFormatter, FileType, OPTIONAL, ZERO_OR_MORE, SUPPRESS) diff --git a/httpie/input.py b/httpie/input.py index da3cc5255f..f9e538efd5 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -303,8 +303,8 @@ def _guess_method(self): # 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) + 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 @@ -572,7 +572,7 @@ def __init__(self, *args, **kwargs): else: super(RequestItemsDict, self).__init__(*args, **kwargs) - #noinspection PyMethodOverriding + # noinspection PyMethodOverriding def __setitem__(self, key, value): """ If `key` is assigned more than once, `self[key]` holds a `list` of all the values. diff --git a/httpie/utils.py b/httpie/utils.py index ad2119aad8..821fac9f1f 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -54,4 +54,3 @@ def humanize_bytes(n, precision=2): # noinspection PyUnboundLocalVariable return '%.*f %s' % (precision, n / factor, suffix) - diff --git a/setup.py b/setup.py index cab89c7c06..fc19ccf30e 100644 --- a/setup.py +++ b/setup.py @@ -40,12 +40,12 @@ def run_tests(self): 'Pygments>=1.5' ] -### Conditional dependencies: +# Conditional dependencies: # sdist -if not 'bdist_wheel' in sys.argv: +if 'bdist_wheel' not in sys.argv: try: - #noinspection PyUnresolvedReferences + # noinspection PyUnresolvedReferences import argparse except ImportError: install_requires.append('argparse>=1.2.1') diff --git a/tests/fixtures.py b/tests/fixtures.py index c7b769e67e..05737c7186 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -38,4 +38,3 @@ def patharg(path): BIN_FILE_CONTENT = f.read() UNICODE = FILE_CONTENT - diff --git a/tests/test_auth.py b/tests/test_auth.py index 6d7cbb491e..25006343bf 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -59,4 +59,3 @@ def test_only_username_in_url(self, url): assert args.auth assert args.auth.key == 'username' assert args.auth.value == '' - diff --git a/tests/test_docs.py b/tests/test_docs.py index ed2ad1e9fa..a02f6510a6 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -9,7 +9,7 @@ def has_docutils(): try: - #noinspection PyUnresolvedReferences + # noinspection PyUnresolvedReferences import docutils return True except ImportError: @@ -32,8 +32,8 @@ def rst_filenames(): def test_rst_file_syntax(filename): p = subprocess.Popen( ['rst2pseudoxml.py', '--report=1', '--exit-status=1', filename], - stderr=subprocess.PIPE, - stdout=subprocess.PIPE + stderr=subprocess.PIPE, + stdout=subprocess.PIPE ) err = p.communicate()[1] assert p.returncode == 0, err diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 6a0d4b60f1..966d87b4ea 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -64,17 +64,20 @@ def test_session_created_and_reused(self, httpbin): def test_session_update(self, httpbin): self.start_session(httpbin) # Get a response to a request from the original session. - r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) + r2 = http('--session=test', 'GET', httpbin.url + '/get', + env=self.env()) assert HTTP_OK in r2 # Make a request modifying the session data. r3 = http('--follow', '--session=test', '--auth=username:password2', - 'GET', httpbin.url + '/cookies/set?hello=world2', 'Hello:World2', + 'GET', httpbin.url + '/cookies/set?hello=world2', + 'Hello:World2', env=self.env()) assert HTTP_OK in r3 # Get a response to a request from the updated session. - r4 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) + r4 = http('--session=test', 'GET', httpbin.url + '/get', + env=self.env()) assert HTTP_OK in r4 assert r4.json['headers']['Hello'] == 'World2' assert r4.json['headers']['Cookie'] == 'hello=world2' @@ -84,7 +87,8 @@ def test_session_update(self, httpbin): def test_session_read_only(self, httpbin): self.start_session(httpbin) # Get a response from the original session. - r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) + r2 = http('--session=test', 'GET', httpbin.url + '/get', + env=self.env()) assert HTTP_OK in r2 # Make a request modifying the session data but @@ -96,7 +100,8 @@ def test_session_read_only(self, httpbin): assert HTTP_OK in r3 # Get a response from the updated session. - r4 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) + r4 = http('--session=test', 'GET', httpbin.url + '/get', + env=self.env()) assert HTTP_OK in r4 # Origin can differ on Travis. @@ -117,8 +122,8 @@ def test_session_ignored_header_prefixes(self, httpbin): 'If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT', env=self.env()) assert HTTP_OK in r1 - - r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) + r2 = http('--session=test', 'GET', httpbin.url + '/get', + env=self.env()) assert HTTP_OK in r2 assert no_content_type(r2.json['headers']) assert 'If-Unmodified-Since' not in r2.json['headers'] diff --git a/tests/test_uploads.py b/tests/test_uploads.py index e97bdafb9f..0bf8457e3a 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -30,7 +30,7 @@ def test_upload_multiple_fields_with_the_same_name(self, httpbin): 'test-file@%s' % FILE_PATH_ARG) assert HTTP_OK in r assert r.count('Content-Disposition: form-data; name="test-file";' - ' filename="%s"' % os.path.basename(FILE_PATH)) == 2 + ' filename="%s"' % os.path.basename(FILE_PATH)) == 2 # Should be 4, but is 3 because httpbin # doesn't seem to support filed field lists assert r.count(FILE_CONTENT) in [3, 4] From 6259b5dd3bf52ff0d008a1b19de489389e60d297 Mon Sep 17 00:00:00 2001 From: Lucas Garron Date: Wed, 28 Oct 2015 15:06:04 -0700 Subject: [PATCH 0108/1182] Add a --default-scheme argument. --- httpie/cli.py | 10 ++++++++++ httpie/input.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/httpie/cli.py b/httpie/cli.py index 2b05a88380..47ee4c544e 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -88,6 +88,7 @@ def _split_lines(self, text, width): metavar='URL', help=""" The scheme defaults to 'http://' if the URL does not include one. + (You can override this with: --default-scheme https) You can also use a shorthand for localhost @@ -558,6 +559,15 @@ def _split_lines(self, text, width): """ ) +troubleshooting.add_argument( + '--default-scheme', + choices=["http", "https"], + default="http", + help=""" + Default scheme to use if not specified in the URL. + + """ +) troubleshooting.add_argument( '--debug', action='store_true', diff --git a/httpie/input.py b/httpie/input.py index da3cc5255f..ecddc5a43f 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -137,7 +137,7 @@ def parse_args(self, env, args=None, namespace=None): if not self.args.ignore_stdin and not env.stdin_isatty: self._body_from_file(self.env.stdin) if not URL_SCHEME_RE.match(self.args.url): - scheme = HTTP + scheme = self.args.default_scheme + "://" # See if we're using curl style shorthand for localhost (:3000/foo) shorthand = re.match(r'^:(?!:)(\d*)(/?.*)$', self.args.url) From 21ee981fc6bb61c95aa01345b2eefea15655bfdc Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 27 Nov 2015 15:02:23 +0100 Subject: [PATCH 0109/1182] Fix typo in CONTRIBUTING.rst --- CONTRIBUTING.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index b5052b310e..01143337bf 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,7 +1,7 @@ Contributing to HTTPie ###################### -Bug reports and code and documentation patches are greatly appretiated. You can +Bug reports and code and documentation patches are greatly appreciated. You can also help by using the development version of HTTPie and reporting any bugs you might encounter. From 4f755a8bdec9c715d06ce47b46c9a878194d563c Mon Sep 17 00:00:00 2001 From: Michael Floering Date: Wed, 2 Dec 2015 11:50:48 -0600 Subject: [PATCH 0110/1182] Fail gracefully if disable_warnings not available Addresses #418. Rationale explained there. --- httpie/client.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 190737d2e3..d55ce62c90 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -11,8 +11,14 @@ from httpie.plugins import plugin_manager -# https://urllib3.readthedocs.org/en/latest/security.html -urllib3.disable_warnings() +try: + # https://urllib3.readthedocs.org/en/latest/security.html + urllib3.disable_warnings() +except 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. They may get some noisy output but execution shouldn't die. Move on + pass FORM = 'application/x-www-form-urlencoded; charset=utf-8' From fad84a962e3831c6a1f9b902e079d17192a75610 Mon Sep 17 00:00:00 2001 From: Alastair McGowan-Douglas Date: Tue, 15 Dec 2015 14:39:26 +0000 Subject: [PATCH 0111/1182] Aitch already has an official spelling - use it http://www.oxforddictionaries.com/definition/english/aitch --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 2c68568ebc..36a1a84d8d 100644 --- a/README.rst +++ b/README.rst @@ -2,9 +2,9 @@ HTTPie: a CLI, cURL-like tool for humans **************************************** -HTTPie (pronounced *aych-tee-tee-pie*) is a **command line HTTP client**. Its -goal is to make CLI interaction with web services as **human-friendly** as -possible. It provides a simple ``http`` command that allows for sending +HTTPie (pronounced *aitch-tee-tee-pie*) is a **command line HTTP client**. +Its goal is to make CLI interaction with web services as **human-friendly** +as possible. It provides a simple ``http`` command that allows for sending arbitrary HTTP requests using a simple and natural syntax, and displays colorized output. HTTPie can be used for **testing, debugging**, and generally **interacting** with HTTP servers. From cc0ba032908efeaefea47300cce0596f69229ab6 Mon Sep 17 00:00:00 2001 From: Tim Martin Date: Mon, 28 Dec 2015 10:28:04 -0600 Subject: [PATCH 0112/1182] Remove duplicate setup.py test option --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index cab89c7c06..840517b2cc 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,6 @@ class PyTest(TestCommand): # and runs the tests with no fancy stuff like parallel execution. def finalize_options(self): TestCommand.finalize_options(self) - self.test_suite = True self.test_args = [ '--doctest-modules', '--verbose', './httpie', './tests' From 288cb4fdeb3823155ac084b9b988c82b2f1f81e3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jan 2016 18:26:42 -0300 Subject: [PATCH 0113/1182] Fix "mock requires setuptools>=17.1. Aborting installation" on Win+Py3 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 840517b2cc..2f77791c6d 100644 --- a/setup.py +++ b/setup.py @@ -28,6 +28,7 @@ def run_tests(self): tests_require = [ # Pytest needs to come last. # https://bitbucket.org/pypa/setuptools/issue/196/ + 'setuptools>=17.1', # Fix 'mock requires setuptools>=17.1' on Win+Py3 'pytest-httpbin', 'pytest', 'mock', From ab3d2656afaedc7b015daeba15a7775f5ba8481f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jan 2016 18:34:13 -0300 Subject: [PATCH 0114/1182] Undo 'Fix "mock requires setuptools>=17.1. Aborting installation" on Win+Py3' --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 7093dd556d..9af190804c 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,6 @@ def run_tests(self): tests_require = [ # Pytest needs to come last. # https://bitbucket.org/pypa/setuptools/issue/196/ - 'setuptools>=17.1', # Fix 'mock requires setuptools>=17.1' on Win+Py3 'pytest-httpbin', 'pytest', 'mock', From b034c8703abcde4a655474bba94799162957e822 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jan 2016 18:41:58 -0300 Subject: [PATCH 0115/1182] PEP8 --- httpie/client.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index d55ce62c90..1115f4dd98 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -15,9 +15,10 @@ # https://urllib3.readthedocs.org/en/latest/security.html urllib3.disable_warnings() except 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. They may get some noisy output but execution shouldn't die. Move on + # 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. + # They may get some noisy output but execution shouldn't die. Move on. pass From 4e2b6b0cccbff2b7cbe61e26675cd6bd917bd936 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jan 2016 18:46:01 -0300 Subject: [PATCH 0116/1182] Update get-pip.py URL --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1e73b258e0..25f499a765 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,7 @@ init: - "ECHO %PYTHON%" - ps: "ls C:/Python*" install: - - ps: (new-object net.webclient).DownloadFile('https://raw.github.com/pypa/pip/master/contrib/get-pip.py', 'C:/get-pip.py') + - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') - "%PYTHON%/python.exe C:/get-pip.py" - "%PYTHON%/Scripts/pip.exe install -e ." test_script: From 33489c9a91bb3e9477a09d66ed2b72e177ed1070 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jan 2016 18:51:17 -0300 Subject: [PATCH 0117/1182] Update pip on Appveyor --- appveyor.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 25f499a765..d5525006a0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,8 +8,9 @@ init: - "ECHO %PYTHON%" - ps: "ls C:/Python*" install: - - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') - - "%PYTHON%/python.exe C:/get-pip.py" +# - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') +# - "%PYTHON%/python.exe C:/get-pip.py" + - "%PYTHON%/Scripts/pip.exe install -U pip" - "%PYTHON%/Scripts/pip.exe install -e ." test_script: - "%PYTHON%/Scripts/pip.exe --version" From c3e5456aba4f007cdcc404079b18b5c9722aaafd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jan 2016 19:01:39 -0300 Subject: [PATCH 0118/1182] Update setuptools on Appveyor --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index d5525006a0..f7067b89de 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,7 +10,7 @@ init: install: # - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') # - "%PYTHON%/python.exe C:/get-pip.py" - - "%PYTHON%/Scripts/pip.exe install -U pip" + - "%PYTHON%/Scripts/pip.exe install -U pip setuptools" - "%PYTHON%/Scripts/pip.exe install -e ." test_script: - "%PYTHON%/Scripts/pip.exe --version" From 4cadc1d4c0f2314a32e71a8df86a33c11162647b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jan 2016 19:08:27 -0300 Subject: [PATCH 0119/1182] Update pytest configuration * Move it from tox.ini to pytest.ini * Ignore tests/fixtures --- pytest.ini | 2 ++ tox.ini | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 pytest.ini diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000000..a778500518 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +addopts = --tb=native +norecursedirs = tests/fixtures diff --git a/tox.ini b/tox.ini index 600ba3f118..6cab5b9572 100644 --- a/tox.ini +++ b/tox.ini @@ -16,6 +16,3 @@ deps = commands = py.test --verbose --doctest-modules --basetemp={envtmpdir} {posargs:./tests ./httpie} - -[pytest] -addopts = --tb=native From f14a0ad37d19fc2f93544f6d21592474d46b0520 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jan 2016 19:11:22 -0300 Subject: [PATCH 0120/1182] Fix pytest configuration --- pytest.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/pytest.ini b/pytest.ini index a778500518..9735e58195 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,2 +1,3 @@ +[pytest] addopts = --tb=native norecursedirs = tests/fixtures From 47220763357f5a25cc535af5c4d2f4f092fb9abd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jan 2016 19:27:07 -0300 Subject: [PATCH 0121/1182] v0.9.3 --- CHANGELOG.rst | 11 ++++++++--- httpie/__init__.py | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5730923227..96e112587d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,12 +6,16 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. -`1.0.0-dev`_ (Unreleased) +`0.9.3`_ (2016-01-01) ------------------------- * Changed the default color ``--style`` from ``solarized`` to ``monokai`` -* Added Bash auto complete support +* Added basic Bash autocomplete support (need to be installed manually) * Added request details to connection error messages +* Fixed ``'requests.packages.urllib3' has no attribute 'disable_warnings'`` + errors that occurred in some installations +* Fixed colors and formatting on Windows +* Fixed ``--auth`` prompt on Windows `0.9.2`_ (2015-02-24) @@ -252,4 +256,5 @@ This project adheres to `Semantic Versioning `_. .. _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 -.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.2...master +.. _0.9.3: https://github.com/jkbrzt/httpie/compare/0.9.2...0.9.3 +.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.3...master diff --git a/httpie/__init__.py b/httpie/__init__.py index 7ae07c9ee2..81e580ea67 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '1.0.0-dev' +__version__ = '0.9.3' __licence__ = 'BSD' From 34c6958dc852106f82186a29dd8e045d2987783d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jan 2016 19:38:21 -0300 Subject: [PATCH 0122/1182] 1.0.0-dev --- CHANGELOG.rst | 3 +++ httpie/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 96e112587d..961f037574 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,9 @@ Change Log This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. +`1.0.0-dev`_ (Unreleased) +------------------------- + `0.9.3`_ (2016-01-01) ------------------------- diff --git a/httpie/__init__.py b/httpie/__init__.py index 81e580ea67..7ae07c9ee2 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '0.9.3' +__version__ = '1.0.0-dev' __licence__ = 'BSD' From 84b81c00eaf47d608aa59d919557622fdeb31978 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jan 2016 14:07:00 -0300 Subject: [PATCH 0123/1182] Fixed tox.ini and improved tests and CONTRIBUTING.txt --- CONTRIBUTING.rst | 70 +++++++++++++++++++++++++++++------------------- Makefile | 8 +++++- httpie/config.py | 4 +-- tests/utils.py | 4 +-- tox.ini | 16 ++++++----- 5 files changed, 64 insertions(+), 38 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 01143337bf..3ffea06313 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,12 +1,13 @@ +###################### Contributing to HTTPie ###################### -Bug reports and code and documentation patches are greatly appreciated. You can -also help by using the development version of HTTPie and reporting any bugs you -might encounter. +Bug reports and code and documentation patches are welcome. You can +help this project also by using the development version of HTTPie +and by reporting any bugs you might encounter. -Bug Reports -=========== +1. Reporting bugs +================= **It's important that you provide the full command argument list as well as the output of the failing command.** @@ -15,12 +16,12 @@ to your bug report, e.g.: .. code-block:: bash - $ http --debug [arguments that trigger the error] - [complete output] + $ http --debug [COMPLETE ARGUMENT LIST THAT TRIGGERS THE ERROR] + [COMPLETE OUTPUT] -Contributing Code and Documentation -=================================== +2. Contributing Code and Docs +============================= 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 @@ -28,8 +29,11 @@ is a bigger one, it's always good to discuss before your starting working on it. -Development Environment ------------------------ +Creating Development Environment +-------------------------------- + +Go to https://github.com/jkbrzt/httpie and fork the project repository. + .. code-block:: bash @@ -52,44 +56,56 @@ Making Changes Please make sure your changes conform to `Style Guide for Python Code`_ (PEP8). -Tests ------ +Testing +------- Before opening a pull requests, please make sure the `test suite`_ passes -in all of the `supported Python environments`_. You should also **add tests -for any new features and bug fixes**. +in all of the `supported Python environments`_. You should also add tests +for any new features and bug fixes. -HTTPie uses `pytest`_ and `Tox`_. +HTTPie uses `pytest`_ and `Tox`_ for testing. -.. code-block:: bash - ### Running all tests: +Running all tests: +****************** + +.. code-block:: bash - # Current Python + # Run all tests on the current Python interpreter make test - # Current Python with coverage + # Run all tests on the current Python with coverage make test-cover - # All the supported and available Pythons via Tox + # Run all tests in all of the supported and available Pythons via Tox make test-tox - ### Running specific tests: - # Current Python - pytest tests/test_uploads.py +Running specific tests: +*********************** + +.. code-block:: bash + + # Run specific tests on the current Python + py.test tests/test_uploads.py + py.test tests/test_uploads.py::TestMultipartFormDataFileUpload + py.test tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok - # All Pythons + # Run specific tests on the on all Pythons via Tox tox -- tests/test_uploads.py --verbose + tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload --verbose + tox -- tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok --verbose + +----- -Don't forget to add yourself to `AUTHORS.rst`_. +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.rst: https://github.com/jkbrzt/httpie/blob/master/AUTHORS.rst +.. _AUTHORS: https://github.com/jkbrzt/httpie/blob/master/AUTHORS.rst .. _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 diff --git a/Makefile b/Makefile index 26b650838d..54f1ede657 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,7 @@ +# +# See ./CONTRIBUTING.rst +# + VERSION=$(shell grep __version__ httpie/__init__.py) REQUIREMENTS="requirements-dev.txt" TAG="\n\n\033[0;32m\#\#\# " @@ -7,6 +11,8 @@ all: test uninstall-httpie: @echo $(TAG)Removing existing installation of HTTPie$(END) + @echo "(NOTE: uninstall httpie manually if this fails)" + @echo - pip uninstall --yes httpie >/dev/null ! which http @echo @@ -22,7 +28,7 @@ init: uninstall-httpie @echo test: init - @echo $(TAG)Running tests in on current Python with coverage $(END) + @echo $(TAG)Running tests on the current Python interpreter with coverage $(END) py.test --cov ./httpie --cov ./tests --doctest-modules --verbose ./httpie ./tests @echo diff --git a/httpie/config.py b/httpie/config.py index 9f28da175f..64f72b2b0f 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -6,11 +6,11 @@ from httpie.compat import is_windows -DEFAULT_CONFIG_DIR = os.environ.get( +DEFAULT_CONFIG_DIR = str(os.environ.get( 'HTTPIE_CONFIG_DIR', os.path.expanduser('~/.httpie') if not is_windows else os.path.expandvars(r'%APPDATA%\\httpie') -) +)) class BaseConfigDict(dict): diff --git a/tests/utils.py b/tests/utils.py index aad27395cd..5efdd011bb 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -53,7 +53,7 @@ class TestEnvironment(Environment): stdout_isatty = True is_windows = False - _shutil = shutil # needed by __del__ (would get gc'd) + _shutil_rmtree = shutil.rmtree # needed by __del__ (would get gc'd) def __init__(self, **kwargs): @@ -72,7 +72,7 @@ def __init__(self, **kwargs): def __del__(self): if self.delete_config_dir: - self._shutil.rmtree(self.config_dir) + self._shutil_rmtree(self.config_dir) def http(*args, **kwargs): diff --git a/tox.ini b/tox.ini index 6cab5b9572..f746660f28 100644 --- a/tox.ini +++ b/tox.ini @@ -1,18 +1,22 @@ # Tox (http://tox.testrun.org/) is a tool for running tests -# in multiple virtualenvs. -# Run: -# $ pip install -r requirements-dev.txt -# $ tox +# in multiple virtualenvs. See ./CONTRIBUTING.rst [tox] -envlist = py26, py27, py34, pypy +envlist = py26, py27, py35, pypy [testenv] deps = + mock pytest pytest-httpbin>=0.0.6 + commands = - py.test --verbose --doctest-modules --basetemp={envtmpdir} {posargs:./tests ./httpie} + # NOTE: the order of the directories in posargs seems to matter. + # When changed, then many ImportMismatchError exceptions occurrs. + py.test \ + --verbose \ + --doctest-modules \ + {posargs:./httpie ./tests} From c82c9f0ae4317bcc2b9210b0fd61fb16d7a4041e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jan 2016 14:28:46 -0300 Subject: [PATCH 0124/1182] Makefile improvements --- CONTRIBUTING.rst | 5 +++++ Makefile | 14 ++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 3ffea06313..ca57350de4 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -80,6 +80,9 @@ Running all tests: # 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 + Running specific tests: *********************** @@ -99,6 +102,7 @@ Running specific tests: ----- +See `Makefile`_ for additional development utilities. Don't forget to add yourself to `AUTHORS`_! @@ -106,6 +110,7 @@ Don't forget to add yourself to `AUTHORS`_! .. _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 .. _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 diff --git a/Makefile b/Makefile index 54f1ede657..ce47d6e53c 100644 --- a/Makefile +++ b/Makefile @@ -10,14 +10,20 @@ END=" \#\#\# \033[0m\n" all: test uninstall-httpie: - @echo $(TAG)Removing existing installation of HTTPie$(END) - @echo "(NOTE: uninstall httpie manually if this fails)" + @echo $(TAG)Uninstalling httpie$(END) @echo - - pip uninstall --yes httpie >/dev/null - ! which http + - pip uninstall --yes httpie &2>/dev/null + @echo "Verifying…" + cd .. && ! python -m httpie --version &2>/dev/null + @echo "Done" @echo uninstall-all: uninstall-httpie + + @echo $(TAG)Uninstalling httpie requirements$(END) + - pip uninstall --yes pygments requests + + @echo $(TAG)Uninstalling development requirements$(END) - pip uninstall --yes -r $(REQUIREMENTS) init: uninstall-httpie From c6690e0182ac924e30a7c4800686f26a0aa7e5ad Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jan 2016 14:33:48 -0300 Subject: [PATCH 0125/1182] Makefile improvements --- Makefile | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index ce47d6e53c..89e0342e8a 100644 --- a/Makefile +++ b/Makefile @@ -7,45 +7,36 @@ REQUIREMENTS="requirements-dev.txt" TAG="\n\n\033[0;32m\#\#\# " END=" \#\#\# \033[0m\n" -all: test - -uninstall-httpie: - @echo $(TAG)Uninstalling httpie$(END) - @echo - - pip uninstall --yes httpie &2>/dev/null - @echo "Verifying…" - cd .. && ! python -m httpie --version &2>/dev/null - @echo "Done" - @echo - -uninstall-all: uninstall-httpie - @echo $(TAG)Uninstalling httpie requirements$(END) - - pip uninstall --yes pygments requests +all: test - @echo $(TAG)Uninstalling development requirements$(END) - - pip uninstall --yes -r $(REQUIREMENTS) init: uninstall-httpie @echo $(TAG)Installing dev requirements$(END) pip install --upgrade -r $(REQUIREMENTS) + @echo $(TAG)Installing HTTPie$(END) pip install --upgrade --editable . + @echo + test: init @echo $(TAG)Running tests on the current Python interpreter with coverage $(END) py.test --cov ./httpie --cov ./tests --doctest-modules --verbose ./httpie ./tests @echo + test-tox: init @echo $(TAG)Running tests on all Pythons via Tox$(END) tox @echo + test-dist: test-sdist test-bdist-wheel @echo + test-sdist: clean uninstall-httpie @echo $(TAG)Testing sdist build an installation$(END) python setup.py sdist @@ -53,6 +44,7 @@ test-sdist: clean uninstall-httpie which http @echo + test-bdist-wheel: clean uninstall-httpie @echo $(TAG)Testing wheel build an installation$(END) python setup.py bdist_wheel @@ -60,9 +52,11 @@ test-bdist-wheel: clean uninstall-httpie which http @echo + # This tests everything, even this Makefile. test-all: uninstall-all clean init test test-tox test-dist + publish: test-all @echo $(TAG)Testing wheel build an installation$(END) @echo "$(VERSION)" @@ -72,8 +66,29 @@ publish: test-all python setup.py bdist_wheel upload @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 + + +uninstall-httpie: + @echo $(TAG)Uninstalling httpie$(END) + - pip uninstall --yes httpie &2>/dev/null + + @echo "Verifying…" + cd .. && ! python -m httpie --version &2>/dev/null + + @echo "Done" + @echo + + +uninstall-all: uninstall-httpie + + @echo $(TAG)Uninstalling httpie requirements$(END) + - pip uninstall --yes pygments requests + + @echo $(TAG)Uninstalling development requirements$(END) + - pip uninstall --yes -r $(REQUIREMENTS) From ea7654215088cc0cf09fa73bae04b3353f357437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Fri, 15 Jan 2016 14:07:41 -0300 Subject: [PATCH 0126/1182] Added guardian/httpie-hmac-auth --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 36a1a84d8d..9e271d83d4 100644 --- a/README.rst +++ b/README.rst @@ -588,6 +588,7 @@ Auth Plugins ------------ * `httpie-oauth `_: OAuth +* `httpie-hmac-auth `_: HMAC * `httpie-ntlm `_: NTLM (NT LAN Manager) * `httpie-negotiate `_: SPNEGO (GSS Negotiate) * `requests-hawk `_: Hawk From a6a79e92e42cf09b1c873e78cf77ba6723f20d36 Mon Sep 17 00:00:00 2001 From: Prayag Verma Date: Mon, 18 Jan 2016 11:20:24 +0530 Subject: [PATCH 0127/1182] Update license year range to 2016 --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index e3b1fc8256..b84d413a10 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright © 2012-2015 Jakub Roztocil +Copyright © 2012-2016 Jakub Roztocil Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From ac69d4311b51abd7905430dc669bbae3530286fe Mon Sep 17 00:00:00 2001 From: Michael Floering Date: Fri, 22 Jan 2016 18:37:30 -0600 Subject: [PATCH 0128/1182] add `-A` as short arg for `--auth-type` Addresses #430 comes with unit test --- httpie/cli.py | 2 +- tests/test_auth.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 2b05a88380..24e8d77a31 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -397,7 +397,7 @@ def _split_lines(self, text, width): _auth_plugins = plugin_manager.get_auth_plugins() auth.add_argument( - '--auth-type', + '--auth-type', '-A', choices=[plugin.auth_type for plugin in _auth_plugins], default=_auth_plugins[0].auth_type, help=""" diff --git a/tests/test_auth.py b/tests/test_auth.py index 6d7cbb491e..926a790031 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -14,11 +14,12 @@ def test_basic_auth(self, httpbin): assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} + @pytest.mark.parametrize('argument_name', ['--auth-type', '-A']) @pytest.mark.skipif( requests.__version__ == '0.13.6', reason='Redirects with prefetch=False are broken in Requests 0.13.6') - def test_digest_auth(self, httpbin): - r = http('--auth-type=digest', '--auth=user:password', + def test_digest_auth(self, httpbin, argument_name): + r = http('{}=digest'.format(argument_name), '--auth=user:password', 'GET', httpbin.url + '/digest-auth/auth/user/password') assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} From deb7b747ccf04f7326828f581232abef0a28d6fa Mon Sep 17 00:00:00 2001 From: Michael Floering Date: Fri, 22 Jan 2016 18:46:01 -0600 Subject: [PATCH 0129/1182] Small fix for Python 2.6 compatibility. Relates to #430 / #432. --- tests/test_auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index a33211c244..cb53ba82b4 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -19,7 +19,7 @@ def test_basic_auth(self, httpbin): requests.__version__ == '0.13.6', reason='Redirects with prefetch=False are broken in Requests 0.13.6') def test_digest_auth(self, httpbin, argument_name): - r = http('{}=digest'.format(argument_name), '--auth=user:password', + r = http(argument_name + '=digest', '--auth=user:password', 'GET', httpbin.url + '/digest-auth/auth/user/password') assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} From 274dddfb457679283dd71fa3e56394d1cc6f6e99 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 17 Feb 2016 14:46:35 +0800 Subject: [PATCH 0130/1182] Changed the default color style back to solarized Closes #440 --- CHANGELOG.rst | 3 +++ httpie/output/formatters/colors.py | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 961f037574..abd8ebdb8d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,9 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (Unreleased) ------------------------- +* Changed the default color style back to``solarized`` as it supports + both the light and dark terminal background mode. + `0.9.3`_ (2016-01-01) ------------------------- diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 65a57d7bc5..6ee3964b78 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -14,7 +14,7 @@ # great and fruity seems to give the best result there. AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys()) AVAILABLE_STYLES.add('solarized') -DEFAULT_STYLE = 'monokai' +DEFAULT_STYLE = 'solarized' class ColorFormatter(FormatterPlugin): @@ -143,8 +143,6 @@ class HTTPLexer(pygments.lexer.RegexLexer): } -# TODO: As Solarized is not the default theme any longer, it should be removed -# or bundled directly with Pygments so that we don't need to support it. class Solarized256Style(pygments.style.Style): """ solarized256 From d32d6f29a9485f811dc80c9673fe0d80cc8db81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Wed, 17 Feb 2016 14:53:00 +0800 Subject: [PATCH 0131/1182] Typo --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index abd8ebdb8d..856364d4f4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,7 +8,7 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (Unreleased) ------------------------- -* Changed the default color style back to``solarized`` as it supports +* Changed the default color style back to ``solarized`` as it supports both the light and dark terminal background mode. From 59e22b16b89755cc45d482b23a6308b6b90e72e3 Mon Sep 17 00:00:00 2001 From: Marcin Szewczyk Date: Sat, 24 Oct 2015 18:16:17 +0200 Subject: [PATCH 0132/1182] When possible, guess the content-type of the file being sent Refined PR #285 by rasky to pass all tests --- httpie/input.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/httpie/input.py b/httpie/input.py index 076987014a..b0fbd77234 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -336,17 +336,14 @@ def _parse_items(self): 'Invalid file fields (perhaps you meant --form?): %s' % ','.join(file_fields)) - fn, fd = self.args.files[''] + fn, fd, ct = self.args.files[''] self.args.files = {} self._body_from_file(fd) if 'Content-Type' not in self.args.headers: - mime, encoding = mimetypes.guess_type(fn, strict=False) - if mime: - content_type = mime - if encoding: - content_type = '%s; charset=%s' % (mime, encoding) + content_type = get_content_type(fn) + if content_type: self.args.headers['Content-Type'] = content_type def _process_output_options(self): @@ -608,6 +605,16 @@ def items(self): RequestItems = namedtuple('RequestItems', ['headers', 'data', 'files', 'params']) +def get_content_type(filename): + """Get content type for a filename in format appropriate for Content-Type + headers. + """ + mime, encoding = mimetypes.guess_type(filename, strict=False) + if mime: + content_type = mime + if encoding: + content_type = '%s; charset=%s' % (mime, encoding) + return content_type def parse_items(items, headers_class=CaseInsensitiveDict, @@ -634,7 +641,8 @@ def parse_items(items, try: with open(os.path.expanduser(value), 'rb') as f: value = (os.path.basename(value), - BytesIO(f.read())) + BytesIO(f.read()), + get_content_type(value)) except IOError as e: raise ParseError('"%s": %s' % (item.orig, e)) target = files From 56f498c1531fc6cfb277911c67ac436e13752286 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 15:45:45 +0800 Subject: [PATCH 0133/1182] Detect Content Type of file uploaded in multipart/form-data request Closes #271 #285 #398 This adds filename-based detection. It's still not possible to specify the content type manually, though. --- .gitignore | 1 + CHANGELOG.rst | 3 ++- httpie/input.py | 9 +++++++-- tests/test_uploads.py | 2 ++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index c585625650..3bdb64f390 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ README.html htmlcov .idea .DS_Store +.cache/ diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 856364d4f4..006a35c544 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,7 +8,8 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (Unreleased) ------------------------- -* Changed the default color style back to ``solarized`` as it supports +* Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests. +* Changed the default color style back to``solarized`` as it supports both the light and dark terminal background mode. diff --git a/httpie/input.py b/httpie/input.py index b0fbd77234..6e259bbece 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -605,9 +605,13 @@ def items(self): RequestItems = namedtuple('RequestItems', ['headers', 'data', 'files', 'params']) + def get_content_type(filename): - """Get content type for a filename in format appropriate for Content-Type - headers. + """ + Return the content type for ``filename`` in format appropriate + for Content-Type headers, or ``None`` if the file type is unknown + to ``mimetypes``. + """ mime, encoding = mimetypes.guess_type(filename, strict=False) if mime: @@ -616,6 +620,7 @@ def get_content_type(filename): content_type = '%s; charset=%s' % (mime, encoding) return content_type + def parse_items(items, headers_class=CaseInsensitiveDict, data_class=OrderedDict, diff --git a/tests/test_uploads.py b/tests/test_uploads.py index 0bf8457e3a..5cbe2caba2 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -23,6 +23,7 @@ def test_upload_ok(self, httpbin): ' filename="%s"' % os.path.basename(FILE_PATH) in r assert FILE_CONTENT in r assert '"foo": "bar"' in r + assert 'Content-Type: text/plain' in r def test_upload_multiple_fields_with_the_same_name(self, httpbin): r = http('--form', '--verbose', 'POST', httpbin.url + '/post', @@ -34,6 +35,7 @@ def test_upload_multiple_fields_with_the_same_name(self, httpbin): # Should be 4, but is 3 because httpbin # doesn't seem to support filed field lists assert r.count(FILE_CONTENT) in [3, 4] + assert r.count('Content-Type: text/plain') == 2 class TestRequestBodyFromFilePath: From c2f8c36952bc1697cf989acec49a61b606c585a8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 16:19:18 +0800 Subject: [PATCH 0134/1182] Updated download example URLs --- README.rst | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/README.rst b/README.rst index 9e271d83d4..97ca016b49 100644 --- a/README.rst +++ b/README.rst @@ -2,8 +2,8 @@ HTTPie: a CLI, cURL-like tool for humans **************************************** -HTTPie (pronounced *aitch-tee-tee-pie*) is a **command line HTTP client**. -Its goal is to make CLI interaction with web services as **human-friendly** +HTTPie (pronounced *aitch-tee-tee-pie*) is a **command line HTTP client**. +Its goal is to make CLI interaction with web services as **human-friendly** as possible. It provides a simple ``http`` command that allows for sending arbitrary HTTP requests using a simple and natural syntax, and displays colorized output. HTTPie can be used for **testing, debugging**, and @@ -1010,20 +1010,17 @@ is being saved to a file. .. code-block:: bash - $ http --download https://github.com/jkbrzt/httpie/tarball/master + $ http --download https://github.com/jkbrzt/httpie/archive/master.tar.gz .. code-block:: http HTTP/1.1 200 OK - Connection: keep-alive - Content-Disposition: attachment; filename=jkbrzt-httpie-0.4.1-33-gfc4f70a.tar.gz - Content-Length: 505530 + Content-Disposition: attachment; filename=httpie-master.tar.gz + Content-Length: 257336 Content-Type: application/x-gzip - Server: GitHub.com - Vary: Accept-Encoding - Downloading 494.89 kB to "jkbrzt-httpie-0.4.1-33-gfc4f70a.tar.gz" - / 21.01% 104.00 kB 47.55 kB/s 0:00:08 ETA + Downloading 251.30 kB to "httpie-master.tar.gz" + Done. 251.30 kB in 2.73862s (91.76 kB/s) If not provided via ``--output, -o``, the output filename will be determined @@ -1036,7 +1033,7 @@ headers and progress are still shown in the terminal: .. code-block:: bash - $ http -d https://github.com/jkbrzt/httpie/tarball/master | tar zxf - + $ http -d https://github.com/jkbrzt/httpie/archive/master.tar.gz | tar zxf - If ``--output, -o`` is specified, you can resume a partial download using the From df193a373ff8f230457e5f194e38adc488c84551 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 16:20:19 +0800 Subject: [PATCH 0135/1182] Updated tarball URL --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 97ca016b49..7fd06d543a 100644 --- a/README.rst +++ b/README.rst @@ -106,7 +106,7 @@ The **latest development version** can be installed directly from GitHub: $ brew install httpie --HEAD # Universal - $ pip install --upgrade https://github.com/jkbrzt/httpie/tarball/master + $ pip install --upgrade https://github.com/jkbrzt/httpie/archive/master.tar.gz From 10da7b63a354b3573e227a61037160e12ad12965 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 16:54:33 +0800 Subject: [PATCH 0136/1182] Mention MacPorts installation method Closes #395 --- README.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 7fd06d543a..95cc00a474 100644 --- a/README.rst +++ b/README.rst @@ -59,13 +59,21 @@ Installation ============ -On **Mac OS X**, HTTPie can be installed via `Homebrew `_: +On **Mac OS X**, HTTPie can be installed via `Homebrew `_ +(recommended): .. code-block:: bash $ brew install httpie +A MacPorts *port* is also available: + +.. code-block:: bash + + $ port install httpie + + Most **Linux** distributions provide a package that can be installed using the system package manager, e.g.: From 8c33e5e3d31d3cd6476c4d9bc963a4c529f883d2 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 19:01:54 +0800 Subject: [PATCH 0137/1182] Parser => HTTPieArgumentParser --- httpie/cli.py | 9 ++++++--- httpie/input.py | 8 ++++---- tests/test_cli.py | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 9a4d92acac..5723532fe0 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -13,7 +13,8 @@ from httpie.plugins import plugin_manager from httpie.sessions import DEFAULT_SESSIONS_DIR from httpie.output.formatters.colors import AVAILABLE_STYLES, DEFAULT_STYLE -from httpie.input import (Parser, AuthCredentialsArgType, KeyValueArgType, +from httpie.input import (HTTPieArgumentParser, + AuthCredentialsArgType, KeyValueArgType, SEP_PROXY, SEP_CREDENTIALS, SEP_GROUP_ALL_ITEMS, OUT_REQ_HEAD, OUT_REQ_BODY, OUT_RESP_HEAD, OUT_RESP_BODY, OUTPUT_OPTIONS, @@ -40,7 +41,7 @@ def _split_lines(self, text, width): text = dedent(text).strip() + '\n\n' return text.splitlines() -parser = Parser( +parser = HTTPieArgumentParser( formatter_class=HTTPieHelpFormatter, description='%s ' % __doc__.strip(), epilog=dedent(""" @@ -51,10 +52,12 @@ def _split_lines(self, text, width): https://github.com/jkbrzt/httpie/issues - """) + """), + usage='see http --help' ) + ####################################################################### # Positional arguments. ####################################################################### diff --git a/httpie/input.py b/httpie/input.py index 6e259bbece..5381097870 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -103,7 +103,7 @@ OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED = OUT_RESP_BODY -class Parser(ArgumentParser): +class HTTPieArgumentParser(ArgumentParser): """Adds additional logic to `argparse.ArgumentParser`. Handles all input (CLI args, file args, stdin), applies defaults, @@ -113,13 +113,13 @@ class Parser(ArgumentParser): def __init__(self, *args, **kwargs): kwargs['add_help'] = False - super(Parser, self).__init__(*args, **kwargs) + super(HTTPieArgumentParser, self).__init__(*args, **kwargs) # noinspection PyMethodOverriding def parse_args(self, env, args=None, namespace=None): self.env = env - self.args, no_options = super(Parser, self)\ + self.args, no_options = super(HTTPieArgumentParser, self)\ .parse_known_args(args, namespace) if self.args.debug: @@ -164,7 +164,7 @@ def _print_message(self, message, file=None): }.get(file, file) if not hasattr(file, 'buffer') and isinstance(message, str): message = message.encode(self.env.stdout_encoding) - super(Parser, self)._print_message(message, file) + super(HTTPieArgumentParser, self)._print_message(message, file) def _setup_standard_streams(self): """ diff --git a/tests/test_cli.py b/tests/test_cli.py index 73f68f7138..00beb16b44 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -201,7 +201,7 @@ def test_dont_expand_full_ipv6_as_shorthand(self): class TestArgumentParser: def setup_method(self, method): - self.parser = input.Parser() + self.parser = input.HTTPieArgumentParser() def test_guess_when_method_set_and_valid(self): self.parser.args = argparse.Namespace() From 589887939507ff26d36ec74bd2c045819cfa3d56 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 19:14:10 +0800 Subject: [PATCH 0138/1182] Fixed --download with --session Closes #412 --- httpie/sessions.py | 4 ++++ tests/test_sessions.py | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/httpie/sessions.py b/httpie/sessions.py index e61a8e3e2a..32254bfb19 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -101,6 +101,10 @@ def update_headers(self, request_headers): """ for name, value in request_headers.items(): + + if value is None: + continue # Ignore explicitely unset headers + value = value.decode('utf8') if name == 'User-Agent' and value.startswith('HTTPie/'): continue diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 966d87b4ea..f568377410 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -2,6 +2,7 @@ import os import shutil import sys +from tempfile import gettempdir import pytest @@ -174,3 +175,14 @@ def test_session_default_header_value_overwritten(self, httpbin): r2 = http('--session=test', httpbin.url + '/headers', env=self.env()) assert HTTP_OK in r2 assert r2.json['headers']['User-Agent'] == 'custom' + + def test_download_in_session(self, httpbin): + # https://github.com/jkbrzt/httpie/issues/412 + self.start_session(httpbin) + cwd = os.getcwd() + try: + os.chdir(gettempdir()) + http('--session=test', '--download', + httpbin.url + '/get', env=self.env()) + finally: + os.chdir(cwd) From 11275577420438885119155af62493a16074ccc7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 19:15:35 +0800 Subject: [PATCH 0139/1182] Cleanup --- tests/test_sessions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index f568377410..f59c36a005 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -180,8 +180,8 @@ def test_download_in_session(self, httpbin): # https://github.com/jkbrzt/httpie/issues/412 self.start_session(httpbin) cwd = os.getcwd() + os.chdir(gettempdir()) try: - os.chdir(gettempdir()) http('--session=test', '--download', httpbin.url + '/get', env=self.env()) finally: From 01fdab55e9f1154e7f8eda32a151a9bb810ac5e3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 19:31:43 +0800 Subject: [PATCH 0140/1182] Explain how to send fieldnames and headers starting with '-' Closes #355 --- README.rst | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 95cc00a474..f92d5b6312 100644 --- a/README.rst +++ b/README.rst @@ -341,11 +341,28 @@ their type is distinguished only by the separator used: | | in a ``multipart/form-data`` request. | +-----------------------+-----------------------------------------------------+ + You can use ``\`` to escape characters that shouldn't be used as separators (or parts thereof). For instance, ``foo\==bar`` will become a data key/value pair (``foo=`` and ``bar``) instead of a URL parameter. -You can also quote values, e.g. ``foo="bar baz"``. +Often it is necessary to quote the values, e.g. ``foo='bar baz'``. + +If any of the field names or headers starts with a minus +(e.g., ``-fieldname``), you need to place all such items after the special +token ``--`` to prevent confusion with ``--arguments``: + +.. code-block:: bash + + $ http httpbin.org/post -- -name-starting-with-dash=foo --Weird-Header:bar + +.. code-block:: http + POST /post HTTP/1.1 + --Weird-Header: yes + + { + "-name-starting-with-dash": "value" + } Note that data fields aren't the only way to specify request data: `Redirected input`_ allows for passing arbitrary data to be sent with the From e385ed6a99675eddc08b2f9a0827251ef474da64 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 19:32:19 +0800 Subject: [PATCH 0141/1182] Fix README --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index f92d5b6312..f0caf7245b 100644 --- a/README.rst +++ b/README.rst @@ -357,6 +357,7 @@ token ``--`` to prevent confusion with ``--arguments``: $ http httpbin.org/post -- -name-starting-with-dash=foo --Weird-Header:bar .. code-block:: http + POST /post HTTP/1.1 --Weird-Header: yes From 0f8d04b4df4cb299e1f9edc6abcb5edeacae6f39 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 20:12:16 +0800 Subject: [PATCH 0142/1182] More robust mime type parsing Closes #344 --- httpie/output/formatters/colors.py | 4 ++-- tests/test_output.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 6ee3964b78..2ccd5d9ae0 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -65,11 +65,11 @@ def get_lexer(self, mime): def get_lexer(mime): mime_types, lexer_names = [mime], [] - type_, subtype = mime.split('/') + type_, subtype = mime.split('/', 1) if '+' not in subtype: lexer_names.append(subtype) else: - subtype_name, subtype_suffix = subtype.split('+') + subtype_name, subtype_suffix = subtype.split('+', 1) lexer_names.extend([subtype_name, subtype_suffix]) mime_types.extend([ '%s/%s' % (type_, subtype_name), diff --git a/tests/test_output.py b/tests/test_output.py index 20ea7b41bb..6a4ebf419c 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -39,6 +39,7 @@ class TestColors: 'foo/bar+json', 'foo/json-foo', 'foo/x-json', + 'application/vnd.comverge.grid+hal+json', ]) def test_get_lexer(self, mime): lexer = get_lexer(mime) From 11a37067e7dfb2231d7f9c885b52caa64a855732 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 21:01:21 +0800 Subject: [PATCH 0143/1182] Document -A as a short name for --auth-type --- CHANGELOG.rst | 1 + README.rst | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 006a35c544..83960b4999 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,7 @@ This project adheres to `Semantic Versioning `_. ------------------------- * Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests. +* Added ``-A`` as short name for ``--auth-type`` * Changed the default color style back to``solarized`` as it supports both the light and dark terminal background mode. diff --git a/README.rst b/README.rst index f0caf7245b..04764891c5 100644 --- a/README.rst +++ b/README.rst @@ -565,7 +565,7 @@ The currently supported authentication schemes are Basic and Digest supported as well (but credentials passed via ``-a`` have higher priority). -``--auth-type`` Specify the auth mechanism. Possible values are +``--auth-type, -A`` Specify the auth mechanism. Possible values are ``basic`` and ``digest``. The default value is ``basic`` so it can often be omitted. =================== ====================================================== @@ -585,7 +585,7 @@ Digest auth: .. code-block:: bash - $ http --auth-type=digest -a username:password example.org + $ http -A digest -a username:password example.org With password prompt: From 6435532f729902f7ffb3f34cf9ac104d8442375a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 28 Feb 2016 21:37:49 +0800 Subject: [PATCH 0144/1182] Updated CHANGELOG --- CHANGELOG.rst | 2 ++ README.rst | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 83960b4999..6af2fd46de 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,8 @@ This project adheres to `Semantic Versioning `_. * Added ``-A`` as short name for ``--auth-type`` * Changed the default color style back to``solarized`` as it supports both the light and dark terminal background mode. +* Fixed ``--session`` when used with ``--download``. +* Fixed handling of ``Content-Type`` with multiple ``+subtype`` parts. `0.9.3`_ (2016-01-01) diff --git a/README.rst b/README.rst index 04764891c5..1bc92b0106 100644 --- a/README.rst +++ b/README.rst @@ -359,7 +359,7 @@ token ``--`` to prevent confusion with ``--arguments``: .. code-block:: http POST /post HTTP/1.1 - --Weird-Header: yes + --Weird-Header: bar { "-name-starting-with-dash": "value" From 763935b77f39dda0d54ea73380f83b92bbd23f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Mon, 29 Feb 2016 02:37:36 +0800 Subject: [PATCH 0145/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6af2fd46de..88db628cca 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,12 +8,12 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (Unreleased) ------------------------- -* Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests. +* Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests * Added ``-A`` as short name for ``--auth-type`` -* Changed the default color style back to``solarized`` as it supports +* Changed the default color style back to ``solarized`` as it supports both the light and dark terminal background mode. -* Fixed ``--session`` when used with ``--download``. -* Fixed handling of ``Content-Type`` with multiple ``+subtype`` parts. +* Fixed ``--session`` when used with ``--download`` +* Fixed handling of ``Content-Type`` with multiple ``+subtype`` parts `0.9.3`_ (2016-01-01) From e2235e56dc2e952e2b33538005e6c276e1d71326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Mon, 29 Feb 2016 02:38:09 +0800 Subject: [PATCH 0146/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 88db628cca..52edadfeb8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,7 +11,7 @@ This project adheres to `Semantic Versioning `_. * Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests * Added ``-A`` as short name for ``--auth-type`` * Changed the default color style back to ``solarized`` as it supports - both the light and dark terminal background mode. + both the light and dark terminal background mode * Fixed ``--session`` when used with ``--download`` * Fixed handling of ``Content-Type`` with multiple ``+subtype`` parts From dc1371d4d676e5cdbe28ee24666a0bd0aa6cc369 Mon Sep 17 00:00:00 2001 From: James Carr Date: Thu, 31 Jul 2014 00:02:03 +0100 Subject: [PATCH 0147/1182] Implemented --max-redirects option Added argument to argparse, changed client so that it uses a new requests Session() with the number of redirects and a single test to show the setting works. --- httpie/cli.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/httpie/cli.py b/httpie/cli.py index cd0c17758a..db3159a4c9 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -380,6 +380,15 @@ def _split_lines(self, text, width): """ ) +sessions.add_argument( + '--max-redirects', + dest='redirects', + default=30, + help=""" + By default, requests has a limit of 30 redirects. + + """ +) ####################################################################### # Authentication From c6d4f6cdf6199ff60af86dddf2bb0ba40ed8d9af Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 12:56:40 +0800 Subject: [PATCH 0148/1182] Show redirects WIP --- httpie/core.py | 101 +++++++++++++++++++++++---------------------- httpie/sessions.py | 6 +-- 2 files changed, 55 insertions(+), 52 deletions(-) diff --git a/httpie/core.py b/httpie/core.py index 1660b93bc8..9afe41b3f7 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -99,7 +99,6 @@ def _error(msg, *args, **kwargs): return exit_status download = None - try: args = parser.parse_args(args=args, env=env) @@ -112,60 +111,64 @@ def _error(msg, *args, **kwargs): ) download.pre_request(args.headers) - response = get_response(args, config_dir=env.config.directory) - - if args.check_status or download: - - exit_status = get_exit_status( - http_status=response.status_code, - follow=args.follow - ) - - if not env.stdout_isatty and exit_status != ExitStatus.OK: - error('HTTP %s %s', - response.raw.status, - response.raw.reason, - level='warning') + last_response = get_response(args, config_dir=env.config.directory) - write_kwargs = { - 'stream': build_output_stream( - args, env, response.request, response), + redirect_chain = last_response.history + [last_response] + for response in redirect_chain: - # This will in fact be `stderr` with `--download` - 'outfile': env.stdout, + if exit_status != ExitStatus.OK: + break - 'flush': env.stdout_isatty or args.stream - } + if args.check_status or download: - try: + exit_status = get_exit_status( + http_status=response.status_code, + follow=args.follow + ) - if env.is_windows and is_py3 and 'colors' in args.prettify: - write_with_colors_win_py3(**write_kwargs) - else: - write(**write_kwargs) + if not env.stdout_isatty and exit_status != ExitStatus.OK: + error('HTTP %s %s', + response.raw.status, + response.raw.reason, + level='warning') + + write_kwargs = { + 'stream': build_output_stream(args, env, + response.request, + response), + # This will in fact be `stderr` with `--download` + 'outfile': env.stdout, + 'flush': env.stdout_isatty or args.stream + } + + try: + if env.is_windows and is_py3 and 'colors' in args.prettify: + write_with_colors_win_py3(**write_kwargs) + else: + write(**write_kwargs) + except IOError as e: + if not traceback and e.errno == errno.EPIPE: + # Ignore broken pipes unless --traceback. + env.stderr.write('\n') + else: + raise + + if download and exit_status == ExitStatus.OK: + # Last response body download. + download_stream, download_to = download.start(last_response) + write( + stream=download_stream, + outfile=download_to, + flush=False, + ) + download.finish() + if download.interrupted: + exit_status = ExitStatus.ERROR + error('Incomplete download: size=%d; downloaded=%d' % ( + download.status.total_size, + download.status.downloaded + )) - if download and exit_status == ExitStatus.OK: - # Response body download. - download_stream, download_to = download.start(response) - write( - stream=download_stream, - outfile=download_to, - flush=False, - ) - download.finish() - if download.interrupted: - exit_status = ExitStatus.ERROR - error('Incomplete download: size=%d; downloaded=%d' % ( - download.status.total_size, - download.status.downloaded - )) - - except IOError as e: - if not traceback and e.errno == errno.EPIPE: - # Ignore broken pipes unless --traceback. - env.stderr.write('\n') - else: - raise except KeyboardInterrupt: if traceback: raise diff --git a/httpie/sessions.py b/httpie/sessions.py index 32254bfb19..9cfd7eea1d 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -22,7 +22,7 @@ def get_response(requests_session, session_name, config_dir, args, read_only=False): - """Like `client.get_response`, but applies permanent + """Like `client.get_responses`, but applies permanent aspects of the session to the request. """ @@ -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' From 356e0436510fee70b4071fac58be81c0a0a7db59 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 13:56:21 +0800 Subject: [PATCH 0149/1182] Added --show-redirects and --max-redirects Closes #157, #183, #188, #246 --- CHANGELOG.rst | 5 ++- README.rst | 16 +++++++++ httpie/__init__.py | 1 + httpie/cli.py | 36 +++++++++++++-------- httpie/core.py | 12 +++++-- tests/{fixtures.py => fixtures/__init__.py} | 2 +- tests/test_redirects.py | 22 +++++++++++++ 7 files changed, 76 insertions(+), 18 deletions(-) rename tests/{fixtures.py => fixtures/__init__.py} (92%) create mode 100644 tests/test_redirects.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 52edadfeb8..aa94209512 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,8 +9,11 @@ This project adheres to `Semantic Versioning `_. ------------------------- * Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests +* Added ``--show-redirects, -R`` to show intermediate responses with ``--follow`` +* Added ``--max-redirects`` (default 30) * Added ``-A`` as short name for ``--auth-type`` -* Changed the default color style back to ``solarized`` as it supports +* Added ``-F`` as short name for ``--follow`` +* Changed the default color style back to``solarized`` as it supports both the light and dark terminal background mode * Fixed ``--session`` when used with ``--download`` * Fixed handling of ``Content-Type`` with multiple ``+subtype`` parts diff --git a/README.rst b/README.rst index 1bc92b0106..5b201aae78 100644 --- a/README.rst +++ b/README.rst @@ -623,6 +623,21 @@ Auth Plugins * `httpie-jwt-auth `_: JWTAuth (JSON Web Tokens) +============== +HTTP Redirects +============== + +By default, HTTP redirects are not followed and only the first +response is shown. To instruct HTTPie to follow the ``Location`` header of +``30x`` responses and show the final response instead, use the ``--follow, -F`` option. + +If you additionally wish to see the intermediary requests/responses as well, +use the ``--show-redirects, -R`` option as well. + +To change the default limit of maximum 30 redirects, use the +``--max-redirects=`` option. + + ======= Proxies ======= @@ -1251,6 +1266,7 @@ Also, the ``--timeout`` option allows to overwrite the default 30s timeout: 3) echo 'Unexpected HTTP 3xx Redirection!' ;; 4) echo 'HTTP 4xx Client Error!' ;; 5) echo 'HTTP 5xx Server Error!' ;; + 6) echo 'Exceeded --max-redirects= redirects!' ;; *) echo 'Other Error!' ;; esac fi diff --git a/httpie/__init__.py b/httpie/__init__.py index 7ae07c9ee2..c4f7b82958 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -12,6 +12,7 @@ class ExitStatus: OK = 0 ERROR = 1 ERROR_TIMEOUT = 2 + ERROR_TOO_MANY_REDIRECTS = 6 # Used only when requested with --check-status: ERROR_HTTP_3XX = 3 diff --git a/httpie/cli.py b/httpie/cli.py index db3159a4c9..f03bb46be4 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -380,16 +380,6 @@ def _split_lines(self, text, width): """ ) -sessions.add_argument( - '--max-redirects', - dest='redirects', - default=30, - help=""" - By default, requests has a limit of 30 redirects. - - """ -) - ####################################################################### # Authentication ####################################################################### @@ -456,15 +446,35 @@ def _split_lines(self, text, width): """ ) network.add_argument( - '--follow', + '--follow', '-F', default=False, action='store_true', help=""" - Set this flag if full redirects are allowed (e.g. re-POST-ing of data at - new Location). + Follow 30x Location redirects. """ ) + +network.add_argument( + '--show-redirects', '-R', + default=False, + action='store_true', + help=""" + Show all responses within the redirect chain (works with --follow). + + """ +) + +network.add_argument( + '--max-redirects', + type=int, + default=30, + help=""" + By default, requests have a limit of 30 redirects (works with --follow). + + """ +) + network.add_argument( '--verify', default='yes', diff --git a/httpie/core.py b/httpie/core.py index 9afe41b3f7..c0014cea94 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -113,8 +113,12 @@ def _error(msg, *args, **kwargs): last_response = get_response(args, config_dir=env.config.directory) - redirect_chain = last_response.history + [last_response] - for response in redirect_chain: + if args.show_redirects: + responses = last_response.history + [last_response] + else: + responses = [last_response] + + for response in responses: if exit_status != ExitStatus.OK: break @@ -183,7 +187,9 @@ def _error(msg, *args, **kwargs): except requests.Timeout: exit_status = ExitStatus.ERROR_TIMEOUT error('Request timed out (%ss).', args.timeout) - + except requests.TooManyRedirects: + exit_status = ExitStatus.ERROR_TOO_MANY_REDIRECTS + error('Too many redirects (--max-redirects=%s).', args.max_redirects) except Exception as e: # TODO: Better distinction between expected and unexpected errors. # Network errors vs. bugs, etc. diff --git a/tests/fixtures.py b/tests/fixtures/__init__.py similarity index 92% rename from tests/fixtures.py rename to tests/fixtures/__init__.py index 05737c7186..294141c175 100644 --- a/tests/fixtures.py +++ b/tests/fixtures/__init__.py @@ -12,7 +12,7 @@ def patharg(path): return path.replace('\\', '\\\\\\') -FIXTURES_ROOT = path.join(path.abspath(path.dirname(__file__)), 'fixtures') +FIXTURES_ROOT = path.join(path.abspath(path.dirname(__file__))) FILE_PATH = path.join(FIXTURES_ROOT, 'test.txt') JSON_FILE_PATH = path.join(FIXTURES_ROOT, 'test.json') BIN_FILE_PATH = path.join(FIXTURES_ROOT, 'test.bin') diff --git a/tests/test_redirects.py b/tests/test_redirects.py new file mode 100644 index 0000000000..35cf9b03cc --- /dev/null +++ b/tests/test_redirects.py @@ -0,0 +1,22 @@ +"""High-level tests.""" +from httpie import ExitStatus +from utils import http, HTTP_OK + + +class TestRedirects: + + def test_follow_no_show_redirects(self, httpbin): + r = http('--follow', httpbin.url + '/redirect/2') + assert r.count('HTTP/1.1') == 1 + assert HTTP_OK in r + + def test_follow_show_redirects(self, httpbin): + r = http('--follow', '--show-redirects', httpbin.url + '/redirect/2') + assert r.count('HTTP/1.1') == 3 + assert r.count('HTTP/1.1 302 FOUND', 2) + assert HTTP_OK in r + + def test_max_redirects(self, httpbin): + r = http('--max-redirects=2', '--follow', httpbin.url + '/redirect/3', + error_exit_ok=True) + assert r.exit_status == ExitStatus.ERROR_TOO_MANY_REDIRECTS From e18b609ef7d867d6efa0efe42c832be5e0d09338 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 14:21:25 +0800 Subject: [PATCH 0150/1182] Fixed --max-redirects --- README.rst | 9 +++++++-- httpie/client.py | 1 + httpie/core.py | 1 - tests/test_redirects.py | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 5b201aae78..13803083e7 100644 --- a/README.rst +++ b/README.rst @@ -631,13 +631,18 @@ By default, HTTP redirects are not followed and only the first response is shown. To instruct HTTPie to follow the ``Location`` header of ``30x`` responses and show the final response instead, use the ``--follow, -F`` option. -If you additionally wish to see the intermediary requests/responses as well, -use the ``--show-redirects, -R`` option as well. +If you additionally wish to see the intermediary requests/responses, +then use the ``--show-redirects, -R`` option as well. To change the default limit of maximum 30 redirects, use the ``--max-redirects=`` option. +.. code-block:: bash + + $ http --follow --show-redirects --max-redirects=5 httpbin.org/redirect/3 + + ======= Proxies ======= diff --git a/httpie/client.py b/httpie/client.py index 1115f4dd98..482f9dce29 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -40,6 +40,7 @@ def get_response(args, config_dir): """Send the request and return a `request.Response`.""" requests_session = get_requests_session() + requests_session.max_redirects = args.max_redirects if not args.session and not args.session_read_only: kwargs = get_requests_kwargs(args) diff --git a/httpie/core.py b/httpie/core.py index c0014cea94..3dbe7f2be1 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -192,7 +192,6 @@ def _error(msg, *args, **kwargs): error('Too many redirects (--max-redirects=%s).', args.max_redirects) except Exception as e: # TODO: Better distinction between expected and unexpected errors. - # Network errors vs. bugs, etc. if traceback: raise msg = str(e) diff --git a/tests/test_redirects.py b/tests/test_redirects.py index 35cf9b03cc..94b1fc07c4 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -17,6 +17,6 @@ def test_follow_show_redirects(self, httpbin): assert HTTP_OK in r def test_max_redirects(self, httpbin): - r = http('--max-redirects=2', '--follow', httpbin.url + '/redirect/3', + r = http('--max-redirects=1', '--follow', httpbin.url + '/redirect/3', error_exit_ok=True) assert r.exit_status == ExitStatus.ERROR_TOO_MANY_REDIRECTS From 5408fb0fb9aa4396864f344d5e6de27bd8363181 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 14:31:27 +0800 Subject: [PATCH 0151/1182] Cleanup --- CHANGELOG.rst | 2 +- tests/test_redirects.py | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index aa94209512..e5bd6dbcd5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,7 +13,7 @@ This project adheres to `Semantic Versioning `_. * Added ``--max-redirects`` (default 30) * Added ``-A`` as short name for ``--auth-type`` * Added ``-F`` as short name for ``--follow`` -* Changed the default color style back to``solarized`` as it supports +* Changed the default color style back to ``solarized`` as it supports both the light and dark terminal background mode * Fixed ``--session`` when used with ``--download`` * Fixed handling of ``Content-Type`` with multiple ``+subtype`` parts diff --git a/tests/test_redirects.py b/tests/test_redirects.py index 94b1fc07c4..e96ea8e5f1 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -3,20 +3,20 @@ from utils import http, HTTP_OK -class TestRedirects: +def test_follow_no_show_redirects(httpbin): + r = http('--follow', httpbin.url + '/redirect/2') + assert r.count('HTTP/1.1') == 1 + assert HTTP_OK in r - def test_follow_no_show_redirects(self, httpbin): - r = http('--follow', httpbin.url + '/redirect/2') - assert r.count('HTTP/1.1') == 1 - assert HTTP_OK in r - def test_follow_show_redirects(self, httpbin): - r = http('--follow', '--show-redirects', httpbin.url + '/redirect/2') - assert r.count('HTTP/1.1') == 3 - assert r.count('HTTP/1.1 302 FOUND', 2) - assert HTTP_OK in r +def test_follow_show_redirects(httpbin): + r = http('--follow', '--show-redirects', httpbin.url + '/redirect/2') + assert r.count('HTTP/1.1') == 3 + assert r.count('HTTP/1.1 302 FOUND', 2) + assert HTTP_OK in r - def test_max_redirects(self, httpbin): - r = http('--max-redirects=1', '--follow', httpbin.url + '/redirect/3', - error_exit_ok=True) - assert r.exit_status == ExitStatus.ERROR_TOO_MANY_REDIRECTS + +def test_max_redirects(httpbin): + r = http('--max-redirects=1', '--follow', httpbin.url + '/redirect/3', + error_exit_ok=True) + assert r.exit_status == ExitStatus.ERROR_TOO_MANY_REDIRECTS From ed08ab133eab5991fe46db011e6e04f3230f0026 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 15:00:17 +0800 Subject: [PATCH 0152/1182] Refactoring --- httpie/core.py | 55 +++++++++++++++++++--------------------- httpie/downloads.py | 2 +- httpie/output/streams.py | 4 +-- tests/test_downloads.py | 34 ++++++++++++------------- 4 files changed, 46 insertions(+), 49 deletions(-) diff --git a/httpie/core.py b/httpie/core.py index 3dbe7f2be1..e6875524a8 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -20,12 +20,13 @@ from httpie import __version__ as httpie_version, ExitStatus from httpie.compat import str, bytes, is_py3 from httpie.client import get_response -from httpie.downloads import Download +from httpie.downloads import Downloader from httpie.context import Environment from httpie.plugins import plugin_manager from httpie.output.streams import ( build_output_stream, - write, write_with_colors_win_py3 + write_stream, + write_stream_with_colors_win_py3 ) @@ -98,21 +99,20 @@ def _error(msg, *args, **kwargs): if args == ['--debug']: return exit_status - download = None + downloader = None try: args = parser.parse_args(args=args, env=env) if args.download: args.follow = True # --download implies --follow. - download = Download( + downloader = Downloader( output_file=args.output_file, progress_file=env.stderr, resume=args.download_resume ) - download.pre_request(args.headers) + downloader.pre_request(args.headers) last_response = get_response(args, config_dir=env.config.directory) - if args.show_redirects: responses = last_response.history + [last_response] else: @@ -120,36 +120,33 @@ def _error(msg, *args, **kwargs): for response in responses: - if exit_status != ExitStatus.OK: - break - - if args.check_status or download: - + if args.check_status or downloader: exit_status = get_exit_status( http_status=response.status_code, follow=args.follow ) - if not env.stdout_isatty and exit_status != ExitStatus.OK: error('HTTP %s %s', response.raw.status, response.raw.reason, level='warning') - write_kwargs = { - 'stream': build_output_stream(args, env, - response.request, - response), - # This will in fact be `stderr` with `--download` + write_stream_kwargs = { + 'stream': build_output_stream( + args=args, + env=env, + request=response.request, + response=response, + ), + # NOTE: `env.stdout` will in fact be `stderr` with `--download` 'outfile': env.stdout, 'flush': env.stdout_isatty or args.stream } - try: if env.is_windows and is_py3 and 'colors' in args.prettify: - write_with_colors_win_py3(**write_kwargs) + write_stream_with_colors_win_py3(**write_stream_kwargs) else: - write(**write_kwargs) + write_stream(**write_stream_kwargs) except IOError as e: if not traceback and e.errno == errno.EPIPE: # Ignore broken pipes unless --traceback. @@ -157,20 +154,20 @@ def _error(msg, *args, **kwargs): else: raise - if download and exit_status == ExitStatus.OK: + if downloader and exit_status == ExitStatus.OK: # Last response body download. - download_stream, download_to = download.start(last_response) - write( + download_stream, download_to = downloader.start(last_response) + write_stream( stream=download_stream, outfile=download_to, flush=False, ) - download.finish() - if download.interrupted: + downloader.finish() + if downloader.interrupted: exit_status = ExitStatus.ERROR error('Incomplete download: size=%d; downloaded=%d' % ( - download.status.total_size, - download.status.downloaded + downloader.status.total_size, + downloader.status.downloaded )) except KeyboardInterrupt: @@ -204,7 +201,7 @@ def _error(msg, *args, **kwargs): exit_status = ExitStatus.ERROR finally: - if download and not download.finished: - download.failed() + if downloader and not downloader.finished: + downloader.failed() return exit_status diff --git a/httpie/downloads.py b/httpie/downloads.py index 122a3b3d0f..e6064a354a 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -144,7 +144,7 @@ def get_unique_filename(filename, exists=os.path.exists): attempt += 1 -class Download(object): +class Downloader(object): def __init__(self, output_file=None, resume=False, progress_file=sys.stderr): diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 8460537dbf..03046a57a3 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -24,7 +24,7 @@ class BinarySuppressedError(Exception): message = BINARY_SUPPRESSED_NOTICE -def write(stream, outfile, flush): +def write_stream(stream, outfile, flush): """Write the output stream.""" try: # Writing bytes so we use the buffer interface (Python 3). @@ -38,7 +38,7 @@ def write(stream, outfile, flush): outfile.flush() -def write_with_colors_win_py3(stream, outfile, flush): +def write_stream_with_colors_win_py3(stream, outfile, flush): """Like `write`, but colorized chunks are written as text directly to `outfile` to ensure it gets processed by colorama. Applies only to Windows with Python 3 and colorized terminal output. diff --git a/tests/test_downloads.py b/tests/test_downloads.py index 3a8c8f24f4..456886b525 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -7,7 +7,7 @@ from httpie.compat import urlopen from httpie.downloads import ( parse_content_range, filename_from_content_disposition, filename_from_url, - get_unique_filename, ContentRangeError, Download, + get_unique_filename, ContentRangeError, Downloader, ) from utils import http, TestEnvironment @@ -106,34 +106,34 @@ def test_actual_download(self, httpbin): def test_download_with_Content_Length(self, httpbin): devnull = open(os.devnull, 'w') - download = Download(output_file=devnull, progress_file=devnull) - download.start(Response( + downloader = Downloader(output_file=devnull, progress_file=devnull) + downloader.start(Response( url=httpbin.url + '/', headers={'Content-Length': 10} )) time.sleep(1.1) - download.chunk_downloaded(b'12345') + downloader.chunk_downloaded(b'12345') time.sleep(1.1) - download.chunk_downloaded(b'12345') - download.finish() - assert not download.interrupted + downloader.chunk_downloaded(b'12345') + downloader.finish() + assert not downloader.interrupted def test_download_no_Content_Length(self, httpbin): devnull = open(os.devnull, 'w') - download = Download(output_file=devnull, progress_file=devnull) - download.start(Response(url=httpbin.url + '/')) + downloader = Downloader(output_file=devnull, progress_file=devnull) + downloader.start(Response(url=httpbin.url + '/')) time.sleep(1.1) - download.chunk_downloaded(b'12345') - download.finish() - assert not download.interrupted + downloader.chunk_downloaded(b'12345') + downloader.finish() + assert not downloader.interrupted def test_download_interrupted(self, httpbin): devnull = open(os.devnull, 'w') - download = Download(output_file=devnull, progress_file=devnull) - download.start(Response( + downloader = Downloader(output_file=devnull, progress_file=devnull) + downloader.start(Response( url=httpbin.url + '/', headers={'Content-Length': 5} )) - download.chunk_downloaded(b'1234') - download.finish() - assert download.interrupted + downloader.chunk_downloaded(b'1234') + downloader.finish() + assert downloader.interrupted From b44e16ed0f566d653f6389adce7be0b71e4c355a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Mon, 29 Feb 2016 15:14:43 +0800 Subject: [PATCH 0153/1182] Fix appveyor --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index f7067b89de..863cd0d1d9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,10 +7,10 @@ environment: init: - "ECHO %PYTHON%" - ps: "ls C:/Python*" -install: +#install: # - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') # - "%PYTHON%/python.exe C:/get-pip.py" - - "%PYTHON%/Scripts/pip.exe install -U pip setuptools" +# - "%PYTHON%/Scripts/pip.exe install -U pip setuptools" - "%PYTHON%/Scripts/pip.exe install -e ." test_script: - "%PYTHON%/Scripts/pip.exe --version" From e42f7b8fc951f5d3a45e143fb9b763c7950e69f4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 15:31:31 +0800 Subject: [PATCH 0154/1182] OSX build --- .travis.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5c44d61161..bbb078657d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,9 @@ sudo: false os: - linux - # - osx env: global: - - NEWEST_PYTHON=3.4 + - NEWEST_PYTHON=3.4 language: python python: - 2.6 @@ -14,7 +13,14 @@ python: - 3.3 - 3.4 - pypy3 + +matrix: + include: + # https://docs.travis-ci.com/user/multi-os/#Python-example-(unsupported-languages) + - os: osx + language: generic + script: - make after_success: - - if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON ]]; then pip install python-coveralls && coveralls; fi + - [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux']] && pip install python-coveralls && coveralls From 576ee83d82ed2b05049b466328d0ae7cfe040572 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 15:35:56 +0800 Subject: [PATCH 0155/1182] Fix travis --- .travis.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index bbb078657d..6000b693cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,14 @@ # https://travis-ci.org/jkbrzt/httpie sudo: false + +language: python os: - linux + env: global: - - NEWEST_PYTHON=3.4 -language: python + - NEWEST_PYTHON=3.4 + python: - 2.6 - 2.7 @@ -22,5 +25,6 @@ matrix: script: - make + after_success: - [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux']] && pip install python-coveralls && coveralls From 0a002ec554aab6d561d5fcef3bd3bc11aeeccbba Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 15:38:59 +0800 Subject: [PATCH 0156/1182] Fix travis --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6000b693cf..ecbaca8bd8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,4 +27,7 @@ script: - make after_success: - - [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux']] && pip install python-coveralls && coveralls + - | + if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux']]; then + pip install python-coveralls && coveralls + fi From f43e473de14ece19280ee3a7d64c686d2e69402c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 16:35:09 +0800 Subject: [PATCH 0157/1182] Travis --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index ecbaca8bd8..5463947472 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,12 @@ matrix: script: - make +install: + - | + if [[ $TRAVIS_OS_NAME == 'osx']]; then + brew install python + fi + after_success: - | if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux']]; then From e5e5d0ce6df482f1743129945990cba8c63b2bbd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 16:36:25 +0800 Subject: [PATCH 0158/1182] Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5463947472..75df6f3b26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ script: install: - | - if [[ $TRAVIS_OS_NAME == 'osx']]; then + if [[ $TRAVIS_OS_NAME == 'osx' ]]; then brew install python fi From 3b217daddce881fdbb4d429832faaa6492049a27 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 16:43:18 +0800 Subject: [PATCH 0159/1182] Travis --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 89e0342e8a..dadf05cca3 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ END=" \#\#\# \033[0m\n" all: test -init: uninstall-httpie +init: @echo $(TAG)Installing dev requirements$(END) pip install --upgrade -r $(REQUIREMENTS) From 73e0455896a56787e2c85cf1e3dd8ff91da7b0cc Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 16:52:33 +0800 Subject: [PATCH 0160/1182] Travis --- .travis.yml | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 75df6f3b26..bcb007ecc1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,29 +7,46 @@ os: env: global: - - NEWEST_PYTHON=3.4 + - NEWEST_PYTHON=3.5 python: - 2.6 - 2.7 - pypy - - 3.3 - - 3.4 + - 3.5 - pypy3 matrix: + include: # https://docs.travis-ci.com/user/multi-os/#Python-example-(unsupported-languages) - os: osx language: generic + env: + - TOXENV=py27 + - os: osx + language: generic + env: + - BREW_INSTALL=python + - TOXENV=py27 + - os: osx + language: generic + env: + - BREW_INSTALL=python3 + - TOXENV=py35 script: - - make + - | + if [[ $TRAVIS_OS_NAME == 'linux' ]]; then + make + else + tox -e "$TOXENV" + fi install: - | - if [[ $TRAVIS_OS_NAME == 'osx' ]]; then - brew install python + if [[ $TRAVIS_OS_NAME == 'osx' && -n "$BREW_INSTALL" ]]; then + brew install "$BREW_INSTALL" fi after_success: From fee54b04d8adeff4b696ac97060c746b1cc8f695 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 17:09:55 +0800 Subject: [PATCH 0161/1182] Travis --- .travis.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index bcb007ecc1..a6c33017db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,6 +35,15 @@ matrix: - BREW_INSTALL=python3 - TOXENV=py35 +install: + - | + if [[ $TRAVIS_OS_NAME == 'osx' ]]; then + if [[ -n "$BREW_INSTALL" ]]; then + brew install "$BREW_INSTALL" + fi + sudo pip install tox + fi + script: - | if [[ $TRAVIS_OS_NAME == 'linux' ]]; then @@ -43,12 +52,6 @@ script: tox -e "$TOXENV" fi -install: - - | - if [[ $TRAVIS_OS_NAME == 'osx' && -n "$BREW_INSTALL" ]]; then - brew install "$BREW_INSTALL" - fi - after_success: - | if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux']]; then From 41b0286f37f862a503b9f26249498d297e1323a8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 17:19:12 +0800 Subject: [PATCH 0162/1182] Travis --- .travis.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index a6c33017db..65c2bd4d56 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,23 +19,32 @@ python: matrix: include: + + # Manually defined OS X builds # https://docs.travis-ci.com/user/multi-os/#Python-example-(unsupported-languages) + + # Stock OSX Python - os: osx language: generic env: - TOXENV=py27 + + # Latest Python 2.x from Homebrew - os: osx language: generic env: - - BREW_INSTALL=python - TOXENV=py27 + - BREW_INSTALL=python + + # Latest Python 3.x from Homebrew - os: osx language: generic env: - - BREW_INSTALL=python3 - TOXENV=py35 + - BREW_INSTALL=python3 install: + - brew update - | if [[ $TRAVIS_OS_NAME == 'osx' ]]; then if [[ -n "$BREW_INSTALL" ]]; then @@ -49,7 +58,7 @@ script: if [[ $TRAVIS_OS_NAME == 'linux' ]]; then make else - tox -e "$TOXENV" + PATH="/usr/local/bin:$PATH" tox -e "$TOXENV" fi after_success: From a97f0d52f6e5480e963865aa2c3a925bd9301b57 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 17:20:50 +0800 Subject: [PATCH 0163/1182] Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 65c2bd4d56..bbe20090ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,10 +44,10 @@ matrix: - BREW_INSTALL=python3 install: - - brew update - | if [[ $TRAVIS_OS_NAME == 'osx' ]]; then if [[ -n "$BREW_INSTALL" ]]; then + brew update brew install "$BREW_INSTALL" fi sudo pip install tox From 3625bb6fa1c4de0f8d49d72bd57f9b4733ed1169 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 22:00:18 +0800 Subject: [PATCH 0164/1182] Updated travis badge title --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 13803083e7..06f65a5cb1 100644 --- a/README.rst +++ b/README.rst @@ -1380,7 +1380,7 @@ Please see `LICENSE `_. :target: https://coveralls.io/r/jkbrzt/httpie?branch=master :alt: Test coverage -.. |unix_build| image:: https://img.shields.io/travis/jkbrzt/httpie/master.svg?style=flat-square&label=unix%20build +.. |unix_build| image:: https://img.shields.io/travis/jkbrzt/httpie/master.svg?style=flat-square&label=Linux%20and%20OS%20X%20builds :target: http://travis-ci.org/jkbrzt/httpie :alt: Build status of the master branch on Mac/Linux From 48ce934dfad3e03f5232a4f8d8ebe1a641f3f215 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 22:01:05 +0800 Subject: [PATCH 0165/1182] Capitalization --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 06f65a5cb1..9a3b0f9690 100644 --- a/README.rst +++ b/README.rst @@ -1372,7 +1372,7 @@ Please see `LICENSE `_. .. _claudiatd/httpie-artwork: https://github.com/claudiatd/httpie-artwork -.. |pypi| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square&label=latest%20version +.. |pypi| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square&label=Latest%20version :target: https://pypi.python.org/pypi/httpie :alt: Latest version released on PyPi @@ -1384,6 +1384,6 @@ Please see `LICENSE `_. :target: http://travis-ci.org/jkbrzt/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 +.. |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 From 9312fabc01676f007980ea84672fba228b0e7fea Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 29 Feb 2016 22:03:08 +0800 Subject: [PATCH 0166/1182] Capitalization II --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 9a3b0f9690..2fb90b21d7 100644 --- a/README.rst +++ b/README.rst @@ -1376,7 +1376,7 @@ Please see `LICENSE `_. :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 +.. |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 :alt: Test coverage From 776328c818ad52bc2d965c905e1a7409b192b5ca Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 00:08:07 +0800 Subject: [PATCH 0167/1182] Added gitter chat --- README.rst | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 2fb90b21d7..10b51bfd71 100644 --- a/README.rst +++ b/README.rst @@ -23,7 +23,7 @@ HTTPie is written in Python, and under the hood it uses the excellent ----- -|pypi| |unix_build| |windows_build| |coverage| +|gitter| |pypi| |unix_build| |windows_build| |coverage| ----- @@ -1372,18 +1372,23 @@ Please see `LICENSE `_. .. _claudiatd/httpie-artwork: https://github.com/claudiatd/httpie-artwork -.. |pypi| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square&label=Latest%20version +.. |pypi| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square&label=latest%20version :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 +.. |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 :alt: Test coverage -.. |unix_build| image:: https://img.shields.io/travis/jkbrzt/httpie/master.svg?style=flat-square&label=Linux%20and%20OS%20X%20builds +.. |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 :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 +.. |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 + :target: https://gitter.im/jkbrzt/httpie + :alt: Chat on Gitter + From 9f8c452e7e3565fda95a4a1c092ecf17c7e50ede Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 00:12:55 +0800 Subject: [PATCH 0168/1182] Added gitter chat --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.travis.yml b/.travis.yml index bbe20090ad..f8f8dd27f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -66,3 +66,13 @@ after_success: if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux']]; then pip install python-coveralls && coveralls fi + +notifications: + + webhooks: + urls: + # https://gitter.im/jkbrzt/httpie + - https://webhooks.gitter.im/e/c42fcd359a110d02830b + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: never # options: [always|never|change] default: always From c50413a9c16b60fbe09b61ae79c7d37d0995e6a5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 00:24:52 +0800 Subject: [PATCH 0169/1182] Added support section --- README.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.rst b/README.rst index 10b51bfd71..8b418a523f 100644 --- a/README.rst +++ b/README.rst @@ -1324,6 +1324,19 @@ HTTPie reaches its final version ``1.0``. All changes are recorded in the +======= +Support +======= + +* Use `GitHub issues `_ + for bug reports and feature requests. +* Ask questions and discuss features on + `Gitter chat `_. +* Ask questions on `StackOverflow `_ + (please make sure to use the + `httpie `_ tag). +* You can also tweet directly to `@jkbrzt `_. + ======= Authors ======= From 0fc1f61f3df13280add82c1ca12ff2250fdbf270 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 00:45:54 +0800 Subject: [PATCH 0170/1182] Fixed README --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 8b418a523f..e46b959eb7 100644 --- a/README.rst +++ b/README.rst @@ -1335,7 +1335,7 @@ Support * Ask questions on `StackOverflow `_ (please make sure to use the `httpie `_ tag). -* You can also tweet directly to `@jkbrzt `_. +* You can also tweet directly to `@jkbrzt`_. ======= Authors From 74e4d0b67852ab0b628f687ac62e2d509fa74b61 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 14:57:15 +0800 Subject: [PATCH 0171/1182] Added JSON detection when ``--json, -j`` is set To correctly format JSON responses even when an incorrect ``Content-Type`` is returned. Closes #92 Closes #349 Closes #368 --- .gitignore | 19 +++++++------ CHANGELOG.rst | 2 ++ README.rst | 8 ++++-- httpie/output/formatters/colors.py | 44 ++++++++++++++++++++++-------- httpie/output/formatters/json.py | 15 +++++----- httpie/output/streams.py | 8 ++++-- tests/test_output.py | 37 ++++++++++++++----------- 7 files changed, 85 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index 3bdb64f390..0131d9ac8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,13 @@ -dist -httpie.egg-info -build -*.pyc -*.egg +.DS_Store +.idea/ +__pycache__/ +dist/ +httpie.egg-info/ +build/ +*.egg-info +.cache/ .tox -README.html .coverage +*.pyc +*.egg htmlcov -.idea -.DS_Store -.cache/ diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e5bd6dbcd5..64ec566045 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,6 +13,8 @@ This project adheres to `Semantic Versioning `_. * Added ``--max-redirects`` (default 30) * Added ``-A`` as short name for ``--auth-type`` * Added ``-F`` as short name for ``--follow`` +* Added JSON detection when ``--json, -j`` is used in order to correctly format + JSON responses even when an incorrect ``Content-Type`` is returned. * Changed the default color style back to ``solarized`` as it supports both the light and dark terminal background mode * Fixed ``--session`` when used with ``--download`` diff --git a/README.rst b/README.rst index e46b959eb7..c0055576d5 100644 --- a/README.rst +++ b/README.rst @@ -389,7 +389,9 @@ both of which can be overwritten: You can use ``--json, -j`` to explicitly set ``Accept`` to ``application/json`` regardless of whether you are sending data (it's a shortcut for setting the header via the usual header notation – -``http url Accept:application/json``). +``http url Accept:application/json``). Also, with ``--json, -j``, +HTTPie tries to detect if the body is JSON even if the ``Content-Type`` +doesn't specify it in order to correctly format it. Simple example: @@ -1330,8 +1332,8 @@ Support * Use `GitHub issues `_ for bug reports and feature requests. -* Ask questions and discuss features on - `Gitter chat `_. +* Ask questions and discuss features in + ` our Gitter chat room `_. * Ask questions on `StackOverflow `_ (please make sure to use the `httpie `_ tag). diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 2ccd5d9ae0..10ce5db20f 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -1,3 +1,5 @@ +import json + import pygments.lexer import pygments.token import pygments.styles @@ -5,6 +7,7 @@ import pygments.style from pygments.formatters.terminal import TerminalFormatter from pygments.formatters.terminal256 import Terminal256Formatter +from pygments.lexers.special import TextLexer from pygments.util import ClassNotFound from httpie.plugins import FormatterPlugin @@ -27,12 +30,16 @@ class ColorFormatter(FormatterPlugin): """ group_name = 'colors' - def __init__(self, env, color_scheme=DEFAULT_STYLE, **kwargs): + 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 + # Cache to speed things up when we process streamed body by line. self.lexer_cache = {} @@ -51,19 +58,18 @@ def format_headers(self, headers): return pygments.highlight(headers, HTTPLexer(), self.formatter).strip() def format_body(self, body, mime): - lexer = self.get_lexer(mime) + lexer = self.get_lexer(mime, body) if lexer: body = pygments.highlight(body, lexer, self.formatter) return body.strip() - def get_lexer(self, mime): - if mime in self.lexer_cache: - return self.lexer_cache[mime] - self.lexer_cache[mime] = get_lexer(mime) - return self.lexer_cache[mime] + def get_lexer(self, mime, body): + return get_lexer(mime, body, self.explicit_json) + +def get_lexer(mime, explicit_json=False, body=''): -def get_lexer(mime): + # Build candidate mime type and lexer names. mime_types, lexer_names = [mime], [] type_, subtype = mime.split('/', 1) if '+' not in subtype: @@ -75,10 +81,14 @@ def get_lexer(mime): '%s/%s' % (type_, subtype_name), '%s/%s' % (type_, subtype_suffix) ]) - # as a last resort, if no lexer feels responsible, and - # the subtype contains 'json', take the JSON lexer - if 'json' in subtype: + + # As a last resort, if no lexer feels responsible, and + # the subtype contains 'json' or explicit --json is set, + # take the JSON lexer + if 'json' in subtype or explicit_json: lexer_names.append('json') + + # Try to resolve the right lexer. lexer = None for mime_type in mime_types: try: @@ -92,6 +102,18 @@ def get_lexer(mime): lexer = pygments.lexers.get_lexer_by_name(name) except ClassNotFound: pass + + if lexer and explicit_json and body and isinstance(lexer, TextLexer): + # When a text lexer is resolved even with --json (i.e. explicit + # text/plain Content-Type), try to parse the response as JSON + # and if it parses, sneak in the JSON lexer instead. + try: + json.loads(body) # FIXME: it also gets parsed in json.py + except ValueError: + pass # Invalid JSON, ignore. + else: + lexer = pygments.lexers.get_lexer_by_name('json') + return lexer diff --git a/httpie/output/formatters/json.py b/httpie/output/formatters/json.py index 292cc142b8..64b15f0ed9 100644 --- a/httpie/output/formatters/json.py +++ b/httpie/output/formatters/json.py @@ -10,17 +10,18 @@ class JSONFormatter(FormatterPlugin): def format_body(self, body, mime): - if 'json' in mime: + if 'json' in mime or self.kwargs['explicit_json']: try: obj = json.loads(body) except ValueError: - # Invalid JSON, ignore. - pass + pass # Invalid JSON, ignore. else: # Indent, sort keys by name, and avoid # unicode escapes to improve readability. - body = json.dumps(obj, - sort_keys=True, - ensure_ascii=False, - indent=DEFAULT_INDENT) + body = json.dumps( + obj=obj, + sort_keys=True, + ensure_ascii=False, + indent=DEFAULT_INDENT + ) return body diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 03046a57a3..b22698142c 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -112,8 +112,12 @@ def get_stream_type(env, args): PrettyStream if args.stream else BufferedPrettyStream, env=env, conversion=Conversion(), - formatting=Formatting(env=env, groups=args.prettify, - color_scheme=args.style), + formatting=Formatting( + env=env, + groups=args.prettify, + color_scheme=args.style, + explicit_json=args.json, + ), ) else: Stream = partial(EncodedStream, env=env) diff --git a/tests/test_output.py b/tests/test_output.py index 6a4ebf419c..483eeb3990 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -28,23 +28,28 @@ def test_verbose_json(self, httpbin): class TestColors: - @pytest.mark.parametrize('mime', [ - 'application/json', - 'application/json+foo', - 'application/foo+json', - 'application/json-foo', - 'application/x-json', - 'foo/json', - 'foo/json+bar', - 'foo/bar+json', - 'foo/json-foo', - 'foo/x-json', - 'application/vnd.comverge.grid+hal+json', - ]) - def test_get_lexer(self, mime): - lexer = get_lexer(mime) + @pytest.mark.parametrize( + argnames=['mime', 'explicit_json', 'body', 'expected_lexer_name'], + argvalues=[ + ('application/json', False, None, 'JSON'), + ('application/json+foo', False, None, 'JSON'), + ('application/foo+json', False, None, 'JSON'), + ('application/json-foo', False, None, 'JSON'), + ('application/x-json', False, None, 'JSON'), + ('foo/json', False, None, 'JSON'), + ('foo/json+bar', False, None, 'JSON'), + ('foo/bar+json', False, None, 'JSON'), + ('foo/json-foo', False, None, 'JSON'), + ('foo/x-json', False, None, 'JSON'), + ('application/vnd.comverge.grid+hal+json', False, None, 'JSON'), + ('text/plain', True, '{}', 'JSON'), + ('text/plain', True, 'foo', 'Text only'), + ] + ) + def test_get_lexer(self, mime, explicit_json, body, expected_lexer_name): + lexer = get_lexer(mime, body=body, explicit_json=explicit_json) assert lexer is not None - assert lexer.name == 'JSON' + assert lexer.name == expected_lexer_name def test_get_lexer_not_found(self): assert get_lexer('xxx/yyy') is None From f96f0ef9ed88b26e6609a9404b02a6a4f3be20ae Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 16:22:54 +0800 Subject: [PATCH 0172/1182] JSON detection improvements --- README.rst | 7 ++++--- httpie/output/formatters/colors.py | 15 ++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/README.rst b/README.rst index c0055576d5..a55226c558 100644 --- a/README.rst +++ b/README.rst @@ -389,9 +389,10 @@ both of which can be overwritten: You can use ``--json, -j`` to explicitly set ``Accept`` to ``application/json`` regardless of whether you are sending data (it's a shortcut for setting the header via the usual header notation – -``http url Accept:application/json``). Also, with ``--json, -j``, -HTTPie tries to detect if the body is JSON even if the ``Content-Type`` -doesn't specify it in order to correctly format it. +``http url Accept:application/json``). + +Additionally, with the ``--json, -j`` option HTTPie tries to detect JSON +responses event when the ``Content-Type`` is ``text/plain`` or unknown. Simple example: diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 10ce5db20f..43a2882902 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -83,9 +83,8 @@ def get_lexer(mime, explicit_json=False, body=''): ]) # As a last resort, if no lexer feels responsible, and - # the subtype contains 'json' or explicit --json is set, - # take the JSON lexer - if 'json' in subtype or explicit_json: + # the subtype contains 'json', take the JSON lexer + if 'json' in subtype: lexer_names.append('json') # Try to resolve the right lexer. @@ -103,14 +102,12 @@ def get_lexer(mime, explicit_json=False, body=''): except ClassNotFound: pass - if lexer and explicit_json and body and isinstance(lexer, TextLexer): - # When a text lexer is resolved even with --json (i.e. explicit - # text/plain Content-Type), try to parse the response as JSON - # and if it parses, sneak in the JSON lexer instead. + if explicit_json and body and (not lexer or isinstance(lexer, TextLexer)): + # JSON response with an incorrect Content-Type? try: - json.loads(body) # FIXME: it also gets parsed in json.py + json.loads(body) # FIXME: the body also gets parsed in json.py except ValueError: - pass # Invalid JSON, ignore. + pass # Nope else: lexer = pygments.lexers.get_lexer_by_name('json') From 345f5a02a20a38f53d1f9a894c1b0519972ca184 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 16:39:50 +0800 Subject: [PATCH 0173/1182] Fixed json absolute import --- httpie/output/formatters/colors.py | 1 + 1 file changed, 1 insertion(+) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 43a2882902..0800d80d0c 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import json import pygments.lexer From e83e554ffb704b7c588a478a7bb187a19bab4a16 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 16:50:30 +0800 Subject: [PATCH 0174/1182] README --- README.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index a55226c558..22f97a4458 100644 --- a/README.rst +++ b/README.rst @@ -23,7 +23,7 @@ HTTPie is written in Python, and under the hood it uses the excellent ----- -|gitter| |pypi| |unix_build| |windows_build| |coverage| +|pypi| |unix_build| |windows_build| |coverage| |gitter| ----- @@ -389,10 +389,9 @@ both of which can be overwritten: You can use ``--json, -j`` to explicitly set ``Accept`` to ``application/json`` regardless of whether you are sending data (it's a shortcut for setting the header via the usual header notation – -``http url Accept:application/json``). - -Additionally, with the ``--json, -j`` option HTTPie tries to detect JSON -responses event when the ``Content-Type`` is ``text/plain`` or unknown. +``http url Accept:application/json``). Additionally, +HTTPie will try to detect JSON responses even when the +``Content-Type`` is incorrectly ``text/plain`` or unknown. Simple example: From 4f8d6c013b3d80a59fe860963a33b84a1da4bbd5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 16:55:12 +0800 Subject: [PATCH 0175/1182] Fixed get_lexer() --- httpie/output/formatters/colors.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 0800d80d0c..6d13fba8dc 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -41,9 +41,6 @@ def __init__(self, env, explicit_json=False, # --json, -j self.explicit_json = explicit_json - # Cache to speed things up when we process streamed body by line. - self.lexer_cache = {} - try: style_class = pygments.styles.get_style_by_name(color_scheme) except ClassNotFound: @@ -65,7 +62,11 @@ def format_body(self, body, mime): return body.strip() def get_lexer(self, mime, body): - return get_lexer(mime, body, self.explicit_json) + return get_lexer( + mime=mime, + explicit_json=self.explicit_json, + body=body, + ) def get_lexer(mime, explicit_json=False, body=''): From 01ca7f0eb28790a594ce94b337caf6f776078215 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 20:24:50 +0800 Subject: [PATCH 0176/1182] Ignore redirected stdout with --output, -o This makes it easier to use HTTPie in cron jobs and scripts. Closes #259 --- CHANGELOG.rst | 5 ++++- Makefile | 2 +- httpie/cli.py | 5 +++-- httpie/core.py | 4 ++++ httpie/input.py | 6 ++---- tests/test_output.py | 20 ++++++++++++++++++++ tests/test_windows.py | 4 +++- 7 files changed, 37 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 64ec566045..4fde5aaf5b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,7 @@ Change Log This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. + `1.0.0-dev`_ (Unreleased) ------------------------- @@ -15,6 +16,8 @@ This project adheres to `Semantic Versioning `_. * Added ``-F`` as short name for ``--follow`` * Added JSON detection when ``--json, -j`` is used in order to correctly format JSON responses even when an incorrect ``Content-Type`` is returned. +* Redirected ``stdout`` doesn't trigger an error anymore when ``--output FILE`` + is set. * Changed the default color style back to ``solarized`` as it supports both the light and dark terminal background mode * Fixed ``--session`` when used with ``--download`` @@ -22,7 +25,7 @@ This project adheres to `Semantic Versioning `_. `0.9.3`_ (2016-01-01) -------------------------- +--------------------- * Changed the default color ``--style`` from ``solarized`` to ``monokai`` * Added basic Bash autocomplete support (need to be installed manually) diff --git a/Makefile b/Makefile index dadf05cca3..89e0342e8a 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ END=" \#\#\# \033[0m\n" all: test -init: +init: uninstall-httpie @echo $(TAG)Installing dev requirements$(END) pip install --upgrade -r $(REQUIREMENTS) diff --git a/httpie/cli.py b/httpie/cli.py index f03bb46be4..e893af25cf 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -310,8 +310,9 @@ def _split_lines(self, text, width): dest='output_file', metavar='FILE', help=""" - Save output to FILE. If --download is set, then only the response body is - saved to the file. Other parts of the HTTP exchange are printed to stderr. + Save output to FILE instead of stdout. If --download is also set, then only + the response body is saved to FILE. Other parts of the HTTP exchange are + printed to stderr. """ diff --git a/httpie/core.py b/httpie/core.py index e6875524a8..2079a9146b 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -204,4 +204,8 @@ def _error(msg, *args, **kwargs): if downloader and not downloader.finished: downloader.failed() + if (not isinstance(args, list) and args.output_file and + args.output_file_specified): + args.output_file.close() + return exit_status diff --git a/httpie/input.py b/httpie/input.py index 5381097870..232e2d9e8f 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -171,12 +171,10 @@ def _setup_standard_streams(self): Modify `env.stdout` and `env.stdout_isatty` based on args, if needed. """ - if not self.env.stdout_isatty and self.args.output_file: - self.error('Cannot use --output, -o with redirected output.') - + self.args.output_file_specified = bool(self.args.output_file) if self.args.download: # FIXME: Come up with a cleaner solution. - if not self.env.stdout_isatty: + if not self.args.output_file and not self.env.stdout_isatty: # Use stdout as the download output file. self.args.output_file = self.env.stdout # With `--download`, we write everything that would normally go to diff --git a/tests/test_output.py b/tests/test_output.py index 483eeb3990..ac58315f51 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -1,10 +1,30 @@ +import os +from tempfile import gettempdir + import pytest from utils import TestEnvironment, http, HTTP_OK, COLOR, CRLF from httpie import ExitStatus +from httpie.compat import urlopen from httpie.output.formatters.colors import get_lexer +@pytest.mark.parametrize('stdout_isatty', [(True,), (False,)]) +def test_output_option(httpbin, stdout_isatty): + output_filename = os.path.join(gettempdir(), test_output_option.__name__) + url = httpbin + '/robots.txt' + + r = http('--output', output_filename, url, + env=TestEnvironment(stdout_isatty=stdout_isatty)) + assert r == '' + + expected_body = urlopen(url).read().decode() + with open(output_filename, 'r') as f: + actual_body = f.read() + + assert actual_body == expected_body + + class TestVerboseFlag: def test_verbose(self, httpbin): r = http('--verbose', diff --git a/tests/test_windows.py b/tests/test_windows.py index 91669f5c30..ca5e2bb611 100644 --- a/tests/test_windows.py +++ b/tests/test_windows.py @@ -22,7 +22,9 @@ class TestFakeWindows: def test_output_file_pretty_not_allowed_on_windows(self, httpbin): env = TestEnvironment(is_windows=True) output_file = os.path.join( - tempfile.gettempdir(), '__httpie_test_output__') + tempfile.gettempdir(), + self.test_output_file_pretty_not_allowed_on_windows.__name__ + ) r = http('--output', output_file, '--pretty=all', 'GET', httpbin.url + '/get', env=env, error_exit_ok=True) From 2a25d71aa4929ef9cb0d5d993ec9f25160d25d65 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 21:10:54 +0800 Subject: [PATCH 0177/1182] Refactored main() into program() + main() --- httpie/core.py | 166 ++++++++++++++++++++++++++----------------- tests/test_errors.py | 9 +-- 2 files changed, 107 insertions(+), 68 deletions(-) diff --git a/httpie/core.py b/httpie/core.py index 2079a9146b..677f4217a3 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -68,41 +68,21 @@ def decode_args(args, stdin_encoding): ] -def main(args=sys.argv[1:], env=Environment(), error=None): - """Run the main program and write the output to ``env.stdout``. - - Return exit status code. - +def program(args, env, log_error): """ - args = decode_args(args, env.stdin_encoding) - plugin_manager.load_installed_plugins() + The main program without error handling - from httpie.cli import parser + :param args: parsed args (argparse.Namespace) + :type env: Environment + :param log_error: error log function + :return: status code - if env.config.default_options: - args = env.config.default_options + args - - def _error(msg, *args, **kwargs): - msg = msg % args - level = kwargs.get('level', 'error') - env.stderr.write('\nhttp: %s: %s\n' % (level, msg)) - - if error is None: - error = _error - - debug = '--debug' in args - traceback = debug or '--traceback' in args + """ exit_status = ExitStatus.OK - - if debug: - print_debug_info(env) - if args == ['--debug']: - return exit_status - downloader = None - try: - args = parser.parse_args(args=args, env=env) + show_traceback = args.debug or args.traceback + try: if args.download: args.follow = True # --download implies --follow. downloader = Downloader( @@ -126,10 +106,10 @@ def _error(msg, *args, **kwargs): follow=args.follow ) if not env.stdout_isatty and exit_status != ExitStatus.OK: - error('HTTP %s %s', - response.raw.status, - response.raw.reason, - level='warning') + log_error( + 'HTTP %s %s', response.raw.status, response.raw.reason, + level='warning' + ) write_stream_kwargs = { 'stream': build_output_stream( @@ -148,7 +128,7 @@ def _error(msg, *args, **kwargs): else: write_stream(**write_stream_kwargs) except IOError as e: - if not traceback and e.errno == errno.EPIPE: + if not show_traceback and e.errno == errno.EPIPE: # Ignore broken pipes unless --traceback. env.stderr.write('\n') else: @@ -165,47 +145,105 @@ def _error(msg, *args, **kwargs): downloader.finish() if downloader.interrupted: exit_status = ExitStatus.ERROR - error('Incomplete download: size=%d; downloaded=%d' % ( + log_error('Incomplete download: size=%d; downloaded=%d' % ( downloader.status.total_size, downloader.status.downloaded )) + return exit_status + + finally: + if downloader and not downloader.finished: + downloader.failed() + + if (not isinstance(args, list) and args.output_file and + args.output_file_specified): + args.output_file.close() + + +def main(args=sys.argv[1:], env=Environment(), custom_log_error=None): + """ + The main function. + + Pre-process args, handle some special type of invocations, and run the main + program with error handling. + + Return exit status code. + + """ + args = decode_args(args, env.stdin_encoding) + plugin_manager.load_installed_plugins() + def log_error(msg, *args, level='error'): + msg = msg % args + env.stderr.write('\nhttp: %s: %s\n' % (level, msg)) + + from httpie.cli import parser + + if env.config.default_options: + args = env.config.default_options + args + + if custom_log_error: + log_error = custom_log_error + + include_debug_info = '--debug' in args + include_traceback = include_debug_info or '--traceback' in args + + if include_debug_info: + print_debug_info(env) + if args == ['--debug']: + return ExitStatus.OK + + exit_status = ExitStatus.OK + + try: + parsed_args = parser.parse_args(args=args, env=env) except KeyboardInterrupt: - if traceback: - raise env.stderr.write('\n') + if include_traceback: + raise exit_status = ExitStatus.ERROR except SystemExit as e: if e.code != ExitStatus.OK: - if traceback: + env.stderr.write('\n') + if include_traceback: raise + exit_status = ExitStatus.ERROR + else: + try: + exit_status = program( + args=parsed_args, + env=env, + log_error=log_error, + ) + except KeyboardInterrupt: env.stderr.write('\n') + if include_traceback: + raise + exit_status = ExitStatus.ERROR + except SystemExit as e: + if e.code != ExitStatus.OK: + env.stderr.write('\n') + if include_traceback: + raise + exit_status = ExitStatus.ERROR + except requests.Timeout: + exit_status = ExitStatus.ERROR_TIMEOUT + log_error('Request timed out (%ss).', parsed_args.timeout) + except requests.TooManyRedirects: + exit_status = ExitStatus.ERROR_TOO_MANY_REDIRECTS + log_error('Too many redirects (--max-redirects=%s).', + parsed_args.max_redirects) + except Exception as e: + # TODO: Further distinction between expected and unexpected errors. + msg = str(e) + if hasattr(e, 'request'): + request = e.request + if hasattr(request, 'url'): + msg += ' while doing %s request to URL: %s' % ( + request.method, request.url) + log_error('%s: %s', type(e).__name__, msg) + if include_traceback: + raise exit_status = ExitStatus.ERROR - except requests.Timeout: - exit_status = ExitStatus.ERROR_TIMEOUT - error('Request timed out (%ss).', args.timeout) - except requests.TooManyRedirects: - exit_status = ExitStatus.ERROR_TOO_MANY_REDIRECTS - error('Too many redirects (--max-redirects=%s).', args.max_redirects) - except Exception as e: - # TODO: Better distinction between expected and unexpected errors. - if traceback: - raise - msg = str(e) - if hasattr(e, 'request'): - request = e.request - if hasattr(request, 'url'): - msg += ' while doing %s request to URL: %s' % ( - request.method, request.url) - error('%s: %s', type(e).__name__, msg) - exit_status = ExitStatus.ERROR - - finally: - if downloader and not downloader.finished: - downloader.failed() - - if (not isinstance(args, list) and args.output_file and - args.output_file_specified): - args.output_file.close() return exit_status diff --git a/tests/test_errors.py b/tests/test_errors.py index 1d7cf24c82..040e889c13 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -3,6 +3,7 @@ from requests import Request, Timeout from requests.exceptions import ConnectionError +from httpie import ExitStatus from httpie.core import main error_msg = None @@ -17,8 +18,8 @@ def error(msg, *args, **kwargs): exc = ConnectionError('Connection aborted') exc.request = Request(method='GET', url='http://www.google.com') get_response.side_effect = exc - ret = main(['--ignore-stdin', 'www.google.com'], error=error) - assert ret == 1 + ret = main(['--ignore-stdin', 'www.google.com'], custom_log_error=error) + assert ret == ExitStatus.ERROR assert error_msg == ( 'ConnectionError: ' 'Connection aborted while doing GET request to URL: ' @@ -43,6 +44,6 @@ def error(msg, *args, **kwargs): exc = Timeout('Request timed out') exc.request = Request(method='GET', url='http://www.google.com') get_response.side_effect = exc - ret = main(['--ignore-stdin', 'www.google.com'], error=error) - assert ret == 2 + ret = main(['--ignore-stdin', 'www.google.com'], custom_log_error=error) + assert ret == ExitStatus.ERROR_TIMEOUT assert error_msg == 'Request timed out (30s).' From e2751e5fa38b5e5cd53a607e5e82dd58ae9904bf Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 21:27:26 +0800 Subject: [PATCH 0178/1182] Fixed args for Python 2.x --- httpie/core.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/httpie/core.py b/httpie/core.py index 677f4217a3..97bf533f36 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -173,8 +173,10 @@ def main(args=sys.argv[1:], env=Environment(), custom_log_error=None): args = decode_args(args, env.stdin_encoding) plugin_manager.load_installed_plugins() - def log_error(msg, *args, level='error'): + def log_error(msg, *args, **kwargs): msg = msg % args + level = kwargs.get('level', 'error') + assert level in ['error', 'warning'] env.stderr.write('\nhttp: %s: %s\n' % (level, msg)) from httpie.cli import parser From 0d2d24eac7272dda521198f3a7ea85a4d6af9a50 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 21:37:26 +0800 Subject: [PATCH 0179/1182] Copy --- httpie/cli.py | 6 +++--- httpie/core.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index e893af25cf..540a04eddf 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -577,7 +577,7 @@ def _split_lines(self, text, width): action='store_true', default=False, help=""" - Prints exception traceback should one occur. + Prints the exception traceback should one occur. """ ) @@ -586,8 +586,8 @@ def _split_lines(self, text, width): action='store_true', default=False, help=""" - Prints exception traceback should one occur, and also other information - that is useful for debugging HTTPie itself and for reporting bugs. + Prints the exception traceback should one occur, as well as other + information useful for debugging HTTPie itself and for reporting bugs. """ ) diff --git a/httpie/core.py b/httpie/core.py index 97bf533f36..b89b5bd02a 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -164,8 +164,8 @@ def main(args=sys.argv[1:], env=Environment(), custom_log_error=None): """ The main function. - Pre-process args, handle some special type of invocations, and run the main - program with error handling. + Pre-process args, handle some special types of invocations, + and run the main program with error handling. Return exit status code. From d30e28c2c7f94c6691b970da0f33f1d6a07e4bc6 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 23:11:06 +0800 Subject: [PATCH 0180/1182] Test suite improvements --- tests/utils.py | 109 ++++++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 47 deletions(-) diff --git a/tests/utils.py b/tests/utils.py index 5efdd011bb..357f3f5786 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -6,7 +6,6 @@ import sys import time import json -import shutil import tempfile import httpie @@ -30,11 +29,11 @@ def no_content_type(headers): return ( - 'Content-Type' not in headers + 'Content-Type' not in headers or # We need to do also this because of this issue: # # TODO: remove this function once the issue is if fixed - or headers['Content-Type'] == 'text/plain' + headers['Content-Type'] == 'text/plain' ) @@ -53,68 +52,82 @@ class TestEnvironment(Environment): stdout_isatty = True is_windows = False - _shutil_rmtree = shutil.rmtree # needed by __del__ (would get gc'd) - def __init__(self, **kwargs): - if 'stdout' not in kwargs: - kwargs['stdout'] = tempfile.TemporaryFile('w+b') - + kwargs['stdout'] = tempfile.TemporaryFile( + mode='w+b', + prefix='httpie_stdout' + ) if 'stderr' not in kwargs: - kwargs['stderr'] = tempfile.TemporaryFile('w+t') - - self.delete_config_dir = False - if 'config_dir' not in kwargs: - kwargs['config_dir'] = mk_config_dir() - self.delete_config_dir = True - + kwargs['stderr'] = tempfile.TemporaryFile( + mode='w+t', + prefix='httpie_stderr' + ) super(TestEnvironment, self).__init__(**kwargs) + self._delete_config_dir = False + + @property + def config(self): + if not self.config_dir.startswith(tempfile.gettempdir()): + self.config_dir = mk_config_dir() + self._delete_config_dir = True + return super(TestEnvironment, self).config + + def cleanup(self): + if self._delete_config_dir: + assert self.config_dir.startswith(tempfile.gettempdir()) + from shutil import rmtree + rmtree(self.config_dir) def __del__(self): - if self.delete_config_dir: - self._shutil_rmtree(self.config_dir) + try: + self.cleanup() + except Exception: + pass def http(*args, **kwargs): + # noinspection PyUnresolvedReferences """ - Run HTTPie and capture stderr/out and exit status. + Run HTTPie and capture stderr/out and exit status. - Invoke `httpie.core.main()` with `args` and `kwargs`, - and return a `CLIResponse` subclass instance. + Invoke `httpie.core.main()` with `args` and `kwargs`, + and return a `CLIResponse` subclass instance. - The return value is either a `StrCLIResponse`, or `BytesCLIResponse` - if unable to decode the output. + The return value is either a `StrCLIResponse`, or `BytesCLIResponse` + if unable to decode the output. - The response has the following attributes: + The response has the following attributes: - `stdout` is represented by the instance itself (print r) - `stderr`: text written to stderr - `exit_status`: the exit status - `json`: decoded JSON (if possible) or `None` + `stdout` is represented by the instance itself (print r) + `stderr`: text written to stderr + `exit_status`: the exit status + `json`: decoded JSON (if possible) or `None` - Exceptions are propagated. + Exceptions are propagated. - If you pass ``error_exit_ok=True``, then error exit statuses - won't result into an exception. + If you pass ``error_exit_ok=True``, then error exit statuses + won't result into an exception. - Example: + Example: - $ http --auth=user:password GET httpbin.org/basic-auth/user/password + $ http --auth=user:password GET httpbin.org/basic-auth/user/password - >>> r = http('-a', 'user:pw', 'httpbin.org/basic-auth/user/pw') - >>> type(r) == StrCLIResponse - True - >>> r.exit_status - 0 - >>> r.stderr - '' - >>> 'HTTP/1.1 200 OK' in r - True - >>> r.json == {'authenticated': True, 'user': 'user'} - True + >>> httpbin = getfixture('httpbin') + >>> r = http('-a', 'user:pw', httpbin.url + '/basic-auth/user/pw') + >>> type(r) == StrCLIResponse + True + >>> r.exit_status + 0 + >>> r.stderr + '' + >>> 'HTTP/1.1 200 OK' in r + True + >>> r.json == {'authenticated': True, 'user': 'user'} + True - """ + """ error_exit_ok = kwargs.pop('error_exit_ok', False) env = kwargs.get('env') if not env: @@ -174,6 +187,7 @@ def dump_stderr(): finally: stdout.close() stderr.close() + env.cleanup() class BaseCLIResponse(object): @@ -221,8 +235,8 @@ def json(self): 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: @@ -238,4 +252,5 @@ def json(self): def mk_config_dir(): - return tempfile.mkdtemp(prefix='httpie_test_config_dir_') + dirname = tempfile.mkdtemp(prefix='httpie_config_') + return dirname From 5e87a2d7e5e122144684fc06299be3a094c9bd00 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 23:13:45 +0800 Subject: [PATCH 0181/1182] Cleanup --- tests/utils.py | 57 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/tests/utils.py b/tests/utils.py index 357f3f5786..466e2f5880 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -89,45 +89,44 @@ def __del__(self): def http(*args, **kwargs): # noinspection PyUnresolvedReferences """ - Run HTTPie and capture stderr/out and exit status. + Run HTTPie and capture stderr/out and exit status. - Invoke `httpie.core.main()` with `args` and `kwargs`, - and return a `CLIResponse` subclass instance. + Invoke `httpie.core.main()` with `args` and `kwargs`, + and return a `CLIResponse` subclass instance. - The return value is either a `StrCLIResponse`, or `BytesCLIResponse` - if unable to decode the output. + The return value is either a `StrCLIResponse`, or `BytesCLIResponse` + if unable to decode the output. - The response has the following attributes: + The response has the following attributes: - `stdout` is represented by the instance itself (print r) - `stderr`: text written to stderr - `exit_status`: the exit status - `json`: decoded JSON (if possible) or `None` + `stdout` is represented by the instance itself (print r) + `stderr`: text written to stderr + `exit_status`: the exit status + `json`: decoded JSON (if possible) or `None` - Exceptions are propagated. + Exceptions are propagated. - If you pass ``error_exit_ok=True``, then error exit statuses - won't result into an exception. + If you pass ``error_exit_ok=True``, then error exit statuses + won't result into an exception. - Example: + Example: - $ http --auth=user:password GET httpbin.org/basic-auth/user/password + $ http --auth=user:password GET httpbin.org/basic-auth/user/password - >>> httpbin = getfixture('httpbin') - >>> r = http('-a', 'user:pw', httpbin.url + '/basic-auth/user/pw') - >>> type(r) == StrCLIResponse - True - >>> r.exit_status - 0 - >>> r.stderr - '' - >>> 'HTTP/1.1 200 OK' in r - True - >>> r.json == {'authenticated': True, 'user': 'user'} - True + >>> httpbin = getfixture('httpbin') + >>> r = http('-a', 'user:pw', httpbin.url + '/basic-auth/user/pw') + >>> type(r) == StrCLIResponse + True + >>> r.exit_status + 0 + >>> r.stderr + '' + >>> 'HTTP/1.1 200 OK' in r + True + >>> r.json == {'authenticated': True, 'user': 'user'} + True - - """ + """ error_exit_ok = kwargs.pop('error_exit_ok', False) env = kwargs.get('env') if not env: From 56afd1adb950d7aefd8d45a8e90c16f5e397757b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 23:22:50 +0800 Subject: [PATCH 0182/1182] Test suite cleanup --- tests/test_defaults.py | 4 +- tests/test_sessions.py | 9 ++- tests/utils.py | 149 ++++++++++++++++++----------------------- 3 files changed, 72 insertions(+), 90 deletions(-) diff --git a/tests/test_defaults.py b/tests/test_defaults.py index 30039df690..a82a1151b8 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -2,7 +2,7 @@ Tests for the provided defaults regarding HTTP method, and --json vs. --form. """ -from utils import TestEnvironment, http, HTTP_OK, no_content_type +from utils import TestEnvironment, http, HTTP_OK from fixtures import FILE_PATH @@ -46,7 +46,7 @@ def test_GET_no_data_no_auto_headers(self, httpbin): r = http('GET', httpbin.url + '/headers') assert HTTP_OK in r assert r.json['headers']['Accept'] == '*/*' - assert no_content_type(r.json['headers']) + assert 'Content-Type' not in r.json['headers'] def test_POST_no_data_no_auto_headers(self, httpbin): # JSON headers shouldn't be automatically set for POST with no data. diff --git a/tests/test_sessions.py b/tests/test_sessions.py index f59c36a005..4b9874e294 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -7,8 +7,7 @@ import pytest from httpie.plugins.builtin import HTTPBasicAuth -from utils import TestEnvironment, mk_config_dir, http, HTTP_OK, \ - no_content_type +from utils import TestEnvironment, mk_config_dir, http, HTTP_OK from fixtures import UNICODE @@ -126,7 +125,7 @@ def test_session_ignored_header_prefixes(self, httpbin): r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env()) assert HTTP_OK in r2 - assert no_content_type(r2.json['headers']) + assert 'Content-Type' not in r2.json['headers'] assert 'If-Unmodified-Since' not in r2.json['headers'] def test_session_by_path(self, httpbin): @@ -158,8 +157,8 @@ def test_session_unicode(self, httpbin): 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 diff --git a/tests/utils.py b/tests/utils.py index 466e2f5880..31aef4ee28 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,7 +1,5 @@ # coding=utf-8 -"""Utilities used by HTTPie tests. - -""" +"""Utilities for HTTPie test suite.""" import os import sys import time @@ -15,8 +13,6 @@ TESTS_ROOT = os.path.abspath(os.path.dirname(__file__)) - - CRLF = '\r\n' COLOR = '\x1b[' HTTP_OK = '200 OK' @@ -27,14 +23,9 @@ ) -def no_content_type(headers): - return ( - 'Content-Type' not in headers or - # We need to do also this because of this issue: - # - # TODO: remove this function once the issue is if fixed - headers['Content-Type'] == 'text/plain' - ) +def mk_config_dir(): + dirname = tempfile.mkdtemp(prefix='httpie_config_') + return dirname def add_auth(url, auth): @@ -43,10 +34,7 @@ def add_auth(url, auth): class TestEnvironment(Environment): - """ - Environment subclass with reasonable defaults suitable for testing. - - """ + """Environment subclass with reasonable defaults for testing.""" colors = 0 stdin_isatty = True, stdout_isatty = True @@ -86,6 +74,67 @@ def __del__(self): pass +class BaseCLIResponse(object): + """ + Represents the result of simulated `$ http' invocation via `http()`. + + Holds and provides access to: + + - stdout output: print(self) + - stderr output: print(self.stderr) + - exit_status output: print(self.exit_status) + + """ + stderr = None + json = None + exit_status = None + + +class BytesCLIResponse(bytes, BaseCLIResponse): + """ + Used as a fallback when a StrCLIResponse cannot be used. + + E.g. when the output contains binary data or when it is colorized. + + `.json` will always be None. + + """ + + +class StrCLIResponse(str, BaseCLIResponse): + + @property + def json(self): + """ + Return deserialized JSON body, if one included in the output + and is parseable. + + """ + if not hasattr(self, '_json'): + self._json = None + # De-serialize JSON body if possible. + if COLOR in self: + # Colorized output cannot be parsed. + pass + elif self.strip().startswith('{'): + # Looks like JSON body. + self._json = json.loads(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: + j = self.strip()[self.strip().rindex('\r\n\r\n'):] + except ValueError: + pass + else: + try: + self._json = json.loads(j) + except ValueError: + pass + return self._json + + def http(*args, **kwargs): # noinspection PyUnresolvedReferences """ @@ -187,69 +236,3 @@ def dump_stderr(): stdout.close() stderr.close() env.cleanup() - - -class BaseCLIResponse(object): - """ - Represents the result of simulated `$ http' invocation via `http()`. - - Holds and provides access to: - - - stdout output: print(self) - - stderr output: print(self.stderr) - - exit_status output: print(self.exit_status) - - """ - stderr = None - json = None - exit_status = None - - -class BytesCLIResponse(bytes, BaseCLIResponse): - """ - Used as a fallback when a StrCLIResponse cannot be used. - - E.g. when the output contains binary data or when it is colorized. - - `.json` will always be None. - - """ - - -class StrCLIResponse(str, BaseCLIResponse): - - @property - def json(self): - """ - Return deserialized JSON body, if one included in the output - and is parseable. - - """ - if not hasattr(self, '_json'): - self._json = None - # De-serialize JSON body if possible. - if COLOR in self: - # Colorized output cannot be parsed. - pass - elif self.strip().startswith('{'): - # Looks like JSON body. - self._json = json.loads(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: - j = self.strip()[self.strip().rindex('\r\n\r\n'):] - except ValueError: - pass - else: - try: - self._json = json.loads(j) - except ValueError: - pass - return self._json - - -def mk_config_dir(): - dirname = tempfile.mkdtemp(prefix='httpie_config_') - return dirname From 20f01709ea34acc963281cbcb969a6ca370d409d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 1 Mar 2016 23:48:13 +0800 Subject: [PATCH 0183/1182] Mention URL escaping Closes #311 --- README.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 22f97a4458..abbbf3dc58 100644 --- a/README.rst +++ b/README.rst @@ -288,17 +288,17 @@ If the port is omitted, then port 80 is assumed. If you find yourself manually constructing URLs with **querystring parameters** on the terminal, you may appreciate the ``param==value`` syntax for appending URL parameters so that you don't have to worry about escaping the ``&`` -separators. To search for ``HTTPie`` on Google Images you could use this -command: +separators and as well as special character in parameter values. +To search for ``HTTPie logo`` on Google Images you could use this command: .. code-block:: bash - $ http GET www.google.com search==HTTPie tbm==isch + $ http www.google.com search=='HTTPie logo' tbm==isch .. code-block:: http - GET /?search=HTTPie&tbm=isch HTTP/1.1 + GET /?search=HTTPie+logo&tbm=isch HTTP/1.1 ============= From d4067fcb6d780cc2d5e6279b16d877573f238691 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 00:31:00 +0800 Subject: [PATCH 0184/1182] Added a short timeout for test requests --- README.rst | 8 +++++--- tests/utils.py | 9 +++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index abbbf3dc58..4e64d0c027 100644 --- a/README.rst +++ b/README.rst @@ -287,9 +287,11 @@ If the port is omitted, then port 80 is assumed. If you find yourself manually constructing URLs with **querystring parameters** on the terminal, you may appreciate the ``param==value`` syntax for appending -URL parameters so that you don't have to worry about escaping the ``&`` -separators and as well as special character in parameter values. -To search for ``HTTPie logo`` on Google Images you could use this command: +URL parameters. With that, you don't have to worry about escaping the ``&`` +separators for you shell. Also, special characters in parameter values, +will also automatically escaped (HTTPie otherwise expects the URL to be +already escaped). To search for ``HTTPie logo`` on Google Images you could use +this command: .. code-block:: bash diff --git a/tests/utils.py b/tests/utils.py index 31aef4ee28..700efc9037 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -185,8 +185,13 @@ def http(*args, **kwargs): stderr = env.stderr args = list(args) - if '--debug' not in args and '--traceback' not in args: - args = ['--traceback'] + args + extra_args = [] + if '--debug' not in args: + if '--traceback' not in args: + extra_args.append('--traceback') + if '--timeout' not in ' '.join(args): + extra_args.append('--timeout=3') + args = extra_args + args def dump_stderr(): stderr.seek(0) From 7fd46e0b0df416ecafcc21fddcd512045bd9b464 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 01:02:11 +0800 Subject: [PATCH 0185/1182] Cleanup --- tests/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/utils.py b/tests/utils.py index 700efc9037..e54969e726 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -189,7 +189,7 @@ def http(*args, **kwargs): if '--debug' not in args: if '--traceback' not in args: extra_args.append('--traceback') - if '--timeout' not in ' '.join(args): + if not any('--timeout' in arg for arg in args): extra_args.append('--timeout=3') args = extra_args + args From f6824f7ade69475cb91a47119d7eac01dde0456d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 02:53:23 +0800 Subject: [PATCH 0186/1182] Cleanup --- httpie/cli.py | 2 -- httpie/client.py | 2 +- httpie/models.py | 2 +- tests/test_ssl.py | 4 ++-- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 540a04eddf..6e4e2be3c4 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -53,11 +53,9 @@ def _split_lines(self, text, width): https://github.com/jkbrzt/httpie/issues """), - usage='see http --help' ) - ####################################################################### # Positional arguments. ####################################################################### diff --git a/httpie/client.py b/httpie/client.py index 482f9dce29..4ff4efb8b4 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -38,7 +38,6 @@ def get_requests_session(): def get_response(args, config_dir): """Send the request and return a `request.Response`.""" - requests_session = get_requests_session() requests_session.max_redirects = args.max_redirects @@ -64,6 +63,7 @@ def dump_request(kwargs): % pformat(kwargs)) + def encode_headers(headers): # This allows for unicode headers which is non-standard but practical. # See: https://github.com/jkbrzt/httpie/issues/212 diff --git a/httpie/models.py b/httpie/models.py index 3f273b4eab..ef3594318d 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -48,7 +48,7 @@ def iter_body(self, chunk_size=1): def iter_lines(self, chunk_size): return ((line, b'\n') for line in self._orig.iter_lines(chunk_size)) - #noinspection PyProtectedMember + # noinspection PyProtectedMember @property def headers(self): original = self._orig.raw._original_response diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 0fda410635..d23af11aa8 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -18,7 +18,7 @@ CA_BUNDLE = pytest_httpbin.certs.where() -class TestClientSSLCertHandling(object): +class TestClientCert: def test_cert_file_not_found(self, httpbin_secure): r = http(httpbin_secure + '/get', @@ -54,7 +54,7 @@ def test_cert_pem(self, httpbin_secure): assert HTTP_OK in r -class TestServerSSLCertHandling(object): +class TestServerCert: def test_self_signed_server_cert_by_default_raises_ssl_error( self, httpbin_secure): From ae7008ee9658825686c1342e5fc399a37c4b1f12 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 09:33:43 +0800 Subject: [PATCH 0187/1182] Appveyor --- appveyor.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 863cd0d1d9..c6224cf78d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,11 +7,13 @@ environment: init: - "ECHO %PYTHON%" - ps: "ls C:/Python*" -#install: + +install: # - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') # - "%PYTHON%/python.exe C:/get-pip.py" # - "%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" From c2dae62af0331c4d5bb736d32ac2d59a6098c6c0 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 09:37:58 +0800 Subject: [PATCH 0188/1182] Appveyor: added Python 3.5 build --- appveyor.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c6224cf78d..1b087769d1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,13 +4,12 @@ environment: matrix: - PYTHON: "C:/Python27" - PYTHON: "C:/Python34" + - PYTHON: "C:/Python35" init: - "ECHO %PYTHON%" - ps: "ls C:/Python*" install: -# - ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py') -# - "%PYTHON%/python.exe C:/get-pip.py" # - "%PYTHON%/Scripts/pip.exe install -U pip setuptools" - "%PYTHON%/Scripts/pip.exe install -e ." From a2dca1e3bba6d9ea59b09dbef34db55808b4ad6f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 09:44:39 +0800 Subject: [PATCH 0189/1182] CI --- .travis.yml | 1 + appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f8f8dd27f1..82c7536d00 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ python: - 2.6 - 2.7 - pypy + - 3.4 - 3.5 - pypy3 diff --git a/appveyor.yml b/appveyor.yml index 1b087769d1..c8f559ae3d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,7 +10,7 @@ init: - ps: "ls C:/Python*" install: -# - "%PYTHON%/Scripts/pip.exe install -U pip setuptools" + - "%PYTHON%/Scripts/pip.exe install -U pip setuptools" - "%PYTHON%/Scripts/pip.exe install -e ." test_script: From fb85509e917836c7bfd18127d5908526b2a66e5e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 09:58:50 +0800 Subject: [PATCH 0190/1182] CI --- appveyor.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c8f559ae3d..d5be13447e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,16 +1,20 @@ # https://ci.appveyor.com/project/jkbrzt/httpie build: false + environment: matrix: - PYTHON: "C:/Python27" - - PYTHON: "C:/Python34" + # Python 3.4 has outdated pip + # - PYTHON: "C:/Python34" - PYTHON: "C:/Python35" + init: - "ECHO %PYTHON%" - ps: "ls C:/Python*" install: - - "%PYTHON%/Scripts/pip.exe install -U pip setuptools" + # FIXME: updating pip fails with PermissionError + # - "%PYTHON%/Scripts/pip.exe install -U pip setuptools" - "%PYTHON%/Scripts/pip.exe install -e ." test_script: From c73dcaf63d69e10620cf1da1d971d49078004afd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 10:08:20 +0800 Subject: [PATCH 0191/1182] CI --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 82c7536d00..f678253670 100644 --- a/.travis.yml +++ b/.travis.yml @@ -74,6 +74,6 @@ notifications: urls: # https://gitter.im/jkbrzt/httpie - https://webhooks.gitter.im/e/c42fcd359a110d02830b - on_success: change # options: [always|never|change] default: always + on_success: always # options: [always|never|change] default: always on_failure: always # options: [always|never|change] default: always - on_start: never # options: [always|never|change] default: always + on_start: always # options: [always|never|change] default: always From 38e8ef14ec8d4f2e6e8040b4ab7f871e75ff088c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 10:35:40 +0800 Subject: [PATCH 0192/1182] Run positive tests first Trying to debug failing SSL tests on Travis - kevin1024/pytest-httpbin#32 --- tests/test_ssl.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index d23af11aa8..ac2fed3b7b 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -20,6 +20,19 @@ class TestClientCert: + def test_cert_and_key(self, httpbin_secure): + r = http(httpbin_secure + '/get', + '--verify', CA_BUNDLE, + '--cert', CLIENT_CERT, + '--cert-key', CLIENT_KEY) + assert HTTP_OK in r + + def test_cert_pem(self, httpbin_secure): + r = http(httpbin_secure + '/get', + '--verify', CA_BUNDLE, + '--cert', CLIENT_PEM) + assert HTTP_OK in r + def test_cert_file_not_found(self, httpbin_secure): r = http(httpbin_secure + '/get', '--verify', CA_BUNDLE, @@ -40,27 +53,8 @@ def test_cert_ok_but_missing_key(self, httpbin_secure): '--verify', CA_BUNDLE, '--cert', CLIENT_CERT) - def test_cert_and_key(self, httpbin_secure): - r = http(httpbin_secure + '/get', - '--verify', CA_BUNDLE, - '--cert', CLIENT_CERT, - '--cert-key', CLIENT_KEY) - assert HTTP_OK in r - - def test_cert_pem(self, httpbin_secure): - r = http(httpbin_secure + '/get', - '--verify', CA_BUNDLE, - '--cert', CLIENT_PEM) - assert HTTP_OK in r - class TestServerCert: - - def test_self_signed_server_cert_by_default_raises_ssl_error( - self, httpbin_secure): - with pytest.raises(SSLError): - http(httpbin_secure.url + '/get') - def test_verify_no_OK(self, httpbin_secure): r = http(httpbin_secure.url + '/get', '--verify=no') assert HTTP_OK in r @@ -70,6 +64,11 @@ def test_verify_custom_ca_bundle_path( r = http(httpbin_secure.url + '/get', '--verify', CA_BUNDLE) assert HTTP_OK in r + def test_self_signed_server_cert_by_default_raises_ssl_error( + self, httpbin_secure): + with pytest.raises(SSLError): + http(httpbin_secure.url + '/get') + def test_verify_custom_ca_bundle_invalid_path(self, httpbin_secure): with pytest.raises(SSLError): http(httpbin_secure.url + '/get', '--verify', '/__not_found__') From dc4da527db3bbc3c9907ee0f72f5f48d3d4b4e2a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 12:12:05 +0800 Subject: [PATCH 0193/1182] Added --ssl= Closes #98 --- CHANGELOG.rst | 2 ++ README.rst | 16 ++++++++++++ httpie/cli.py | 65 ++++++++++++++++++++++++++++++----------------- httpie/client.py | 26 +++++++++++++++++-- httpie/input.py | 15 +++++++++++ tests/test_ssl.py | 21 +++++++++++++++ 6 files changed, 119 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4fde5aaf5b..c790dfea0c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,8 @@ This project adheres to `Semantic Versioning `_. ------------------------- * Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests +* Added ``--ssl=`` to specify SSL/TLS the desired protocol version + to use for HTTPS requests. * Added ``--show-redirects, -R`` to show intermediate responses with ``--follow`` * Added ``--max-redirects`` (default 30) * Added ``-A`` as short name for ``--auth-type`` diff --git a/README.rst b/README.rst index 4e64d0c027..8784fa3659 100644 --- a/README.rst +++ b/README.rst @@ -730,6 +730,22 @@ path of the key file with ``--cert-key``: $ http --cert=client.crt --cert-key=client.key https://example.org +----------- +SSL version +----------- + +Use the ``--ssl=`` 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 +available set of protocols may vary depending your on OpenSSL installation.) + +.. code-block:: bash + + # Specify the vulnerable SSL v3 protocol to talk to an outdated server: + $ http --ssl=ssl3 https://vulnerable.example.org + + ---------------------------- SNI (Server Name Indication) ---------------------------- diff --git a/httpie/cli.py b/httpie/cli.py index 6e4e2be3c4..771126cbb8 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -20,7 +20,7 @@ OUT_RESP_BODY, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, SessionNameValidator, - readable_file_arg) + readable_file_arg, SSL_VERSION_ARG_MAPPING) class HTTPieHelpFormatter(RawDescriptionHelpFormatter): @@ -485,29 +485,6 @@ def _split_lines(self, text, width): """ ) -network.add_argument( - '--cert', - default=None, - type=readable_file_arg, - help=""" - You can specify a local cert to use as client side SSL certificate. - This file may either contain both private key and certificate or you may - specify --cert-key separately. - - """ -) - -network.add_argument( - '--cert-key', - default=None, - type=readable_file_arg, - help=""" - The private key to use with SSL. Only needed if --cert is given and the - certificate file does not contain the private key. - - """ -) - network.add_argument( '--timeout', type=float, @@ -537,6 +514,46 @@ def _split_lines(self, text, width): ) +####################################################################### +# SSL +####################################################################### + +ssl = parser.add_argument_group(title='SSL') +ssl.add_argument( + '--ssl', # TODO: Maybe something more general, such as --secure-protocol? + dest='ssl_version', + choices=list(sorted(SSL_VERSION_ARG_MAPPING.keys())), + help=""" + 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. Available protocols + may vary depending on OpenSSL installation (only the supported ones + are shown here). + """ +) +ssl.add_argument( + '--cert', + default=None, + type=readable_file_arg, + help=""" + You can specify a local cert to use as client side SSL certificate. + This file may either contain both private key and certificate or you may + specify --cert-key separately. + + """ +) + +ssl.add_argument( + '--cert-key', + default=None, + type=readable_file_arg, + help=""" + The private key to use with SSL. Only needed if --cert is given and the + certificate file does not contain the private key. + + """ +) + ####################################################################### # Troubleshooting ####################################################################### diff --git a/httpie/client.py b/httpie/client.py index 4ff4efb8b4..8c0b6fe851 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -3,11 +3,13 @@ from pprint import pformat import requests +from requests.adapters import HTTPAdapter from requests.packages import urllib3 from httpie import sessions from httpie import __version__ from httpie.compat import str +from httpie.input import SSL_VERSION_ARG_MAPPING from httpie.plugins import plugin_manager @@ -27,8 +29,23 @@ DEFAULT_UA = 'HTTPie/%s' % __version__ -def get_requests_session(): +class HTTPieHTTPAdapter(HTTPAdapter): + + def __init__(self, ssl_version=None, **kwargs): + self._ssl_version = ssl_version + super(HTTPieHTTPAdapter, self).__init__(**kwargs) + + def init_poolmanager(self, *args, **kwargs): + kwargs['ssl_version'] = self._ssl_version + super(HTTPieHTTPAdapter, self).init_poolmanager(*args, **kwargs) + + +def get_requests_session(ssl_version): requests_session = requests.Session() + requests_session.mount( + 'https://', + HTTPieHTTPAdapter(ssl_version=ssl_version) + ) for cls in plugin_manager.get_transport_plugins(): transport_plugin = cls() requests_session.mount(prefix=transport_plugin.prefix, @@ -38,7 +55,12 @@ def get_requests_session(): def get_response(args, config_dir): """Send the request and return a `request.Response`.""" - requests_session = get_requests_session() + + ssl_version = None + if args.ssl_version: + ssl_version = SSL_VERSION_ARG_MAPPING[args.ssl_version] + + requests_session = get_requests_session(ssl_version) requests_session.max_redirects = args.max_redirects if not args.session and not args.session_read_only: diff --git a/httpie/input.py b/httpie/input.py index 232e2d9e8f..96c7945a26 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -2,6 +2,7 @@ """ import os +import ssl import sys import re import errno @@ -103,6 +104,20 @@ OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED = OUT_RESP_BODY +SSL_VERSION_ARG_MAPPING = { + 'ssl2.3': 'PROTOCOL_SSLv23', + 'ssl3': 'PROTOCOL_SSLv3', + 'tls1': 'PROTOCOL_TLSv1', + 'tls1.1': 'PROTOCOL_TLSv1_1', + 'tls1.2': 'PROTOCOL_TLSv1_2', +} +SSL_VERSION_ARG_MAPPING = dict( + (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): """Adds additional logic to `argparse.ArgumentParser`. diff --git a/tests/test_ssl.py b/tests/test_ssl.py index ac2fed3b7b..b2c7108a7c 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -5,6 +5,7 @@ from requests.exceptions import SSLError from httpie import ExitStatus +from httpie.input import SSL_VERSION_ARG_MAPPING from utils import http, HTTP_OK, TESTS_ROOT @@ -18,6 +19,26 @@ CA_BUNDLE = pytest_httpbin.certs.where() +@pytest.mark.parametrize( + argnames='ssl_version', + argvalues=SSL_VERSION_ARG_MAPPING.keys() +) +def test_ssl_version(httpbin_secure, ssl_version): + try: + r = http( + '--verify', CA_BUNDLE, + '--ssl', ssl_version, + httpbin_secure + '/get' + ) + assert HTTP_OK in r + except SSLError as e: + if ssl_version == 'ssl3': + # pytest-httpbin doesn't support ssl3 + assert 'SSLV3_ALERT_HANDSHAKE_FAILURE' in str(e) + else: + raise + + class TestClientCert: def test_cert_and_key(self, httpbin_secure): From 04326946613eb5c835628aaab9365f53b36c393b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 12:24:24 +0800 Subject: [PATCH 0194/1182] Changel --- CHANGELOG.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c790dfea0c..762deacbfc 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,18 +10,18 @@ This project adheres to `Semantic Versioning `_. ------------------------- * Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests -* Added ``--ssl=`` to specify SSL/TLS the desired protocol version +* Added ``--ssl=`` to specify the desired SSL/TLS protocol version to use for HTTPS requests. * Added ``--show-redirects, -R`` to show intermediate responses with ``--follow`` * Added ``--max-redirects`` (default 30) * Added ``-A`` as short name for ``--auth-type`` * Added ``-F`` as short name for ``--follow`` -* Added JSON detection when ``--json, -j`` is used in order to correctly format - JSON responses even when an incorrect ``Content-Type`` is returned. +* Added JSON detection with ``--json, -j`` to work around incorrect + ``Content-Type`` * Redirected ``stdout`` doesn't trigger an error anymore when ``--output FILE`` is set. -* Changed the default color style back to ``solarized`` as it supports - both the light and dark terminal background mode +* Changed the default ``--style`` back to ``solarized`` for better support + of light and dark terminals * Fixed ``--session`` when used with ``--download`` * Fixed handling of ``Content-Type`` with multiple ``+subtype`` parts From ecbbad816ab2e43aecda36f1559c1c491d6cc05b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 12:24:46 +0800 Subject: [PATCH 0195/1182] Fix coveralls integration --- httpie/client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/httpie/client.py b/httpie/client.py index 8c0b6fe851..dcae10a816 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -85,7 +85,6 @@ def dump_request(kwargs): % pformat(kwargs)) - def encode_headers(headers): # This allows for unicode headers which is non-standard but practical. # See: https://github.com/jkbrzt/httpie/issues/212 From 564670566c7902ad09f414fa681de6b18a883319 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 12:25:19 +0800 Subject: [PATCH 0196/1182] Fix coveralls integration --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f678253670..2e232758a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,7 +64,7 @@ script: 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 fi From 66e168b2afe4c9ba94275eb8649ddb8a03779679 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 13:16:41 +0800 Subject: [PATCH 0197/1182] Improved failed test output --- CHANGELOG.rst | 4 ++-- httpie/__init__.py | 7 +++++++ pytest.ini | 1 - tests/utils.py | 20 +++++++++++++++----- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 762deacbfc..4e9d46ee51 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,12 +12,12 @@ This project adheres to `Semantic Versioning `_. * Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests * Added ``--ssl=`` to specify the desired SSL/TLS protocol version to use for HTTPS requests. +* Added JSON detection with ``--json, -j`` to work around incorrect + ``Content-Type`` * Added ``--show-redirects, -R`` to show intermediate responses with ``--follow`` * Added ``--max-redirects`` (default 30) * Added ``-A`` as short name for ``--auth-type`` * Added ``-F`` as short name for ``--follow`` -* Added JSON detection with ``--json, -j`` to work around incorrect - ``Content-Type`` * Redirected ``stdout`` doesn't trigger an error anymore when ``--output FILE`` is set. * Changed the default ``--style`` back to ``solarized`` for better support diff --git a/httpie/__init__.py b/httpie/__init__.py index c4f7b82958..6c7fe03bd7 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -18,3 +18,10 @@ class ExitStatus: ERROR_HTTP_3XX = 3 ERROR_HTTP_4XX = 4 ERROR_HTTP_5XX = 5 + + +EXIT_STATUS_LABELS = dict( + (value, key) + for key, value in ExitStatus.__dict__.items() + if key.isupper() +) diff --git a/pytest.ini b/pytest.ini index 9735e58195..f132993de7 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,3 +1,2 @@ [pytest] -addopts = --tb=native norecursedirs = tests/fixtures diff --git a/tests/utils.py b/tests/utils.py index e54969e726..be2f80e20b 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -6,7 +6,7 @@ import json import tempfile -import httpie +from httpie import ExitStatus, EXIT_STATUS_LABELS from httpie.context import Environment from httpie.core import main from httpie.compat import bytes, str @@ -135,6 +135,10 @@ def json(self): return self._json +class ExitStatusException(Exception): + pass + + def http(*args, **kwargs): # noinspection PyUnresolvedReferences """ @@ -205,7 +209,7 @@ def dump_stderr(): time.sleep(.5) except SystemExit: if error_exit_ok: - exit_status = httpie.ExitStatus.ERROR + exit_status = ExitStatus.ERROR else: dump_stderr() raise @@ -214,9 +218,15 @@ def dump_stderr(): sys.stderr.write(stderr.read()) raise else: - if exit_status != httpie.ExitStatus.OK and not error_exit_ok: + if not error_exit_ok and exit_status != ExitStatus.OK: dump_stderr() - raise Exception('Unexpected exit status: %s', exit_status) + raise ExitStatusException( + 'httpie.core.main() unexpectedly returned' + ' a non-zero exit status: {0} ({1})'.format( + exit_status, + EXIT_STATUS_LABELS[exit_status] + ) + ) stdout.seek(0) stderr.seek(0) @@ -232,7 +242,7 @@ def dump_stderr(): r.stderr = stderr.read() r.exit_status = exit_status - if r.exit_status != httpie.ExitStatus.OK: + if r.exit_status != ExitStatus.OK: sys.stderr.write(r.stderr) return r From d24f30d0af9b040db7dd9cd15a8926122851a10c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 13:31:23 +0800 Subject: [PATCH 0198/1182] Cleanup --- tests/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/utils.py b/tests/utils.py index be2f80e20b..e90e750273 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -135,7 +135,7 @@ def json(self): return self._json -class ExitStatusException(Exception): +class ExitStatusError(Exception): pass @@ -220,7 +220,7 @@ def dump_stderr(): else: if not error_exit_ok and exit_status != ExitStatus.OK: dump_stderr() - raise ExitStatusException( + raise ExitStatusError( 'httpie.core.main() unexpectedly returned' ' a non-zero exit status: {0} ({1})'.format( exit_status, From 4cfa143bfe3d8cf109c02cabe7c3b237e41dacaa Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 13:31:40 +0800 Subject: [PATCH 0199/1182] Fixed coverage --- .coveragerc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000000..59f4738f25 --- /dev/null +++ b/.coveragerc @@ -0,0 +1 @@ +; needs to exist otherwise `$ coveralls fails` From 13a979ad1165e1c6d49d422a8b5229db81972a15 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 2 Mar 2016 13:42:42 +0800 Subject: [PATCH 0200/1182] Cleanup --- .coveragerc | 2 +- CHANGELOG.rst | 2 +- README.rst | 14 ++++++++------ httpie/cli.py | 22 +++++++++++----------- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/.coveragerc b/.coveragerc index 59f4738f25..99e1cbc0be 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1 +1 @@ -; needs to exist otherwise `$ coveralls fails` +; needs to exist otherwise `$ coveralls` fails diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4e9d46ee51..2c11f0583e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,7 +19,7 @@ This project adheres to `Semantic Versioning `_. * Added ``-A`` as short name for ``--auth-type`` * Added ``-F`` as short name for ``--follow`` * Redirected ``stdout`` doesn't trigger an error anymore when ``--output FILE`` - is set. + is set * Changed the default ``--style`` back to ``solarized`` for better support of light and dark terminals * Fixed ``--session`` when used with ``--download`` diff --git a/README.rst b/README.rst index 8784fa3659..97fc2dbbdd 100644 --- a/README.rst +++ b/README.rst @@ -738,7 +738,7 @@ Use the ``--ssl=`` 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 -available set of protocols may vary depending your on OpenSSL installation.) +available set of protocols may vary depending on your OpenSSL installation.) .. code-block:: bash @@ -1348,12 +1348,14 @@ HTTPie reaches its final version ``1.0``. All changes are recorded in the Support ======= -* Use `GitHub issues `_ +Please use the following support channels: + +* `GitHub issues `_ for bug reports and feature requests. -* Ask questions and discuss features in - ` our Gitter chat room `_. -* Ask questions on `StackOverflow `_ - (please make sure to use the +* `Our Gitter chat room `_ + to ask questions, discuss features, and for general discussion. +* `StackOverflow `_ + to ask questions (please make sure to use the `httpie `_ tag). * You can also tweet directly to `@jkbrzt`_. diff --git a/httpie/cli.py b/httpie/cli.py index 771126cbb8..f964b23318 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -474,17 +474,6 @@ def _split_lines(self, text, width): """ ) -network.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". - - """ -) - network.add_argument( '--timeout', type=float, @@ -519,6 +508,16 @@ def _split_lines(self, text, width): ####################################################################### ssl = parser.add_argument_group(title='SSL') +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". + + """ +) ssl.add_argument( '--ssl', # TODO: Maybe something more general, such as --secure-protocol? dest='ssl_version', @@ -529,6 +528,7 @@ def _split_lines(self, text, width): the server and your installation of OpenSSL support. Available protocols may vary depending on OpenSSL installation (only the supported ones are shown here). + """ ) ssl.add_argument( From 5dbd104c3b8672941f236ba48cc3a3d58c8295e4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 3 Mar 2016 17:09:34 +0800 Subject: [PATCH 0201/1182] Nobody ain't got time for that --- tests/test_exit_status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index 7ac643f940..131c52bb94 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -23,7 +23,7 @@ def test_error_response_exits_0_without_check_status(self, httpbin): ) def test_timeout_exit_status(self, httpbin): - r = http('--timeout=0.5', 'GET', httpbin.url + '/delay/1', + r = http('--timeout=0.01', 'GET', httpbin.url + '/delay/0.02', error_exit_ok=True) assert r.exit_status == ExitStatus.ERROR_TIMEOUT From 20823c17025627849d0efce5e4b345f03917b60e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 3 Mar 2016 17:14:39 +0800 Subject: [PATCH 0202/1182] Removed the "implicit_content_type" config option If you used: "implicit_content_type": "form" You can achieve the the same result with: "default_options": ["--form"] If you used: "implicit_content_type": "json" Then it's the default behaviour and it can be removed. In either case HTTPie will migrate your config file on the next invocation. --- CHANGELOG.rst | 2 ++ README.rst | 51 ++++++++++++++++++++++---------------------- httpie/config.py | 17 ++++++++++++++- httpie/input.py | 6 ------ tests/test_config.py | 33 ++++++++++++++++++++++++++++ tests/utils.py | 15 +++++++------ 6 files changed, 85 insertions(+), 39 deletions(-) create mode 100644 tests/test_config.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2c11f0583e..03c90cee1c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,6 +18,8 @@ This project adheres to `Semantic Versioning `_. * Added ``--max-redirects`` (default 30) * Added ``-A`` as short name for ``--auth-type`` * Added ``-F`` as short name for ``--follow`` +* Removed the ``"implicit_content_type" config option + (use ``"default_options": ["--form"]`` instead) * Redirected ``stdout`` doesn't trigger an error anymore when ``--output FILE`` is set * Changed the default ``--style`` back to ``solarized`` for better support diff --git a/README.rst b/README.rst index 97fc2dbbdd..c66d0f5fb8 100644 --- a/README.rst +++ b/README.rst @@ -1230,31 +1230,32 @@ Config HTTPie uses a simple configuration file that contains a JSON object with the following keys: -========================= ================================================= -``__meta__`` HTTPie automatically stores some metadata here. - Do not change. - -``implicit_content_type`` A ``String`` specifying the implicit content type - for request data. The default value for this - option is ``json`` and can be changed to - ``form``. - -``default_options`` An ``Array`` (by default empty) of options - that should be applied to every request. - - For instance, you can use this option to change - the default style and output options: - ``"default_options": ["--style=fruity", "--body"]`` - - Another useful default option is - ``"--session=default"`` to make HTTPie always - use `sessions`_. - - Default options from config file can be unset - for a particular invocation via - ``--no-OPTION`` arguments passed on the - command line (e.g., ``--no-style`` - or ``--no-session``). + +``__meta__`` +------------ +HTTPie automatically stores some of its metadata here. Do not change. + + +``default_options`` +------------------- + +An ``Array`` (by default empty) of default options that should be applied to +every invocation of HTTPie. + +For instance, you can use this option to change the default style and output +options: ``"default_options": ["--style=fruity", "--body"]`` + +Another useful default option is ``"--session=default"`` to make HTTPie always +use `sessions`_. + +Or you could change the implicit request content type from JSON to form by +adding the ``--form``. + +Default options from config file can be unset for a particular invocation via +``--no-OPTION`` arguments passed on the command line (e.g., ``--no-style`` +or ``--no-session``). + + ========================= ================================================= The default location of the configuration file is ``~/.httpie/config.json`` diff --git a/httpie/config.py b/httpie/config.py index 64f72b2b0f..f7282387d0 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -84,7 +84,6 @@ class Config(BaseConfigDict): about = 'HTTPie configuration file' DEFAULTS = { - 'implicit_content_type': 'json', 'default_options': [] } @@ -93,5 +92,21 @@ def __init__(self, directory=DEFAULT_CONFIG_DIR): self.update(self.DEFAULTS) self.directory = directory + def load(self): + super(Config, self).load() + self._migrate_implicit_content_type() + def _get_path(self): return os.path.join(self.directory, self.name + '.json') + + def _migrate_implicit_content_type(self): + """Migrate the removed implicit_content_type config option""" + try: + implicit_content_type = self.pop('implicit_content_type') + except KeyError: + pass + else: + if implicit_content_type == 'form': + self['default_options'].insert(0, '--form') + self.save() + self.load() diff --git a/httpie/input.py b/httpie/input.py index 96c7945a26..c622b65b4d 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -142,7 +142,6 @@ def parse_args(self, env, args=None, namespace=None): # Arguments processing and environment setup. self._apply_no_options(no_options) - self._apply_config() self._validate_download_options() self._setup_standard_streams() self._process_output_options() @@ -214,11 +213,6 @@ def _setup_standard_streams(self): self.env.stdout = self.args.output_file self.env.stdout_isatty = False - def _apply_config(self): - if (not self.args.json - and self.env.config.implicit_content_type == 'form'): - self.args.form = True - def _process_auth(self): """ If only a username provided via --auth, then ask for a password. diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000000..c309117316 --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,33 @@ +from utils import TestEnvironment, http + + +def test_default_options(httpbin): + env = TestEnvironment() + env.config['default_options'] = ['--form'] + env.config.save() + r = http(httpbin.url + '/post', 'foo=bar', env=env) + assert r.json['form'] == {"foo": "bar"} + + +def test_default_options_overwrite(httpbin): + env = TestEnvironment() + env.config['default_options'] = ['--form'] + env.config.save() + r = http('--json', httpbin.url + '/post', 'foo=bar', env=env) + assert r.json['json'] == {"foo": "bar"} + + +def test_migrate_implicit_content_type(): + config = TestEnvironment().config + + config['implicit_content_type'] = 'json' + config.save() + config.load() + assert 'implicit_content_type' not in config + assert not config['default_options'] + + config['implicit_content_type'] = 'form' + config.save() + config.load() + assert 'implicit_content_type' not in config + assert config['default_options'] == ['--form'] diff --git a/tests/utils.py b/tests/utils.py index e90e750273..feede79058 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -189,13 +189,14 @@ def http(*args, **kwargs): stderr = env.stderr args = list(args) - extra_args = [] - if '--debug' not in args: - if '--traceback' not in args: - extra_args.append('--traceback') - if not any('--timeout' in arg for arg in args): - extra_args.append('--timeout=3') - args = extra_args + args + args_with_config_defaults = args + env.config.default_options + add_to_args = [] + if '--debug' not in args_with_config_defaults: + if '--traceback' not in args_with_config_defaults: + add_to_args.append('--traceback') + if not any('--timeout' in arg for arg in args_with_config_defaults): + add_to_args.append('--timeout=3') + args = add_to_args + args def dump_stderr(): stderr.seek(0) From 2d9414d34c5ab8b77de0ab17b208d014a1acf16e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 3 Mar 2016 17:21:51 +0800 Subject: [PATCH 0203/1182] Fixed README --- README.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index c66d0f5fb8..74f6e5b6d0 100644 --- a/README.rst +++ b/README.rst @@ -1231,11 +1231,14 @@ HTTPie uses a simple configuration file that contains a JSON object with the following keys: +------------ ``__meta__`` ------------ + HTTPie automatically stores some of its metadata here. Do not change. +------------------- ``default_options`` ------------------- @@ -1246,7 +1249,7 @@ For instance, you can use this option to change the default style and output options: ``"default_options": ["--style=fruity", "--body"]`` Another useful default option is ``"--session=default"`` to make HTTPie always -use `sessions`_. +use `sessions`_ (one name ``default`` will automatically be created/used). Or you could change the implicit request content type from JSON to form by adding the ``--form``. @@ -1255,9 +1258,6 @@ Default options from config file can be unset for a particular invocation via ``--no-OPTION`` arguments passed on the command line (e.g., ``--no-style`` or ``--no-session``). - -========================= ================================================= - The default location of the configuration file is ``~/.httpie/config.json`` (or ``%APPDATA%\httpie\config.json`` on Windows). From 5bdf4a3baede7e85dcc529aadb240e895e833f52 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 3 Mar 2016 17:22:12 +0800 Subject: [PATCH 0204/1182] Fixed test_rst_file_syntax error message --- tests/test_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_docs.py b/tests/test_docs.py index a02f6510a6..07363535d8 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -36,4 +36,4 @@ def test_rst_file_syntax(filename): stdout=subprocess.PIPE ) err = p.communicate()[1] - assert p.returncode == 0, err + assert p.returncode == 0, err.decode('utf8') From f7d1b739e2328edf7ca31e663220c9781c6c274b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 3 Mar 2016 17:24:46 +0800 Subject: [PATCH 0205/1182] README --- README.rst | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 74f6e5b6d0..97daf4d7e1 100644 --- a/README.rst +++ b/README.rst @@ -1246,21 +1246,16 @@ An ``Array`` (by default empty) of default options that should be applied to every invocation of HTTPie. For instance, you can use this option to change the default style and output -options: ``"default_options": ["--style=fruity", "--body"]`` - -Another useful default option is ``"--session=default"`` to make HTTPie always +options: ``"default_options": ["--style=fruity", "--body"]`` Another useful +default option could be ``"--session=default"`` to make HTTPie always use `sessions`_ (one name ``default`` will automatically be created/used). - Or you could change the implicit request content type from JSON to form by -adding the ``--form``. +adding ``--form`` to the list. Default options from config file can be unset for a particular invocation via ``--no-OPTION`` arguments passed on the command line (e.g., ``--no-style`` -or ``--no-session``). - -The default location of the configuration file is ``~/.httpie/config.json`` -(or ``%APPDATA%\httpie\config.json`` on Windows). - +or ``--no-session``). The default location of the configuration file is +``~/.httpie/config.json`` (or ``%APPDATA%\httpie\config.json`` on Windows). The config directory location can be changed by setting the ``HTTPIE_CONFIG_DIR`` environment variable. From 6731cb881a4313f39a07e654602a7859feb90c4b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 3 Mar 2016 17:26:47 +0800 Subject: [PATCH 0206/1182] README --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 97daf4d7e1..9941607384 100644 --- a/README.rst +++ b/README.rst @@ -1248,7 +1248,7 @@ every invocation of HTTPie. For instance, you can use this option to change the default style and output options: ``"default_options": ["--style=fruity", "--body"]`` Another useful default option could be ``"--session=default"`` to make HTTPie always -use `sessions`_ (one name ``default`` will automatically be created/used). +use `sessions`_ (one named ``default`` will automatically be used). Or you could change the implicit request content type from JSON to form by adding ``--form`` to the list. From 529981af7a792128f737ef73addfd6643e6dc437 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 3 Mar 2016 18:46:58 +0800 Subject: [PATCH 0207/1182] Fix CHANGELOG --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 03c90cee1c..812f62f84c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,7 +18,7 @@ This project adheres to `Semantic Versioning `_. * Added ``--max-redirects`` (default 30) * Added ``-A`` as short name for ``--auth-type`` * Added ``-F`` as short name for ``--follow`` -* Removed the ``"implicit_content_type" config option +* Removed the ``implicit_content_type`` config option (use ``"default_options": ["--form"]`` instead) * Redirected ``stdout`` doesn't trigger an error anymore when ``--output FILE`` is set From 4e574e6b8e45f9fa14d5d57db15447c45e41fc71 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 3 Mar 2016 18:47:12 +0800 Subject: [PATCH 0208/1182] Cleanup tests --- tests/test_auth.py | 110 ++++++++++++------------- tests/test_cli.py | 2 +- tests/test_exit_status.py | 113 +++++++++++++------------- tests/test_httpie.py | 149 ++++++++++++++++++---------------- tests/test_output.py | 2 +- tests/test_stream.py | 70 ++++++++-------- tests/test_unicode.py | 166 ++++++++++++++++++++------------------ 7 files changed, 315 insertions(+), 297 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index cb53ba82b4..f3d1df88a8 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -1,5 +1,5 @@ """HTTP authentication-related tests.""" -import requests +import mock import pytest from utils import http, add_auth, HTTP_OK, TestEnvironment @@ -7,56 +7,58 @@ import httpie.cli -class TestAuth: - def test_basic_auth(self, httpbin): - r = http('--auth=user:password', - 'GET', httpbin.url + '/basic-auth/user/password') - assert HTTP_OK in r - assert r.json == {'authenticated': True, 'user': 'user'} - - @pytest.mark.parametrize('argument_name', ['--auth-type', '-A']) - @pytest.mark.skipif( - requests.__version__ == '0.13.6', - reason='Redirects with prefetch=False are broken in Requests 0.13.6') - def test_digest_auth(self, httpbin, argument_name): - r = http(argument_name + '=digest', '--auth=user:password', - 'GET', httpbin.url + '/digest-auth/auth/user/password') - assert HTTP_OK in r - assert r.json == {'authenticated': True, 'user': 'user'} - - def test_password_prompt(self, httpbin): - httpie.input.AuthCredentials._getpass = lambda self, prompt: 'password' - r = http('--auth', 'user', - 'GET', httpbin.url + '/basic-auth/user/password') - assert HTTP_OK in r - assert r.json == {'authenticated': True, 'user': 'user'} - - def test_credentials_in_url(self, httpbin): - url = add_auth(httpbin.url + '/basic-auth/user/password', - auth='user:password') - r = http('GET', url) - assert HTTP_OK in r - assert r.json == {'authenticated': True, 'user': 'user'} - - def test_credentials_in_url_auth_flag_has_priority(self, httpbin): - """When credentials are passed in URL and via -a at the same time, - then the ones from -a are used.""" - url = add_auth(httpbin.url + '/basic-auth/user/password', - auth='user:wrong') - r = http('--auth=user:password', 'GET', url) - assert HTTP_OK in r - assert r.json == {'authenticated': True, 'user': 'user'} - - @pytest.mark.parametrize('url', [ - 'username@example.org', - 'username:@example.org', - ]) - def test_only_username_in_url(self, url): - """ - https://github.com/jkbrzt/httpie/issues/242 - - """ - args = httpie.cli.parser.parse_args(args=[url], env=TestEnvironment()) - assert args.auth - assert args.auth.key == 'username' - assert args.auth.value == '' +def test_basic_auth(httpbin): + r = http('--auth=user:password', + 'GET', httpbin.url + '/basic-auth/user/password') + assert HTTP_OK in r + assert r.json == {'authenticated': True, 'user': 'user'} + + +@pytest.mark.parametrize('argument_name', ['--auth-type', '-A']) +def test_digest_auth(httpbin, argument_name): + r = http(argument_name + '=digest', '--auth=user:password', + 'GET', httpbin.url + '/digest-auth/auth/user/password') + assert HTTP_OK in r + assert r.json == {'authenticated': True, 'user': 'user'} + + +@mock.patch('httpie.input.AuthCredentials._getpass', + new=lambda self, prompt: 'password') +def test_password_prompt(httpbin): + r = http('--auth', 'user', + 'GET', httpbin.url + '/basic-auth/user/password') + assert HTTP_OK in r + assert r.json == {'authenticated': True, 'user': 'user'} + + +def test_credentials_in_url(httpbin): + url = add_auth(httpbin.url + '/basic-auth/user/password', + auth='user:password') + r = http('GET', url) + assert HTTP_OK in r + assert r.json == {'authenticated': True, 'user': 'user'} + + +def test_credentials_in_url_auth_flag_has_priority(httpbin): + """When credentials are passed in URL and via -a at the same time, + then the ones from -a are used.""" + url = add_auth(httpbin.url + '/basic-auth/user/password', + auth='user:wrong') + r = http('--auth=user:password', 'GET', url) + assert HTTP_OK in r + assert r.json == {'authenticated': True, 'user': 'user'} + + +@pytest.mark.parametrize('url', [ + 'username@example.org', + 'username:@example.org', +]) +def test_only_username_in_url(url): + """ + https://github.com/jkbrzt/httpie/issues/242 + + """ + args = httpie.cli.parser.parse_args(args=[url], env=TestEnvironment()) + assert args.auth + assert args.auth.key == 'username' + assert args.auth.value == '' diff --git a/tests/test_cli.py b/tests/test_cli.py index 00beb16b44..d5e8f1f9c1 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -154,7 +154,7 @@ def test_query_string_params_in_url_and_items_with_duplicates(self, assert '"url": "%s"' % url in r -class TestURLshorthand: +class TestLocalhostShorthand: def test_expand_localhost_shorthand(self): args = parser.parse_args(args=[':'], env=TestEnvironment()) assert args.url == 'http://localhost' diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index 131c52bb94..9249c87baa 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -1,63 +1,58 @@ -import requests -import pytest - from httpie import ExitStatus from utils import TestEnvironment, http, HTTP_OK -class TestExitStatus: - def test_ok_response_exits_0(self, httpbin): - r = http('GET', httpbin.url + '/status/200') - assert HTTP_OK in r - assert r.exit_status == ExitStatus.OK - - def test_error_response_exits_0_without_check_status(self, httpbin): - r = http('GET', httpbin.url + '/status/500') - assert '500 INTERNAL SERVER ERRO' in r - assert r.exit_status == ExitStatus.OK - assert not r.stderr - - @pytest.mark.skipif( - tuple(map(int, requests.__version__.split('.'))) < (2, 3, 0), - reason='timeout broken in requests prior v2.3.0 (#185)' - ) - def test_timeout_exit_status(self, httpbin): - - r = http('--timeout=0.01', 'GET', httpbin.url + '/delay/0.02', - error_exit_ok=True) - assert r.exit_status == ExitStatus.ERROR_TIMEOUT - - def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected( - self, httpbin): - env = TestEnvironment(stdout_isatty=False) - r = http('--check-status', '--headers', - 'GET', httpbin.url + '/status/301', - env=env, error_exit_ok=True) - assert '301 MOVED PERMANENTLY' in r - assert r.exit_status == ExitStatus.ERROR_HTTP_3XX - assert '301 moved permanently' in r.stderr.lower() - - @pytest.mark.skipif( - requests.__version__ == '0.13.6', - reason='Redirects with prefetch=False are broken in Requests 0.13.6') - def test_3xx_check_status_redirects_allowed_exits_0(self, httpbin): - r = http('--check-status', '--follow', - 'GET', httpbin.url + '/status/301', - error_exit_ok=True) - # The redirect will be followed so 200 is expected. - assert HTTP_OK in r - assert r.exit_status == ExitStatus.OK - - def test_4xx_check_status_exits_4(self, httpbin): - r = http('--check-status', 'GET', httpbin.url + '/status/401', - error_exit_ok=True) - assert '401 UNAUTHORIZED' in r - assert r.exit_status == ExitStatus.ERROR_HTTP_4XX - # Also stderr should be empty since stdout isn't redirected. - assert not r.stderr - - def test_5xx_check_status_exits_5(self, httpbin): - r = http('--check-status', 'GET', httpbin.url + '/status/500', - error_exit_ok=True) - assert '500 INTERNAL SERVER ERROR' in r - assert r.exit_status == ExitStatus.ERROR_HTTP_5XX +def test_ok_response_exits_0(httpbin): + r = http('GET', httpbin.url + '/status/200') + assert HTTP_OK in r + assert r.exit_status == ExitStatus.OK + + +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 not r.stderr + + +def test_timeout_exit_status(httpbin): + + r = http('--timeout=0.01', 'GET', httpbin.url + '/delay/0.02', + 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) + r = http('--check-status', '--headers', + 'GET', httpbin.url + '/status/301', + env=env, error_exit_ok=True) + assert '301 MOVED PERMANENTLY' in r + assert r.exit_status == ExitStatus.ERROR_HTTP_3XX + assert '301 moved permanently' in r.stderr.lower() + + +def test_3xx_check_status_redirects_allowed_exits_0(httpbin): + r = http('--check-status', '--follow', + 'GET', httpbin.url + '/status/301', + error_exit_ok=True) + # The redirect will be followed so 200 is expected. + assert HTTP_OK in r + assert r.exit_status == ExitStatus.OK + + +def test_4xx_check_status_exits_4(httpbin): + r = http('--check-status', 'GET', httpbin.url + '/status/401', + error_exit_ok=True) + assert '401 UNAUTHORIZED' in r + assert r.exit_status == ExitStatus.ERROR_HTTP_4XX + # Also stderr should be empty since stdout isn't redirected. + assert not r.stderr + + +def test_5xx_check_status_exits_5(httpbin): + r = http('--check-status', 'GET', httpbin.url + '/status/500', + error_exit_ok=True) + assert '500 INTERNAL SERVER ERROR' in r + assert r.exit_status == ExitStatus.ERROR_HTTP_5XX diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 6fb47bf61e..391a437bfc 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -7,73 +7,82 @@ from httpie.compat import is_py26 -class TestHTTPie: - - def test_debug(self): - r = http('--debug') - assert r.exit_status == httpie.ExitStatus.OK - assert 'HTTPie %s' % httpie.__version__ in r.stderr - assert 'HTTPie data:' in r.stderr - - def test_help(self): - r = http('--help', error_exit_ok=True) - assert r.exit_status == httpie.ExitStatus.OK - assert 'https://github.com/jkbrzt/httpie/issues' in r - - def test_version(self): - r = http('--version', error_exit_ok=True) - assert r.exit_status == httpie.ExitStatus.OK - # FIXME: py3 has version in stdout, py2 in stderr - assert httpie.__version__ == r.stderr.strip() + r.strip() - - def test_GET(self, httpbin): - r = http('GET', httpbin.url + '/get') - assert HTTP_OK in r - - def test_DELETE(self, httpbin): - r = http('DELETE', httpbin.url + '/delete') - assert HTTP_OK in r - - def test_PUT(self, httpbin): - r = http('PUT', httpbin.url + '/put', 'foo=bar') - assert HTTP_OK in r - assert r.json['json']['foo'] == 'bar' - - def test_POST_JSON_data(self, httpbin): - r = http('POST', httpbin.url + '/post', 'foo=bar') - assert HTTP_OK in r - assert r.json['json']['foo'] == 'bar' - - def test_POST_form(self, httpbin): - r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar') - assert HTTP_OK in r - assert '"foo": "bar"' in r - - def test_POST_form_multiple_values(self, httpbin): - r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar', 'foo=baz') - assert HTTP_OK in r - assert r.json['form'] == {'foo': ['bar', 'baz']} - - def test_POST_stdin(self, httpbin): - with open(FILE_PATH) as f: - env = TestEnvironment(stdin=f, stdin_isatty=False) - r = http('--form', 'POST', httpbin.url + '/post', env=env) - assert HTTP_OK in r - assert FILE_CONTENT in r - - def test_headers(self, httpbin): - r = http('GET', httpbin.url + '/headers', 'Foo:bar') - assert HTTP_OK in r - assert '"User-Agent": "HTTPie' in r, r - assert '"Foo": "bar"' in r - - @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(self, httpbin): - r = http('PATCH', httpbin.url + '/patch', - 'order:={"map":{"1":"first","2":"second"}}') - assert HTTP_OK in r - assert r.json['data'] == \ - '{"order": {"map": {"1": "first", "2": "second"}}}' +def test_debug(): + r = http('--debug') + assert r.exit_status == httpie.ExitStatus.OK + assert 'HTTPie %s' % httpie.__version__ in r.stderr + assert 'HTTPie data:' 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 + + +def test_version(): + r = http('--version', error_exit_ok=True) + assert r.exit_status == httpie.ExitStatus.OK + # FIXME: py3 has version in stdout, py2 in stderr + assert httpie.__version__ == r.stderr.strip() + r.strip() + + +def test_GET(httpbin): + r = http('GET', httpbin.url + '/get') + assert HTTP_OK in r + + +def test_DELETE(httpbin): + r = http('DELETE', httpbin.url + '/delete') + assert HTTP_OK in r + + +def test_PUT(httpbin): + r = http('PUT', httpbin.url + '/put', 'foo=bar') + assert HTTP_OK in r + assert r.json['json']['foo'] == 'bar' + + +def test_POST_JSON_data(httpbin): + r = http('POST', httpbin.url + '/post', 'foo=bar') + assert HTTP_OK in r + assert r.json['json']['foo'] == 'bar' + + +def test_POST_form(httpbin): + r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar') + assert HTTP_OK in r + assert '"foo": "bar"' in r + + +def test_POST_form_multiple_values(httpbin): + r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar', 'foo=baz') + assert HTTP_OK in r + assert r.json['form'] == {'foo': ['bar', 'baz']} + + +def test_POST_stdin(httpbin): + with open(FILE_PATH) as f: + env = TestEnvironment(stdin=f, stdin_isatty=False) + r = http('--form', 'POST', httpbin.url + '/post', env=env) + assert HTTP_OK in r + assert FILE_CONTENT in r + + +def test_headers(httpbin): + r = http('GET', httpbin.url + '/headers', 'Foo:bar') + assert HTTP_OK in r + assert '"User-Agent": "HTTPie' in r, r + assert '"Foo": "bar"' in r + + +@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): + r = http('PATCH', httpbin.url + '/patch', + 'order:={"map":{"1":"first","2":"second"}}') + assert HTTP_OK in r + assert r.json['data'] == \ + '{"order": {"map": {"1": "first", "2": "second"}}}' diff --git a/tests/test_output.py b/tests/test_output.py index ac58315f51..d20abade76 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -9,7 +9,7 @@ from httpie.output.formatters.colors import get_lexer -@pytest.mark.parametrize('stdout_isatty', [(True,), (False,)]) +@pytest.mark.parametrize('stdout_isatty', [True, False]) def test_output_option(httpbin, stdout_isatty): output_filename = os.path.join(gettempdir(), test_output_option.__name__) url = httpbin + '/robots.txt' diff --git a/tests/test_stream.py b/tests/test_stream.py index 9e96751908..48c8dbf693 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -6,37 +6,39 @@ from fixtures import BIN_FILE_CONTENT, BIN_FILE_PATH -class TestStream: - # GET because httpbin 500s with binary POST body. - - @pytest.mark.skipif(is_windows, - reason='Pretty redirect not supported under Windows') - def test_pretty_redirected_stream(self, httpbin): - """Test that --stream works with prettified redirected output.""" - with open(BIN_FILE_PATH, 'rb') as f: - env = TestEnvironment(colors=256, stdin=f, - stdin_isatty=False, - stdout_isatty=False) - r = http('--verbose', '--pretty=all', '--stream', 'GET', - httpbin.url + '/get', env=env) - assert BINARY_SUPPRESSED_NOTICE.decode() in r - - def test_encoded_stream(self, 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) - r = http('--pretty=none', '--stream', '--verbose', 'GET', - httpbin.url + '/get', env=env) - assert BINARY_SUPPRESSED_NOTICE.decode() in r - - def test_redirected_stream(self, httpbin): - """Test that --stream works with non-prettified - redirected terminal output.""" - with open(BIN_FILE_PATH, 'rb') as f: - env = TestEnvironment(stdout_isatty=False, - stdin_isatty=False, - stdin=f) - r = http('--pretty=none', '--stream', '--verbose', 'GET', - httpbin.url + '/get', env=env) - assert BIN_FILE_CONTENT in r +# GET because httpbin 500s with binary POST body. + + +@pytest.mark.skipif(is_windows, + reason='Pretty redirect not supported under Windows') +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, + stdin_isatty=False, + stdout_isatty=False) + r = http('--verbose', '--pretty=all', '--stream', 'GET', + httpbin.url + '/get', env=env) + assert BINARY_SUPPRESSED_NOTICE.decode() in r + + +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) + r = http('--pretty=none', '--stream', '--verbose', 'GET', + httpbin.url + '/get', env=env) + assert BINARY_SUPPRESSED_NOTICE.decode() in r + + +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, + stdin_isatty=False, + stdin=f) + r = http('--pretty=none', '--stream', '--verbose', 'GET', + httpbin.url + '/get', env=env) + assert BIN_FILE_CONTENT in r diff --git a/tests/test_unicode.py b/tests/test_unicode.py index abcd9ebd7a..482fbb6cbe 100644 --- a/tests/test_unicode.py +++ b/tests/test_unicode.py @@ -7,81 +7,91 @@ from fixtures import UNICODE -class TestUnicode: - - def test_unicode_headers(self, httpbin): - # httpbin doesn't interpret utf8 headers - r = http(httpbin.url + '/headers', u'Test:%s' % UNICODE) - assert HTTP_OK in r - - def test_unicode_headers_verbose(self, httpbin): - # httpbin doesn't interpret utf8 headers - r = http('--verbose', httpbin.url + '/headers', u'Test:%s' % UNICODE) - assert HTTP_OK in r - assert UNICODE in r - - def test_unicode_form_item(self, httpbin): - r = http('--form', 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) - assert HTTP_OK in r - assert r.json['form'] == {'test': UNICODE} - - def test_unicode_form_item_verbose(self, httpbin): - r = http('--verbose', '--form', - 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) - assert HTTP_OK in r - assert UNICODE in r - - def test_unicode_json_item(self, httpbin): - r = http('--json', 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) - assert HTTP_OK in r - assert r.json['json'] == {'test': UNICODE} - - def test_unicode_json_item_verbose(self, httpbin): - r = http('--verbose', '--json', - 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) - assert HTTP_OK in r - assert UNICODE in r - - def test_unicode_raw_json_item(self, httpbin): - r = http('--json', 'POST', httpbin.url + '/post', - u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE)) - assert HTTP_OK in r - assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} - - def test_unicode_raw_json_item_verbose(self, httpbin): - r = http('--json', 'POST', httpbin.url + '/post', - u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE)) - assert HTTP_OK in r - assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} - - def test_unicode_url_query_arg_item(self, httpbin): - r = http(httpbin.url + '/get', u'test==%s' % UNICODE) - assert HTTP_OK in r - assert r.json['args'] == {'test': UNICODE}, r - - def test_unicode_url_query_arg_item_verbose(self, httpbin): - r = http('--verbose', httpbin.url + '/get', u'test==%s' % UNICODE) - assert HTTP_OK in r - assert UNICODE in r - - def test_unicode_url(self, httpbin): - r = http(httpbin.url + u'/get?test=' + UNICODE) - assert HTTP_OK in r - assert r.json['args'] == {'test': UNICODE} - - # def test_unicode_url_verbose(self): - # r = http(httpbin.url + '--verbose', u'/get?test=' + UNICODE) - # assert HTTP_OK in r - - def test_unicode_basic_auth(self, httpbin): - # it doesn't really authenticate us because httpbin - # doesn't interpret the utf8-encoded auth - http('--verbose', '--auth', u'test:%s' % UNICODE, - httpbin.url + u'/basic-auth/test/' + UNICODE) - - def test_unicode_digest_auth(self, httpbin): - # it doesn't really authenticate us because httpbin - # doesn't interpret the utf8-encoded auth - http('--auth-type=digest', - '--auth', u'test:%s' % UNICODE, - httpbin.url + u'/digest-auth/auth/test/' + UNICODE) +def test_unicode_headers(httpbin): + # httpbin doesn't interpret utf8 headers + r = http(httpbin.url + '/headers', u'Test:%s' % UNICODE) + assert HTTP_OK in r + + +def test_unicode_headers_verbose(httpbin): + # httpbin doesn't interpret utf8 headers + r = http('--verbose', httpbin.url + '/headers', u'Test:%s' % UNICODE) + assert HTTP_OK in r + assert UNICODE in r + + +def test_unicode_form_item(httpbin): + r = http('--form', 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) + assert HTTP_OK in r + assert r.json['form'] == {'test': UNICODE} + + +def test_unicode_form_item_verbose(httpbin): + r = http('--verbose', '--form', + 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) + assert HTTP_OK in r + assert UNICODE in r + + +def test_unicode_json_item(httpbin): + r = http('--json', 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) + assert HTTP_OK in r + assert r.json['json'] == {'test': UNICODE} + + +def test_unicode_json_item_verbose(httpbin): + r = http('--verbose', '--json', + 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) + assert HTTP_OK in r + assert UNICODE in r + + +def test_unicode_raw_json_item(httpbin): + r = http('--json', 'POST', httpbin.url + '/post', + u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE)) + assert HTTP_OK in r + assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} + + +def test_unicode_raw_json_item_verbose(httpbin): + r = http('--json', 'POST', httpbin.url + '/post', + u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE)) + assert HTTP_OK in r + assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} + + +def test_unicode_url_query_arg_item(httpbin): + r = http(httpbin.url + '/get', u'test==%s' % UNICODE) + assert HTTP_OK in r + assert r.json['args'] == {'test': UNICODE}, r + + +def test_unicode_url_query_arg_item_verbose(httpbin): + r = http('--verbose', httpbin.url + '/get', u'test==%s' % UNICODE) + assert HTTP_OK in r + assert UNICODE in r + + +def test_unicode_url(httpbin): + r = http(httpbin.url + u'/get?test=' + UNICODE) + assert HTTP_OK in r + assert r.json['args'] == {'test': UNICODE} + +# def test_unicode_url_verbose(self): +# r = http(httpbin.url + '--verbose', u'/get?test=' + UNICODE) +# assert HTTP_OK in r + + +def test_unicode_basic_auth(httpbin): + # it doesn't really authenticate us because httpbin + # doesn't interpret the utf8-encoded auth + http('--verbose', '--auth', u'test:%s' % UNICODE, + httpbin.url + u'/basic-auth/test/' + UNICODE) + + +def test_unicode_digest_auth(httpbin): + # it doesn't really authenticate us because httpbin + # doesn't interpret the utf8-encoded auth + http('--auth-type=digest', + '--auth', u'test:%s' % UNICODE, + httpbin.url + u'/digest-auth/auth/test/' + UNICODE) From bb49a1f979a66c647bbe676bdb0cc8163bd87c7e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 5 Mar 2016 01:42:13 +0800 Subject: [PATCH 0209/1182] Improved --debug output --- CHANGELOG.rst | 1 + httpie/client.py | 4 ++-- httpie/context.py | 16 ++++++++++++++++ httpie/core.py | 8 ++++++-- httpie/utils.py | 16 ++++++++++++++++ tests/test_errors.py | 2 +- tests/test_httpie.py | 1 - 7 files changed, 42 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 812f62f84c..8c37eafa68 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,7 @@ This project adheres to `Semantic Versioning `_. is set * Changed the default ``--style`` back to ``solarized`` for better support of light and dark terminals +* Improved ``--debug`` output * Fixed ``--session`` when used with ``--download`` * Fixed handling of ``Content-Type`` with multiple ``+subtype`` parts diff --git a/httpie/client.py b/httpie/client.py index dcae10a816..3304927997 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -11,7 +11,7 @@ from httpie.compat import str from httpie.input import SSL_VERSION_ARG_MAPPING from httpie.plugins import plugin_manager - +from httpie.utils import repr_dict_nice try: # https://urllib3.readthedocs.org/en/latest/security.html @@ -82,7 +82,7 @@ def get_response(args, config_dir): def dump_request(kwargs): sys.stderr.write('\n>>> requests.request(**%s)\n\n' - % pformat(kwargs)) + % repr_dict_nice(kwargs)) def encode_headers(headers): diff --git a/httpie/context.py b/httpie/context.py index cd97831d7c..f14de856d1 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -3,6 +3,8 @@ from httpie.compat import is_windows from httpie.config import DEFAULT_CONFIG_DIR, Config +from httpie.utils import repr_dict_nice + class Environment(object): """ @@ -82,3 +84,17 @@ def config(self): else: self._config.load() return self._config + + def __str__(self): + defaults = dict(type(self).__dict__) + actual = dict(defaults) + actual.update(self.__dict__) + actual['config'] = self.config + return repr_dict_nice(dict( + (key, value) + for key, value in actual.items() + if not key.startswith('_')) + ) + + def __repr__(self): + return '<{0} {1}>'.format(type(self).__name__, str(self)) diff --git a/httpie/core.py b/httpie/core.py index b89b5bd02a..4c224b8a10 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -12,6 +12,7 @@ """ import sys import errno +import platform import requests from requests import __version__ as requests_version @@ -48,11 +49,14 @@ def get_exit_status(http_status, follow=False): def print_debug_info(env): env.stderr.writelines([ 'HTTPie %s\n' % httpie_version, - 'HTTPie data: %s\n' % env.config.directory, 'Requests %s\n' % requests_version, 'Pygments %s\n' % pygments_version, - 'Python %s %s\n' % (sys.version, sys.platform) + 'Python %s\n%s\n' % (sys.version, sys.executable), + '%s %s' % (platform.system(), platform.release()), ]) + env.stderr.write('\n\n') + env.stderr.write(repr(env)) + env.stderr.write('\n') def decode_args(args, stdin_encoding): diff --git a/httpie/utils.py b/httpie/utils.py index 821fac9f1f..c3b012581a 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -10,6 +10,22 @@ def load_json_preserve_order(s): return json.loads(s, object_pairs_hook=OrderedDict) +def repr_dict_nice(d): + def prepare_dict(d): + for k, v in d.items(): + if isinstance(v, dict): + v = dict(prepare_dict(v)) + elif isinstance(v, bytes): + v = v.decode('utf8') + elif not isinstance(v, (int, str)): + v = repr(v) + yield k, v + return json.dumps( + dict(prepare_dict(d)), + indent=4, sort_keys=True, + ) + + def humanize_bytes(n, precision=2): # Author: Doug Latornell # Licence: MIT diff --git a/tests/test_errors.py b/tests/test_errors.py index 040e889c13..0274e01180 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -32,7 +32,7 @@ def test_error_traceback(get_response): exc.request = Request(method='GET', url='http://www.google.com') get_response.side_effect = exc with raises(ConnectionError): - ret = main(['--ignore-stdin', '--traceback', 'www.google.com']) + main(['--ignore-stdin', '--traceback', 'www.google.com']) @mock.patch('httpie.core.get_response') diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 391a437bfc..dd48b1d197 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -11,7 +11,6 @@ def test_debug(): r = http('--debug') assert r.exit_status == httpie.ExitStatus.OK assert 'HTTPie %s' % httpie.__version__ in r.stderr - assert 'HTTPie data:' in r.stderr def test_help(): From 13ee9389aabc2faacfc79968dc54e8bf377dde9f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 5 Mar 2016 19:48:35 +0800 Subject: [PATCH 0210/1182] Add link to contributors --- AUTHORS.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 684fe8be9c..e074d415a9 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -8,6 +8,8 @@ HTTPie authors Patches and ideas ----------------- +`Complete list of contributors on GitHib `_ + * `Cláudia T. Delgado `_ (logo) * `Hank Gay `_ * `Jake Basile `_ @@ -34,3 +36,5 @@ Patches and ideas * `Dennis Brakhane `_ * `Matt Layman `_ * `Edward Yang `_ + + From 5e03aeceb7477e5ca5b80470d4fa17599dd981bd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 6 Mar 2016 08:33:14 +0800 Subject: [PATCH 0211/1182] Make fruity default style one Windows (again) --- httpie/output/formatters/colors.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 6d13fba8dc..b01774330c 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -11,14 +11,19 @@ from pygments.lexers.special import TextLexer from pygments.util import ClassNotFound +from httpie.compat import is_windows from httpie.plugins import FormatterPlugin -# Colors on Windows via colorama don't look that -# great and fruity seems to give the best result there. AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys()) AVAILABLE_STYLES.add('solarized') -DEFAULT_STYLE = 'solarized' + +if is_windows: + # Colors on Windows via colorama don't look that + # great and fruity seems to give the best result there + DEFAULT_STYLE = 'fruity' +else: + DEFAULT_STYLE = 'solarized' class ColorFormatter(FormatterPlugin): From a6ebc44a488ed8f25ba4056c974d2060e16e6953 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 6 Mar 2016 17:42:35 +0800 Subject: [PATCH 0212/1182] Run tests against both HTTP and HTTPS Some of the tests now use the `httpbin_both` fixture from pytest-httpbin. Also, made httpbin's CA trusted by default and added `httpbin_secure_untrusted` fixture to allow overriding that for particular tests. --- tests/conftest.py | 14 ++++++++++++++ tests/test_auth.py | 16 ++++++++-------- tests/test_binary.py | 1 + tests/test_downloads.py | 20 ++++++++++---------- tests/test_httpie.py | 36 ++++++++++++++++++------------------ tests/test_ssl.py | 21 +++++++-------------- 6 files changed, 58 insertions(+), 50 deletions(-) create mode 100644 tests/conftest.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000000..4b4a8bac47 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,14 @@ +import pytest +from pytest_httpbin.plugin import httpbin_ca_bundle + + +# Make httpbin's CA trusted by default +pytest.fixture(autouse=True)(httpbin_ca_bundle) + + +@pytest.fixture(scope='function') +def httpbin_secure_untrusted(monkeypatch, httpbin_secure): + """Like the `httpbin_secure` fixture, but without the + make-CA-trusted-by-default""" + monkeypatch.delenv('REQUESTS_CA_BUNDLE') + return httpbin_secure diff --git a/tests/test_auth.py b/tests/test_auth.py index f3d1df88a8..1d7395b6b2 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -7,17 +7,17 @@ import httpie.cli -def test_basic_auth(httpbin): +def test_basic_auth(httpbin_both): r = http('--auth=user:password', - 'GET', httpbin.url + '/basic-auth/user/password') + 'GET', httpbin_both + '/basic-auth/user/password') assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} @pytest.mark.parametrize('argument_name', ['--auth-type', '-A']) -def test_digest_auth(httpbin, argument_name): +def test_digest_auth(httpbin_both, argument_name): r = http(argument_name + '=digest', '--auth=user:password', - 'GET', httpbin.url + '/digest-auth/auth/user/password') + 'GET', httpbin_both.url + '/digest-auth/auth/user/password') assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} @@ -31,18 +31,18 @@ def test_password_prompt(httpbin): assert r.json == {'authenticated': True, 'user': 'user'} -def test_credentials_in_url(httpbin): - url = add_auth(httpbin.url + '/basic-auth/user/password', +def test_credentials_in_url(httpbin_both): + url = add_auth(httpbin_both.url + '/basic-auth/user/password', auth='user:password') r = http('GET', url) assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} -def test_credentials_in_url_auth_flag_has_priority(httpbin): +def test_credentials_in_url_auth_flag_has_priority(httpbin_both): """When credentials are passed in URL and via -a at the same time, then the ones from -a are used.""" - url = add_auth(httpbin.url + '/basic-auth/user/password', + url = add_auth(httpbin_both.url + '/basic-auth/user/password', auth='user:wrong') r = http('--auth=user:password', 'GET', url) assert HTTP_OK in r diff --git a/tests/test_binary.py b/tests/test_binary.py index 7c112045a1..9d4702e97e 100644 --- a/tests/test_binary.py +++ b/tests/test_binary.py @@ -6,6 +6,7 @@ class TestBinaryRequestData: + def test_binary_stdin(self, httpbin): with open(BIN_FILE_PATH, 'rb') as stdin: env = TestEnvironment( diff --git a/tests/test_downloads.py b/tests/test_downloads.py index 456886b525..2d973c33e6 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -94,21 +94,21 @@ def exists(filename): class TestDownloads: # TODO: more tests - def test_actual_download(self, httpbin): - url = httpbin.url + '/robots.txt' - body = urlopen(url).read().decode() + 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) - r = http('--download', url, env=env) + r = http('--download', httpbin_both.url + robots_txt, env=env) assert 'Downloading' in r.stderr assert '[K' in r.stderr assert 'Done' in r.stderr assert body == r - def test_download_with_Content_Length(self, httpbin): + def test_download_with_Content_Length(self, httpbin_both): devnull = open(os.devnull, 'w') downloader = Downloader(output_file=devnull, progress_file=devnull) downloader.start(Response( - url=httpbin.url + '/', + url=httpbin_both.url + '/', headers={'Content-Length': 10} )) time.sleep(1.1) @@ -118,20 +118,20 @@ def test_download_with_Content_Length(self, httpbin): downloader.finish() assert not downloader.interrupted - def test_download_no_Content_Length(self, httpbin): + def test_download_no_Content_Length(self, httpbin_both): devnull = open(os.devnull, 'w') downloader = Downloader(output_file=devnull, progress_file=devnull) - downloader.start(Response(url=httpbin.url + '/')) + downloader.start(Response(url=httpbin_both.url + '/')) time.sleep(1.1) downloader.chunk_downloaded(b'12345') downloader.finish() assert not downloader.interrupted - def test_download_interrupted(self, httpbin): + def test_download_interrupted(self, httpbin_both): devnull = open(os.devnull, 'w') downloader = Downloader(output_file=devnull, progress_file=devnull) downloader.start(Response( - url=httpbin.url + '/', + url=httpbin_both.url + '/', headers={'Content-Length': 5} )) downloader.chunk_downloaded(b'1234') diff --git a/tests/test_httpie.py b/tests/test_httpie.py index dd48b1d197..dcfb0d7678 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -26,50 +26,50 @@ def test_version(): assert httpie.__version__ == r.stderr.strip() + r.strip() -def test_GET(httpbin): - r = http('GET', httpbin.url + '/get') +def test_GET(httpbin_both): + r = http('GET', httpbin_both + '/get') assert HTTP_OK in r -def test_DELETE(httpbin): - r = http('DELETE', httpbin.url + '/delete') +def test_DELETE(httpbin_both): + r = http('DELETE', httpbin_both + '/delete') assert HTTP_OK in r -def test_PUT(httpbin): - r = http('PUT', httpbin.url + '/put', 'foo=bar') +def test_PUT(httpbin_both): + r = http('PUT', httpbin_both + '/put', 'foo=bar') assert HTTP_OK in r assert r.json['json']['foo'] == 'bar' -def test_POST_JSON_data(httpbin): - r = http('POST', httpbin.url + '/post', 'foo=bar') +def test_POST_JSON_data(httpbin_both): + r = http('POST', httpbin_both + '/post', 'foo=bar') assert HTTP_OK in r assert r.json['json']['foo'] == 'bar' -def test_POST_form(httpbin): - r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar') +def test_POST_form(httpbin_both): + r = http('--form', 'POST', httpbin_both + '/post', 'foo=bar') assert HTTP_OK in r assert '"foo": "bar"' in r -def test_POST_form_multiple_values(httpbin): - r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar', 'foo=baz') +def test_POST_form_multiple_values(httpbin_both): + r = http('--form', 'POST', httpbin_both + '/post', 'foo=bar', 'foo=baz') assert HTTP_OK in r assert r.json['form'] == {'foo': ['bar', 'baz']} -def test_POST_stdin(httpbin): +def test_POST_stdin(httpbin_both): with open(FILE_PATH) as f: env = TestEnvironment(stdin=f, stdin_isatty=False) - r = http('--form', 'POST', httpbin.url + '/post', env=env) + r = http('--form', 'POST', httpbin_both + '/post', env=env) assert HTTP_OK in r assert FILE_CONTENT in r -def test_headers(httpbin): - r = http('GET', httpbin.url + '/headers', 'Foo:bar') +def test_headers(httpbin_both): + r = http('GET', httpbin_both + '/headers', 'Foo:bar') assert HTTP_OK in r assert '"User-Agent": "HTTPie' in r, r assert '"Foo": "bar"' in r @@ -79,8 +79,8 @@ def test_headers(httpbin): is_py26, reason='the `object_pairs_hook` arg for `json.loads()` is Py>2.6 only' ) -def test_json_input_preserve_order(httpbin): - r = http('PATCH', httpbin.url + '/patch', +def test_json_input_preserve_order(httpbin_both): + r = http('PATCH', httpbin_both + '/patch', 'order:={"map":{"1":"first","2":"second"}}') assert HTTP_OK in r assert r.json['data'] == \ diff --git a/tests/test_ssl.py b/tests/test_ssl.py index b2c7108a7c..a5ed54cd30 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -19,14 +19,10 @@ CA_BUNDLE = pytest_httpbin.certs.where() -@pytest.mark.parametrize( - argnames='ssl_version', - argvalues=SSL_VERSION_ARG_MAPPING.keys() -) +@pytest.mark.parametrize('ssl_version', SSL_VERSION_ARG_MAPPING.keys()) def test_ssl_version(httpbin_secure, ssl_version): try: r = http( - '--verify', CA_BUNDLE, '--ssl', ssl_version, httpbin_secure + '/get' ) @@ -43,20 +39,17 @@ class TestClientCert: def test_cert_and_key(self, httpbin_secure): r = http(httpbin_secure + '/get', - '--verify', CA_BUNDLE, '--cert', CLIENT_CERT, '--cert-key', CLIENT_KEY) assert HTTP_OK in r def test_cert_pem(self, httpbin_secure): r = http(httpbin_secure + '/get', - '--verify', CA_BUNDLE, '--cert', CLIENT_PEM) assert HTTP_OK in r def test_cert_file_not_found(self, httpbin_secure): r = http(httpbin_secure + '/get', - '--verify', CA_BUNDLE, '--cert', '/__not_found__', error_exit_ok=True) assert r.exit_status == ExitStatus.ERROR @@ -65,30 +58,30 @@ def test_cert_file_not_found(self, httpbin_secure): def test_cert_file_invalid(self, httpbin_secure): with pytest.raises(SSLError): http(httpbin_secure + '/get', - '--verify', CA_BUNDLE, '--cert', __file__) def test_cert_ok_but_missing_key(self, httpbin_secure): with pytest.raises(SSLError): http(httpbin_secure + '/get', - '--verify', CA_BUNDLE, '--cert', CLIENT_CERT) class TestServerCert: + def test_verify_no_OK(self, httpbin_secure): r = http(httpbin_secure.url + '/get', '--verify=no') assert HTTP_OK in r def test_verify_custom_ca_bundle_path( - self, httpbin_secure): - r = http(httpbin_secure.url + '/get', '--verify', CA_BUNDLE) + self, httpbin_secure_untrusted): + r = http(httpbin_secure_untrusted + '/get', '--verify', CA_BUNDLE) assert HTTP_OK in r def test_self_signed_server_cert_by_default_raises_ssl_error( - self, httpbin_secure): + self, + httpbin_secure_untrusted): with pytest.raises(SSLError): - http(httpbin_secure.url + '/get') + http(httpbin_secure_untrusted.url + '/get') def test_verify_custom_ca_bundle_invalid_path(self, httpbin_secure): with pytest.raises(SSLError): From 6e1dbadff94c2ed168119cd17df37d7ec9cb8d05 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 6 Mar 2016 02:09:52 +0800 Subject: [PATCH 0213/1182] Replace --show-redirects with --all and add --print-others, -P With --all, any intermediary requests/responses are shown (such as redirects or the initial unauthorized Digest auth request). The --print-others, -P option works like --print, -p, but only applies to intermediary requests/responses. The default behaviour is to inherit the value of -p. --- CHANGELOG.rst | 3 ++- README.rst | 36 ++++++++++++++++++++++--- httpie/cli.py | 57 +++++++++++++++++++++++++--------------- httpie/core.py | 15 +++++++---- httpie/input.py | 36 +++++++++++++++++-------- httpie/output/streams.py | 10 +++---- tests/test_redirects.py | 32 ++++++++++++++++++---- 7 files changed, 137 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8c37eafa68..c70698d5c5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,7 +14,8 @@ This project adheres to `Semantic Versioning `_. to use for HTTPS requests. * Added JSON detection with ``--json, -j`` to work around incorrect ``Content-Type`` -* Added ``--show-redirects, -R`` to show intermediate responses with ``--follow`` +* Added ``--all`` to show intermediate responses such as redirects (with ``--follow``) +* Added ``--print-others, -P WHAT`` * Added ``--max-redirects`` (default 30) * Added ``-A`` as short name for ``--auth-type`` * Added ``-F`` as short name for ``--follow`` diff --git a/README.rst b/README.rst index 9941607384..50ab6937b3 100644 --- a/README.rst +++ b/README.rst @@ -636,7 +636,7 @@ response is shown. To instruct HTTPie to follow the ``Location`` header of ``30x`` responses and show the final response instead, use the ``--follow, -F`` option. If you additionally wish to see the intermediary requests/responses, -then use the ``--show-redirects, -R`` option as well. +then use the ``--all`` option as well. To change the default limit of maximum 30 redirects, use the ``--max-redirects=`` option. @@ -644,7 +644,7 @@ To change the default limit of maximum 30 redirects, use the .. code-block:: bash - $ http --follow --show-redirects --max-redirects=5 httpbin.org/redirect/3 + $ http --follow --all --max-redirects=5 httpbin.org/redirect/3 ======= @@ -771,8 +771,8 @@ You can use the following command to test SNI support: Output Options ============== -By default, HTTPie outputs the whole response message (headers as well as the -body). +By default, HTTPie only outputs the final response and whole response message +is printed (headers as well as the body). You can control what should be printed via several options: @@ -780,6 +780,7 @@ You can control what should 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). ``--print, -p`` Selects parts of the HTTP exchange. ================= ===================================================== @@ -833,6 +834,33 @@ Print request and response headers: $ http --print=Hh PUT httpbin.org/put hello=world +--------------------------------------- +Viewing Intermediary Requests/Responses +--------------------------------------- + +If you'd like to see any intermediary requests/responses together with the +final one, then use the ``--all`` option. Intermediary requests include +followed redirects (with ``--follow``), the first unauthorized request when +Digest auth is used (``--auth=digest``), etc. They are by default also +formatted according to ``--print, -p`` (and its shortcuts described above), +which can be customized with ``--print-others, -P`` which takes the same +arguments as ``--print, -p`` but applies to the intermediary requests only. + + +View all responses that lead to the final one: + +.. code-block:: bash + + $ http --all --follow httpbin.org/redirect/3 + + +Print the final and the intermediary requests/responses differently: + +.. code-block:: bash + + $ http --all --follow --print=hH --print-others=H httpbin.org/redirect/3 + + ------------------------- Conditional Body Download ------------------------- diff --git a/httpie/cli.py b/httpie/cli.py index f964b23318..5ddfe47209 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -250,17 +250,6 @@ def _split_lines(self, text, width): default=OUTPUT_OPTIONS_DEFAULT, ) ) -output_options.add_argument( - '--verbose', '-v', - dest='output_options', - action='store_const', - const=''.join(OUTPUT_OPTIONS), - help=""" - Print the whole request as well as the response. Shortcut for --print={0}. - - """ - .format(''.join(OUTPUT_OPTIONS)) -) output_options.add_argument( '--headers', '-h', dest='output_options', @@ -284,6 +273,42 @@ def _split_lines(self, text, width): .format(OUT_RESP_BODY) ) +output_options.add_argument( + '--verbose', '-v', + dest='verbose', + action='store_true', + help=""" + Verbose output. Print the whole request as well as the response. Also print + any intermediary requests/responses (such as redirects). + It's a shortcut for: --all --print={0} + + """ + .format(''.join(OUTPUT_OPTIONS)) +) +output_options.add_argument( + '--all', + default=False, + action='store_true', + help=""" + By default, only the final request/response is shown. Use this flag to show + any intermediary requests/responses as well. Intermediary requests include + followed redirects (with --follow), the first unauthorized request when + Digest auth is used (--auth=digest), etc. + + """ +) +output_options.add_argument( + '--print-others', '-P', + dest='output_options_others', + metavar='WHAT', + help=""" + The same as --print, -p but applies only to intermediary requests/responses + (such as redirects) when their inclusion is enabled with --all. If this + options is not specified, then they are formatted the same way as the final + response. + + """ +) output_options.add_argument( '--stream', '-S', action='store_true', @@ -454,16 +479,6 @@ def _split_lines(self, text, width): """ ) -network.add_argument( - '--show-redirects', '-R', - default=False, - action='store_true', - help=""" - Show all responses within the redirect chain (works with --follow). - - """ -) - network.add_argument( '--max-redirects', type=int, diff --git a/httpie/core.py b/httpie/core.py index 4c224b8a10..c3c9b33acc 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -96,11 +96,11 @@ def program(args, env, log_error): ) downloader.pre_request(args.headers) - last_response = get_response(args, config_dir=env.config.directory) - if args.show_redirects: - responses = last_response.history + [last_response] + final_response = get_response(args, config_dir=env.config.directory) + if args.all: + responses = final_response.history + [final_response] else: - responses = [last_response] + responses = [final_response] for response in responses: @@ -121,6 +121,11 @@ def program(args, env, log_error): env=env, request=response.request, response=response, + output_options=( + args.output_options + if response is final_response + else args.output_options_others + ) ), # NOTE: `env.stdout` will in fact be `stderr` with `--download` 'outfile': env.stdout, @@ -140,7 +145,7 @@ def program(args, env, log_error): if downloader and exit_status == ExitStatus.OK: # Last response body download. - download_stream, download_to = downloader.start(last_response) + download_stream, download_to = downloader.start(final_response) write_stream( stream=download_stream, outfile=download_to, diff --git a/httpie/input.py b/httpie/input.py index c622b65b4d..39c112d398 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -359,18 +359,32 @@ def _process_output_options(self): The default output options are stdout-type-sensitive. """ - if not self.args.output_options: - self.args.output_options = ( - OUTPUT_OPTIONS_DEFAULT - if self.env.stdout_isatty - else OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED - ) + def check_options(value, option): + unknown = set(value) - OUTPUT_OPTIONS + if unknown: + self.error('Unknown output options: {0}={1}'.format( + option, + ','.join(unknown) + )) + + if self.args.verbose: + self.args.all = True + + if self.args.output_options is None: + if self.args.verbose: + self.args.output_options = ''.join(OUTPUT_OPTIONS) + else: + self.args.output_options = ( + OUTPUT_OPTIONS_DEFAULT + if self.env.stdout_isatty + else OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED + ) - unknown_output_options = set(self.args.output_options) - OUTPUT_OPTIONS - if unknown_output_options: - self.error( - 'Unknown output options: %s' % ','.join(unknown_output_options) - ) + if self.args.output_options_others is None: + self.args.output_options_others = self.args.output_options + + check_options(self.args.output_options, '--print') + check_options(self.args.output_options_others, '--print-others') if self.args.download and OUT_RESP_BODY in self.args.output_options: # Response body is always downloaded with --download and it goes diff --git a/httpie/output/streams.py b/httpie/output/streams.py index b22698142c..3483a6d3ce 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -55,15 +55,15 @@ def write_stream_with_colors_win_py3(stream, outfile, flush): outfile.flush() -def build_output_stream(args, env, request, response): +def build_output_stream(args, env, request, response, output_options): """Build and return a chain of iterators over the `request`-`response` exchange each of which yields `bytes` chunks. """ - req_h = OUT_REQ_HEAD in args.output_options - req_b = OUT_REQ_BODY in args.output_options - resp_h = OUT_RESP_HEAD in args.output_options - resp_b = OUT_RESP_BODY in args.output_options + req_h = OUT_REQ_HEAD in output_options + req_b = OUT_REQ_BODY in output_options + resp_h = OUT_RESP_HEAD in output_options + resp_b = OUT_RESP_BODY in output_options req = req_h or req_b resp = resp_h or resp_b diff --git a/tests/test_redirects.py b/tests/test_redirects.py index e96ea8e5f1..579f5c6c2a 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -3,16 +3,38 @@ from utils import http, HTTP_OK -def test_follow_no_show_redirects(httpbin): +def test_follow_all_redirects_shown(httpbin): + r = http('--follow', '--all', httpbin.url + '/redirect/2') + assert r.count('HTTP/1.1') == 3 + assert r.count('HTTP/1.1 302 FOUND', 2) + assert HTTP_OK in r + + +def test_follow_without_all_redirects_hidden(httpbin): r = http('--follow', httpbin.url + '/redirect/2') assert r.count('HTTP/1.1') == 1 assert HTTP_OK in r -def test_follow_show_redirects(httpbin): - r = http('--follow', '--show-redirects', httpbin.url + '/redirect/2') - assert r.count('HTTP/1.1') == 3 - assert r.count('HTTP/1.1 302 FOUND', 2) +def test_follow_all_output_options_used_for_redirects(httpbin): + r = http('--check-status', + '--follow', + '--all', + '--print=H', + httpbin.url + '/redirect/2') + assert r.count('GET /') == 3 + assert HTTP_OK not in r + + +def test_follow_redirect_output_options(httpbin): + r = http('--check-status', + '--follow', + '--all', + '--print=h', + '--print-others=H', + httpbin.url + '/redirect/2') + assert r.count('GET /') == 2 + assert 'HTTP/1.1 302 FOUND' not in r assert HTTP_OK in r From 7ce6eb148ef2c406d780e2f932bfdc2b5f8f96ec Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 7 Mar 2016 07:09:58 +0800 Subject: [PATCH 0214/1182] Typo --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 50ab6937b3..c5df2ed455 100644 --- a/README.rst +++ b/README.rst @@ -771,8 +771,8 @@ You can use the following command to test SNI support: Output Options ============== -By default, HTTPie only outputs the final response and whole response message -is printed (headers as well as the body). +By default, HTTPie only outputs the final response and the whole response +message is printed (headers as well as the body). You can control what should be printed via several options: From 25d1e8e418425a208eca285cbe435a5914da542c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 7 Mar 2016 11:46:59 +0800 Subject: [PATCH 0215/1182] Add `Accept-Encoding: identity` for --download #423 --- httpie/downloads.py | 9 +++++---- tests/test_ssl.py | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/httpie/downloads.py b/httpie/downloads.py index e6064a354a..b49e335285 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -178,8 +178,8 @@ def pre_request(self, request_headers): :type request_headers: dict """ - # Disable content encoding so that we can resume, etc. - request_headers['Accept-Encoding'] = None + # Ask the server not to encode the content so that we can resume, etc. + request_headers['Accept-Encoding'] = 'identity' if self._resume: bytes_have = os.path.getsize(self._output_file.name) if bytes_have: @@ -201,6 +201,8 @@ def start(self, response): """ assert not self.status.time_started + # FIXME: some servers still might sent Content-Encoding: gzip + # try: total_size = int(response.headers['Content-Length']) except (KeyError, ValueError, TypeError): @@ -299,8 +301,7 @@ def __init__(self): def started(self, resumed_from=0, total_size=None): assert self.time_started is None - if total_size is not None: - self.total_size = total_size + self.total_size = total_size self.downloaded = self.resumed_from = resumed_from self.time_started = time() diff --git a/tests/test_ssl.py b/tests/test_ssl.py index a5ed54cd30..b226186e4c 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -13,6 +13,7 @@ CLIENT_KEY = os.path.join(TESTS_ROOT, 'client_certs', 'client.key') CLIENT_PEM = os.path.join(TESTS_ROOT, 'client_certs', 'client.pem') +# FIXME: # We test against a local httpbin instance which uses a self-signed cert. # Requests without --verify= will fail with a verification error. # See: https://github.com/kevin1024/pytest-httpbin#https-support From 8881ebf0333a763e2cb79c9b1aeec185c58f00bb Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 9 Mar 2016 13:49:00 +0800 Subject: [PATCH 0216/1182] Changed the version icon label to include to word "stable" --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index c5df2ed455..077b0ed576 100644 --- a/README.rst +++ b/README.rst @@ -1431,7 +1431,7 @@ Please see `LICENSE `_. .. _claudiatd/httpie-artwork: https://github.com/claudiatd/httpie-artwork -.. |pypi| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square&label=latest%20version +.. |pypi| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square&label=latest%20stable%20version :target: https://pypi.python.org/pypi/httpie :alt: Latest version released on PyPi From 76e15b227cd4136d2748ac0c3aca08726f5d8cd8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 9 Mar 2016 21:58:11 +0800 Subject: [PATCH 0217/1182] Added test_verbose_implies_all --- tests/test_output.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_output.py b/tests/test_output.py index d20abade76..d4ac560cb4 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -45,6 +45,13 @@ def test_verbose_json(self, httpbin): assert HTTP_OK in r assert '"baz": "bar"' in r + def test_verbose_implies_all(self, httpbin): + r = http('--verbose', '--follow', httpbin + '/redirect/1') + assert 'GET /redirect/1 HTTP/1.1' in r + assert 'HTTP/1.1 302 FOUND' in r + assert 'GET /get HTTP/1.1' in r + assert HTTP_OK in r + class TestColors: From 35a99fe04b9f6c0c3879e42d81843bb0f4f9b637 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 9 Mar 2016 21:58:34 +0800 Subject: [PATCH 0218/1182] Added test for -F shortcut --- tests/test_redirects.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test_redirects.py b/tests/test_redirects.py index 579f5c6c2a..7c1ab5061a 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -1,4 +1,6 @@ """High-level tests.""" +import pytest + from httpie import ExitStatus from utils import http, HTTP_OK @@ -10,8 +12,9 @@ def test_follow_all_redirects_shown(httpbin): assert HTTP_OK in r -def test_follow_without_all_redirects_hidden(httpbin): - r = http('--follow', httpbin.url + '/redirect/2') +@pytest.mark.parametrize('follow_flag', ['--follow', '-F']) +def test_follow_without_all_redirects_hidden(httpbin, follow_flag): + r = http(follow_flag, httpbin.url + '/redirect/2') assert r.count('HTTP/1.1') == 1 assert HTTP_OK in r From 7c68d87c103a91d8d3603bc783881cb4cc8c85c2 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 10 Mar 2016 14:27:33 +0800 Subject: [PATCH 0219/1182] README --- CHANGELOG.rst | 4 ++-- README.rst | 32 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c70698d5c5..ce50d3029d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,8 +15,8 @@ This project adheres to `Semantic Versioning `_. * Added JSON detection with ``--json, -j`` to work around incorrect ``Content-Type`` * Added ``--all`` to show intermediate responses such as redirects (with ``--follow``) -* Added ``--print-others, -P WHAT`` -* Added ``--max-redirects`` (default 30) +* Added ``--print-others, -P WHAT`` to specify formatting of intermediate responses +* Added ``--max-redirects=N`` (default 30) * Added ``-A`` as short name for ``--auth-type`` * Added ``-F`` as short name for ``--follow`` * Removed the ``implicit_content_type`` config option diff --git a/README.rst b/README.rst index 077b0ed576..596a67fc9b 100644 --- a/README.rst +++ b/README.rst @@ -821,10 +821,10 @@ the HTTP exchange: ========== ================== Character Stands for ========== ================== -``H`` Request headers. -``B`` Request body. -``h`` Response headers. -``b`` Response body. +``H`` request headers +``B`` request body +``h`` response headers +``b`` response body ========== ================== Print request and response headers: @@ -838,27 +838,27 @@ Print request and response headers: Viewing Intermediary Requests/Responses --------------------------------------- -If you'd like to see any intermediary requests/responses together with the -final one, then use the ``--all`` option. Intermediary requests include -followed redirects (with ``--follow``), the first unauthorized request when -Digest auth is used (``--auth=digest``), etc. They are by default also -formatted according to ``--print, -p`` (and its shortcuts described above), -which can be customized with ``--print-others, -P`` which takes the same -arguments as ``--print, -p`` but applies to the intermediary requests only. - - -View all responses that lead to the final one: +To see any intermediary requests/responses together with the final one, +use the ``--all`` option. Intermediary requests include followed redirects +(with ``--follow``), the first unauthorized request when HTTP digest +authentication is used (``--auth=digest``), etc. .. code-block:: bash + # Include all responses that lead to the final one: $ http --all --follow httpbin.org/redirect/3 -Print the final and the intermediary requests/responses differently: +The intermediary requests/response are by default formatted according to +``--print, -p`` (and its shortcuts described above). If you'd like to change +that, use the ``--print-others, -P`` option. It takes the same +arguments as ``--print, -p`` but applies to the intermediary requests only. + .. code-block:: bash - $ http --all --follow --print=hH --print-others=H httpbin.org/redirect/3 + # Print the intermediary requests/responses differently than the final one: + $ http -A digest -a foo:bar --all -p Hh -P H httpbin.org/digest-auth/auth/foo/bar ------------------------- From 001bda19450ad85c91345eea3cfa3991e1d492ba Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 17 Mar 2016 15:00:50 +0800 Subject: [PATCH 0220/1182] README --- README.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 596a67fc9b..766fc800e4 100644 --- a/README.rst +++ b/README.rst @@ -838,8 +838,9 @@ Print request and response headers: Viewing Intermediary Requests/Responses --------------------------------------- -To see any intermediary requests/responses together with the final one, -use the ``--all`` option. Intermediary requests include followed redirects +To see *all* the HTTP communication, i.e. the final request/resposne as +well as any possible intermediary requests/responses, use the **``--all``** +option. The intermediary HTTP communication include followed redirects (with ``--follow``), the first unauthorized request when HTTP digest authentication is used (``--auth=digest``), etc. @@ -851,7 +852,7 @@ authentication is used (``--auth=digest``), etc. The intermediary requests/response are by default formatted according to ``--print, -p`` (and its shortcuts described above). If you'd like to change -that, use the ``--print-others, -P`` option. It takes the same +that, use the **``--print-others, -P``** option. It takes the same arguments as ``--print, -p`` but applies to the intermediary requests only. From 5300b0b490b8db48fac30b5e32164be93dc574b7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 17 Mar 2016 15:58:01 +0800 Subject: [PATCH 0221/1182] Fixed #451 - OSError: [Errno 36] File name too long --- CHANGELOG.rst | 1 + httpie/downloads.py | 36 ++++++++++++++++++++++++++++++++++-- tests/test_downloads.py | 34 ++++++++++++++++++++++++++++++---- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ce50d3029d..23bda11a70 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,6 +27,7 @@ This project adheres to `Semantic Versioning `_. of light and dark terminals * Improved ``--debug`` output * Fixed ``--session`` when used with ``--download`` +* Fixed ``--download`` to trim too long filenames before saving the file * Fixed handling of ``Content-Type`` with multiple ``+subtype`` parts diff --git a/httpie/downloads.py b/httpie/downloads.py index b49e335285..972151e1f0 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -7,6 +7,7 @@ import os import re import sys +import errno import mimetypes import threading from time import sleep, time @@ -135,12 +136,43 @@ def filename_from_url(url, content_type): return fn +def trim_filename(filename, max_len): + if len(filename) > max_len: + trim_by = len(filename) - max_len + name, ext = os.path.splitext(filename) + if trim_by >= len(name): + filename = filename[:-trim_by] + else: + filename = name[:-trim_by] + ext + return filename + + +def get_filename_max_length(directory): + try: + max_len = os.pathconf(directory, 'PC_NAME_MAX') + except OSError as e: + if e.errno == errno.EINVAL: + max_len = 255 + else: + raise + return max_len + + +def trim_filename_if_needed(filename, directory='.', extra=0): + max_len = get_filename_max_length(directory) - extra + if len(filename) > max_len: + filename = trim_filename(filename, max_len) + return filename + + def get_unique_filename(filename, exists=os.path.exists): attempt = 0 while True: suffix = '-' + str(attempt) if attempt > 0 else '' - if not exists(filename + suffix): - return filename + suffix + try_filename = trim_filename_if_needed(filename, extra=len(suffix)) + try_filename += suffix + if not exists(try_filename): + return try_filename attempt += 1 diff --git a/tests/test_downloads.py b/tests/test_downloads.py index 2d973c33e6..e09bdde327 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -2,6 +2,7 @@ import time import pytest +import mock from requests.structures import CaseInsensitiveDict from httpie.compat import urlopen @@ -74,7 +75,31 @@ def test_filename_from_url(self): content_type='x-foo/bar' ) - def test_unique_filename(self): + @pytest.mark.parametrize( + 'orig_name, unique_on_attempt, expected', + [ + # Simple + ('foo.bar', 0, 'foo.bar'), + ('foo.bar', 1, 'foo.bar-1'), + ('foo.bar', 10, 'foo.bar-10'), + # Trim + ('A' * 20, 0, 'A' * 10), + ('A' * 20, 1, 'A' * 8 + '-1'), + ('A' * 20, 10, 'A' * 7 + '-10'), + # Trim before ext + ('A' * 20 + '.txt', 0, 'A' * 6 + '.txt'), + ('A' * 20 + '.txt', 1, 'A' * 4 + '.txt-1'), + # Trim at the end + ('foo.' + 'A' * 20, 0, 'foo.' + 'A' * 6), + ('foo.' + 'A' * 20, 1, 'foo.' + 'A' * 4 + '-1'), + ('foo.' + 'A' * 20, 10, 'foo.' + 'A' * 3 + '-10'), + ] + ) + @mock.patch('httpie.downloads.get_filename_max_length') + def test_unique_filename(self, get_filename_max_length, + orig_name, unique_on_attempt, + expected): + def attempts(unique_on_attempt=0): # noinspection PyUnresolvedReferences,PyUnusedLocal def exists(filename): @@ -86,9 +111,10 @@ def exists(filename): exists.attempt = 0 return exists - assert 'foo.bar' == get_unique_filename('foo.bar', attempts(0)) - assert 'foo.bar-1' == get_unique_filename('foo.bar', attempts(1)) - assert 'foo.bar-10' == get_unique_filename('foo.bar', attempts(10)) + get_filename_max_length.return_value = 10 + + actual = get_unique_filename(orig_name, attempts(unique_on_attempt)) + assert expected == actual class TestDownloads: From 557911b606d1609016985fdb67aae6970b7363ed Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 17 Mar 2016 16:14:14 +0800 Subject: [PATCH 0222/1182] Handle that os.pathconf is posix-only --- httpie/downloads.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/httpie/downloads.py b/httpie/downloads.py index 972151e1f0..58e7b943e9 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -148,13 +148,17 @@ def trim_filename(filename, max_len): def get_filename_max_length(directory): + max_len = 255 try: - max_len = os.pathconf(directory, 'PC_NAME_MAX') - except OSError as e: - if e.errno == errno.EINVAL: - max_len = 255 - else: - raise + pathconf = os.pathconf + except AttributeError: + pass # non-posix + else: + try: + max_len = pathconf(directory, 'PC_NAME_MAX') + except OSError as e: + if e.errno != errno.EINVAL: + raise return max_len From 293295cad6547e9e3e59bc2888d94b6b6ba03c8e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 18 Mar 2016 09:15:44 +0800 Subject: [PATCH 0223/1182] Removed XML formatter Closes #443 Closes #389 Closes #415 Closes #384 Closes #394 --- CHANGELOG.rst | 2 ++ httpie/output/formatters/xml.py | 61 --------------------------------- httpie/plugins/__init__.py | 2 -- 3 files changed, 2 insertions(+), 63 deletions(-) delete mode 100644 httpie/output/formatters/xml.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 23bda11a70..7e95e30c40 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,6 +29,8 @@ This project adheres to `Semantic Versioning `_. * Fixed ``--session`` when used with ``--download`` * Fixed ``--download`` to trim too long filenames before saving the file * Fixed handling of ``Content-Type`` with multiple ``+subtype`` parts +* Removed XML formatting as the implementation suffered from multiple issues + `0.9.3`_ (2016-01-01) diff --git a/httpie/output/formatters/xml.py b/httpie/output/formatters/xml.py deleted file mode 100644 index dc82e5bea7..0000000000 --- a/httpie/output/formatters/xml.py +++ /dev/null @@ -1,61 +0,0 @@ -from __future__ import absolute_import -import re -from xml.etree import ElementTree - -from httpie.plugins import FormatterPlugin - - -DECLARATION_RE = re.compile('<\?xml[^\n]+?\?>', flags=re.I) -DOCTYPE_RE = re.compile('', flags=re.I) - - -DEFAULT_INDENT = 4 - - -def indent(elem, indent_text=' ' * DEFAULT_INDENT): - """ - In-place prettyprint formatter - C.f. http://effbot.org/zone/element-lib.htm#prettyprint - - """ - def _indent(elem, level=0): - i = "\n" + level * indent_text - if len(elem): - if not elem.text or not elem.text.strip(): - elem.text = i + indent_text - if not elem.tail or not elem.tail.strip(): - elem.tail = i - for elem in elem: - _indent(elem, level + 1) - if not elem.tail or not elem.tail.strip(): - elem.tail = i - else: - if level and (not elem.tail or not elem.tail.strip()): - elem.tail = i - - return _indent(elem) - - -class XMLFormatter(FormatterPlugin): - # TODO: tests - - def format_body(self, body, mime): - if 'xml' in mime: - # FIXME: orig NS names get forgotten during the conversion, etc. - try: - root = ElementTree.fromstring(body.encode('utf8')) - except ElementTree.ParseError: - # Ignore invalid XML errors (skips attempting to pretty print) - pass - else: - indent(root) - # Use the original declaration - declaration = DECLARATION_RE.match(body) - doctype = DOCTYPE_RE.match(body) - body = ElementTree.tostring(root, encoding='utf-8')\ - .decode('utf8') - if doctype: - body = '%s\n%s' % (doctype.group(0), body) - if declaration: - body = '%s\n%s' % (declaration.group(0), body) - return body diff --git a/httpie/plugins/__init__.py b/httpie/plugins/__init__.py index 4be81e7a30..13b8565006 100644 --- a/httpie/plugins/__init__.py +++ b/httpie/plugins/__init__.py @@ -11,7 +11,6 @@ from httpie.plugins.builtin import BasicAuthPlugin, DigestAuthPlugin from httpie.output.formatters.headers import HeadersFormatter from httpie.output.formatters.json import JSONFormatter -from httpie.output.formatters.xml import XMLFormatter from httpie.output.formatters.colors import ColorFormatter @@ -20,5 +19,4 @@ DigestAuthPlugin) plugin_manager.register(HeadersFormatter, JSONFormatter, - XMLFormatter, ColorFormatter) From 33eb9acd92b876ff86bfa39666b7610d1f93eb4c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 18 Mar 2016 09:20:19 +0800 Subject: [PATCH 0224/1182] Updated README --- README.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/README.rst b/README.rst index 766fc800e4..77221c9cf4 100644 --- a/README.rst +++ b/README.rst @@ -1000,7 +1000,6 @@ Also, the following formatting is applied: * HTTP headers are sorted by name. * JSON data is indented, sorted by keys, and unicode escapes are converted to the characters they represent. -* XML data is indented for better readability. One of these options can be used to control output processing: From ec245a1e80827ef777902c98fa5fb2328c003f74 Mon Sep 17 00:00:00 2001 From: Jeff Dickey Date: Wed, 6 Apr 2016 11:28:03 -0700 Subject: [PATCH 0225/1182] added completions for fish shell --- httpie-completion.fish | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 httpie-completion.fish diff --git a/httpie-completion.fish b/httpie-completion.fish new file mode 100644 index 0000000000..4e4efd30a5 --- /dev/null +++ b/httpie-completion.fish @@ -0,0 +1,60 @@ +function __fish_httpie_auth_types + echo "basic"\t"Basic HTTP auth" + echo "digest"\t"Digest HTTP auth" +end + +function __fish_httpie_styles + echo "autumn" + echo "borland" + echo "bw" + echo "colorful" + echo "default" + echo "emacs" + echo "friendly" + echo "fruity" + echo "igor" + echo "manni" + echo "monokai" + echo "murphy" + echo "native" + echo "paraiso-dark" + echo "paraiso-light" + echo "pastie" + echo "perldoc" + echo "rrt" + echo "solarized" + echo "tango" + echo "trac" + echo "vim" + echo "vs" + echo "xcode" +end + +complete -x -c http -s s -l style -d 'Output coloring style (default is "monokai")' -A -a "autumn borland bw colorful default emacs friendly fruity igor manni monokai murphy native paraiso-dark paraiso-light pastie perldoc rrt solarized tango trac vim vs xcode" +complete -c http -s f -l form -d 'Data items from the command line are serialized as form fields' +complete -c http -s j -l json -d '(default) Data items from the command line are serialized as a JSON object' +complete -x -c http -l pretty -d 'Controls output processing' -a "all colors format none" -A +complete -x -c http -s s -l style -d 'Output coloring style (default is "monokai")' -A -a "autumn borland bw colorful default emacs friendly fruity igor manni monokai murphy native paraiso-dark paraiso-light pastie perldoc rrt solarized tango trac vim vs xcode" +complete -x -c http -s p -l print -d 'String specifying what the output should contain' +complete -c http -s v -l verbose -d 'Print the whole request as well as the response' +complete -c http -s h -l headers -d 'Print only the response headers' +complete -c http -s b -l body -d 'Print only the response body' +complete -c http -s S -l stream -d 'Always stream the output by line' +complete -c http -s o -l output -d 'Save output to FILE' +complete -c http -s d -l download -d 'Do not print the response body to stdout' +complete -c http -s c -l continue -d 'Resume an interrupted download' +complete -x -c http -l session -d 'Create, or reuse and update a session' +complete -x -c http -s a -l auth -d 'If only the username is provided (-a username), HTTPie will prompt for the password' +complete -x -c http -l auth-type -d 'The authentication mechanism to be used' -a '(__fish_httpie_auth_types)' -A +complete -x -c http -l proxy -d 'String mapping protocol to the URL of the proxy' +complete -c http -l follow -d 'Allow full redirects' +complete -x -c http -l verify -d 'SSL cert verification' +complete -c http -l cert -d 'SSL cert' +complete -c http -l cert-key -d 'Private SSL cert key' +complete -x -c http -l timeout -d 'Connection timeout in seconds' +complete -c http -l check-status -d 'Error with non-200 HTTP status code' +complete -c http -l ignore-stdin -d 'Do not attempt to read stdin' +complete -c http -l help -d 'Show help' +complete -c http -l version -d 'Show version' +complete -c http -l traceback -d 'Prints exception traceback should one occur' +complete -c http -l debug -d 'Show debugging information' From eba6b63c55579c28bdaa45b76e805b3f0f698d35 Mon Sep 17 00:00:00 2001 From: Kyle Mathews Date: Mon, 18 Apr 2016 15:11:04 -0700 Subject: [PATCH 0226/1182] Remove extra backtick. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 77221c9cf4..545293d7dc 100644 --- a/README.rst +++ b/README.rst @@ -737,7 +737,7 @@ SSL version Use the ``--ssl=`` 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``. (The actually available set of protocols may vary depending on your OpenSSL installation.) .. code-block:: bash From 9fbe745987cd4faca843f9442e0240f84fcfff43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Thu, 28 Apr 2016 12:28:20 +0200 Subject: [PATCH 0227/1182] Update readthedocs links. --- httpie/client.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 3304927997..e8a9ef302e 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -14,7 +14,7 @@ from httpie.utils import repr_dict_nice try: - # https://urllib3.readthedocs.org/en/latest/security.html + # https://urllib3.readthedocs.io/en/latest/security.html urllib3.disable_warnings() except AttributeError: # In some rare cases, the user may have an old version of the requests diff --git a/setup.py b/setup.py index 9af190804c..d1d6e793f5 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,7 @@ def run_tests(self): # bdist_wheel extras_require = { - # http://wheel.readthedocs.org/en/latest/#defining-conditional-dependencies + # 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'], From 098257c0be7c63c56bb5484f907538075f8cab25 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jul 2016 18:49:27 +0200 Subject: [PATCH 0228/1182] Rename --print-others to --history-print. --- CHANGELOG.rst | 2 +- README.rst | 2 +- httpie/cli.py | 4 ++-- httpie/core.py | 2 +- httpie/input.py | 6 +++--- tests/test_redirects.py | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7e95e30c40..101e69f071 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,7 +15,7 @@ This project adheres to `Semantic Versioning `_. * Added JSON detection with ``--json, -j`` to work around incorrect ``Content-Type`` * Added ``--all`` to show intermediate responses such as redirects (with ``--follow``) -* Added ``--print-others, -P WHAT`` to specify formatting of intermediate responses +* Added ``--history-print, -P WHAT`` to specify formatting of intermediate responses * Added ``--max-redirects=N`` (default 30) * Added ``-A`` as short name for ``--auth-type`` * Added ``-F`` as short name for ``--follow`` diff --git a/README.rst b/README.rst index 545293d7dc..afacd452c0 100644 --- a/README.rst +++ b/README.rst @@ -852,7 +852,7 @@ authentication is used (``--auth=digest``), etc. The intermediary requests/response are by default formatted according to ``--print, -p`` (and its shortcuts described above). If you'd like to change -that, use the **``--print-others, -P``** option. It takes the same +that, use the ``--history-print, -P`` option. It takes the same arguments as ``--print, -p`` but applies to the intermediary requests only. diff --git a/httpie/cli.py b/httpie/cli.py index 5ddfe47209..b35d33fbbb 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -298,8 +298,8 @@ def _split_lines(self, text, width): """ ) output_options.add_argument( - '--print-others', '-P', - dest='output_options_others', + '--history-print', '-P', + dest='output_options_history', metavar='WHAT', help=""" The same as --print, -p but applies only to intermediary requests/responses diff --git a/httpie/core.py b/httpie/core.py index c3c9b33acc..31e5c48bdc 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -124,7 +124,7 @@ def program(args, env, log_error): output_options=( args.output_options if response is final_response - else args.output_options_others + else args.output_options_history ) ), # NOTE: `env.stdout` will in fact be `stderr` with `--download` diff --git a/httpie/input.py b/httpie/input.py index 39c112d398..85cb9a2707 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -380,11 +380,11 @@ def check_options(value, option): else OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED ) - if self.args.output_options_others is None: - self.args.output_options_others = self.args.output_options + if self.args.output_options_history is None: + self.args.output_options_history = self.args.output_options check_options(self.args.output_options, '--print') - check_options(self.args.output_options_others, '--print-others') + check_options(self.args.output_options_history, '--history-print') if self.args.download and OUT_RESP_BODY in self.args.output_options: # Response body is always downloaded with --download and it goes diff --git a/tests/test_redirects.py b/tests/test_redirects.py index 7c1ab5061a..1895ea042a 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -34,7 +34,7 @@ def test_follow_redirect_output_options(httpbin): '--follow', '--all', '--print=h', - '--print-others=H', + '--history-print=H', httpbin.url + '/redirect/2') assert r.count('GET /') == 2 assert 'HTTP/1.1 302 FOUND' not in r From 963b2746f55c5d94c9a81647e5840b98882ea9b8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jul 2016 18:57:13 +0200 Subject: [PATCH 0229/1182] Be more liberal when detecting JSON in the formatter Closes #485 --- httpie/output/formatters/json.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/httpie/output/formatters/json.py b/httpie/output/formatters/json.py index 64b15f0ed9..5a3e9bc93b 100644 --- a/httpie/output/formatters/json.py +++ b/httpie/output/formatters/json.py @@ -10,7 +10,13 @@ class JSONFormatter(FormatterPlugin): def format_body(self, body, mime): - if 'json' in mime or self.kwargs['explicit_json']: + maybe_json = [ + 'json', + 'javascript', + 'text', + ] + if (any(token in mime for token in maybe_json) or + self.kwargs['explicit_json']): try: obj = json.loads(body) except ValueError: From 65081b2f12cc78a3c8ef1c80043dfc0cd5c65e55 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jul 2016 19:00:06 +0200 Subject: [PATCH 0230/1182] Cleanup --- httpie/output/formatters/json.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httpie/output/formatters/json.py b/httpie/output/formatters/json.py index 5a3e9bc93b..6d8c89ef90 100644 --- a/httpie/output/formatters/json.py +++ b/httpie/output/formatters/json.py @@ -15,8 +15,8 @@ def format_body(self, body, mime): 'javascript', 'text', ] - if (any(token in mime for token in maybe_json) or - self.kwargs['explicit_json']): + if (self.kwargs['explicit_json'] or + any(token in mime for token in maybe_json)): try: obj = json.loads(body) except ValueError: From b565b4628e92231f0dba901fb0881eda9393166a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jul 2016 19:00:18 +0200 Subject: [PATCH 0231/1182] v0.9.4 --- CHANGELOG.rst | 11 ++++++++--- httpie/__init__.py | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 101e69f071..fa1f8769cf 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,10 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (Unreleased) ------------------------- + +`0.9.4`_ (2016-07-01) +--------------------- + * Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests * Added ``--ssl=`` to specify the desired SSL/TLS protocol version to use for HTTPS requests. @@ -28,8 +32,8 @@ This project adheres to `Semantic Versioning `_. * Improved ``--debug`` output * Fixed ``--session`` when used with ``--download`` * Fixed ``--download`` to trim too long filenames before saving the file -* Fixed handling of ``Content-Type`` with multiple ``+subtype`` parts -* Removed XML formatting as the implementation suffered from multiple issues +* Fixed the handling of ``Content-Type`` with multiple ``+subtype`` parts +* Removed the XML formatter as the implementation suffered from multiple issues @@ -284,4 +288,5 @@ This project adheres to `Semantic Versioning `_. .. _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 -.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.3...master +.. _0.9.4: https://github.com/jkbrzt/httpie/compare/0.9.3...0.9.4 +.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.4...master diff --git a/httpie/__init__.py b/httpie/__init__.py index 6c7fe03bd7..18b8f987d5 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '1.0.0-dev' +__version__ = '0.9.4' __licence__ = 'BSD' From e25948f6a094628592bb9367ba4e562dc6f2bfd3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Jul 2016 19:17:31 +0200 Subject: [PATCH 0232/1182] 1.0.0-dev --- httpie/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/__init__.py b/httpie/__init__.py index 18b8f987d5..6c7fe03bd7 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '0.9.4' +__version__ = '1.0.0-dev' __licence__ = 'BSD' From 2b0e6428424af581fd1663252d5c2212e31b2ce6 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 11:07:46 +0200 Subject: [PATCH 0233/1182] Document preference for Python 3 Also mention that the Homebrew formula depends on Python 3 starting with HTTPie 0.9.4. --- CHANGELOG.rst | 4 ++++ README.rst | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fa1f8769cf..ca4b970c0e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,10 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (Unreleased) ------------------------- +* Added Python 3 as a dependency for Homebrew installations + to ensure some of the newer HTTP features work out of the box + for macOS users (starting with HTTPie 0.9.4.). + `0.9.4`_ (2016-07-01) --------------------- diff --git a/README.rst b/README.rst index afacd452c0..e6e46ce9cc 100644 --- a/README.rst +++ b/README.rst @@ -117,6 +117,17 @@ The **latest development version** can be installed directly from GitHub: $ pip install --upgrade https://github.com/jkbrzt/httpie/archive/master.tar.gz +-------------- +Python version +-------------- + +Although Python 2.6 and 2.7 are supported as well, it is recommended to install +HTTPie against the latest Python 3.x whenever possible. That will ensure that +some of the newer HTTP features, such as `SNI (Server Name Indication)`_, +work out of the box. +Python 3 is the default for Homebrew installs starting version 0.9.4. +To see which version HTTPie uses, run ``http --debug``. + ===== Usage @@ -750,8 +761,8 @@ available set of protocols may vary depending on your OpenSSL installation.) SNI (Server Name Indication) ---------------------------- -If you use HTTPie with Python < 2.7.9 -(can be verified with ``python --version``) and need to talk to servers that +If you use HTTPie with `Python version`_ lower than 2.7.9 +(can be verified with ``http --debug``) and need to talk to servers that use **SNI (Server Name Indication)** you need to install some additional dependencies: From caf60cbc65aa79f16257b44022b27b6843dc6889 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 11:11:06 +0200 Subject: [PATCH 0234/1182] Typos --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e6e46ce9cc..e6a1db7685 100644 --- a/README.rst +++ b/README.rst @@ -125,7 +125,7 @@ Although Python 2.6 and 2.7 are supported as well, it is recommended to install HTTPie against the latest Python 3.x whenever possible. That will ensure that some of the newer HTTP features, such as `SNI (Server Name Indication)`_, work out of the box. -Python 3 is the default for Homebrew installs starting version 0.9.4. +Python 3 is the default for Homebrew installations starting with version 0.9.4. To see which version HTTPie uses, run ``http --debug``. From 0c7c248dce3e1a91ce3ee68f5f34e7ccdcb872c6 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 11:17:38 +0200 Subject: [PATCH 0235/1182] Fix CHANGELOG --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ca4b970c0e..869c2dffd5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,8 +10,8 @@ This project adheres to `Semantic Versioning `_. ------------------------- * Added Python 3 as a dependency for Homebrew installations - to ensure some of the newer HTTP features work out of the box - for macOS users (starting with HTTPie 0.9.4.). + to ensure some of the newer HTTP features work out of the box + for macOS users (starting with HTTPie 0.9.4.). `0.9.4`_ (2016-07-01) From 5acbc904b7356cecf081f33e948e394d660a15b2 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 11:50:30 +0200 Subject: [PATCH 0236/1182] Added the ability to unset headers Closes #476 --- CHANGELOG.rst | 2 ++ README.rst | 18 +++++++++++++++++- httpie/input.py | 15 +++++++++++++-- tests/test_httpie.py | 23 +++++++++++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 869c2dffd5..53e3c7cb76 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,8 @@ This project adheres to `Semantic Versioning `_. * Added Python 3 as a dependency for Homebrew installations to ensure some of the newer HTTP features work out of the box for macOS users (starting with HTTPie 0.9.4.). +* Added the ability to unset a request header with ``Header:``, and send an + empty value with ``Header;``. `0.9.4`_ (2016-07-01) diff --git a/README.rst b/README.rst index e6a1db7685..506d21157d 100644 --- a/README.rst +++ b/README.rst @@ -560,7 +560,23 @@ There are a couple of default headers that HTTPie sets: Host: -Any of the default headers can be overwritten. +Any of the default headers can be overwritten and some of them unset. + +To unset a header that has already been specified (such a one of the default +headers), use ``Header:``: + + +.. code-block:: bash + + $ http httpbin.org/headers Accept: User-Agent: + + +To send a header with an empty value, use ``Header;``: + + +.. code-block:: bash + + $ http httpbin.org/headers 'Header;' ============== diff --git a/httpie/input.py b/httpie/input.py index 85cb9a2707..d1f6600f18 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -34,6 +34,7 @@ # Various separators used in args SEP_HEADERS = ':' +SEP_HEADERS_EMPTY = ';' SEP_CREDENTIALS = ':' SEP_PROXY = ':' SEP_DATA = '=' @@ -67,6 +68,7 @@ # Separators allowed in ITEM arguments SEP_GROUP_ALL_ITEMS = frozenset([ SEP_HEADERS, + SEP_HEADERS_EMPTY, SEP_QUERY, SEP_DATA, SEP_DATA_RAW_JSON, @@ -655,11 +657,20 @@ def parse_items(items, data = [] files = [] params = [] - for item in items: value = item.value - if item.sep == SEP_HEADERS: + if value == '': + # No value => unset the header + value = None + target = headers + elif item.sep == SEP_HEADERS_EMPTY: + if item.value: + raise ParseError( + 'Invalid item "%s" ' + '(to specify an empty header use `Header;`)' + % item.orig + ) target = headers elif item.sep == SEP_QUERY: target = params diff --git a/tests/test_httpie.py b/tests/test_httpie.py index dcfb0d7678..37cc152c66 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -1,5 +1,7 @@ """High-level tests.""" import pytest + +from httpie.input import ParseError from utils import TestEnvironment, http, HTTP_OK from fixtures import FILE_PATH, FILE_CONTENT @@ -75,6 +77,27 @@ def test_headers(httpbin_both): assert '"Foo": "bar"' in r +def test_headers_unset(httpbin_both): + r = http('GET', httpbin_both + '/headers') + assert 'Accept' in r.json['headers'] # default Accept present + + r = http('GET', httpbin_both + '/headers', 'Accept:') + assert 'Accept' not in r.json['headers'] # default Accept unset + + +def test_headers_empty_value(httpbin_both): + r = http('GET', httpbin_both + '/headers') + assert r.json['headers']['Accept'] # default Accept has value + + r = http('GET', httpbin_both + '/headers', 'Accept;') + assert r.json['headers']['Accept'] == '' # Accept has no value + + +def test_headers_empty_value_with_value_gives_error(httpbin): + with pytest.raises(ParseError): + http('GET', httpbin + '/headers', 'Accept;SYNTAX_ERROR') + + @pytest.mark.skipif( is_py26, reason='the `object_pairs_hook` arg for `json.loads()` is Py>2.6 only' From c8e06b55e1c52e0e92700eafeddb03f904231054 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 12:03:19 +0200 Subject: [PATCH 0237/1182] Fix tests --- tests/test_cli.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index d5e8f1f9c1..831d04eab3 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -68,10 +68,11 @@ def test_escape_longsep(self): def test_valid_items(self): items = input.parse_items([ self.key_value('string=value'), - self.key_value('header:value'), + self.key_value('Header:value'), + self.key_value('Unset-Header:'), + self.key_value('Empty-Header;'), self.key_value('list:=["a", 1, {}, false]'), self.key_value('obj:={"a": "b"}'), - self.key_value('eh:'), self.key_value('ed='), self.key_value('bool:=true'), self.key_value('file@' + FILE_PATH_ARG), @@ -83,7 +84,11 @@ def test_valid_items(self): # Parsed headers # `requests.structures.CaseInsensitiveDict` => `dict` headers = dict(items.headers._store.values()) - assert headers == {'header': 'value', 'eh': ''} + assert headers == { + 'Header': 'value', + 'Unset-Header': None, + 'Empty-Header': '' + } # Parsed data raw_json_embed = items.data.pop('raw-json-embed') From 364b91cbc42af69d8ce1e32471f90ef141dfefb1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 12:03:52 +0200 Subject: [PATCH 0238/1182] Skip pypy3 tests on TravisCI --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2e232758a5..3406262c9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,8 @@ python: - pypy - 3.4 - 3.5 - - pypy3 +# Currently fails because of a Flask issue +# - pypy3 matrix: From 1124d68946f6e4109798dfdc07ec7c9e37df4442 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 12:47:02 +0200 Subject: [PATCH 0239/1182] Added --default-scheme Closes #289 --- CHANGELOG.rst | 1 + README.rst | 7 +++++++ httpie/cli.py | 1 - httpie/input.py | 2 -- tests/test_cli.py | 12 +++++++++++- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 53e3c7cb76..9cb4120f17 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,7 @@ This project adheres to `Semantic Versioning `_. for macOS users (starting with HTTPie 0.9.4.). * Added the ability to unset a request header with ``Header:``, and send an empty value with ``Header;``. +* Added ``--default-scheme ``. `0.9.4`_ (2016-07-01) diff --git a/README.rst b/README.rst index 506d21157d..b7a675aba9 100644 --- a/README.rst +++ b/README.rst @@ -313,6 +313,13 @@ this command: GET /?search=HTTPie+logo&tbm=isch HTTP/1.1 +You can use the ``--default-scheme `` option to create +shortcuts for other protocols than HTTP: + +.. code-block:: bash + + $ alias https="http --default-scheme https" + ============= Request Items diff --git a/httpie/cli.py b/httpie/cli.py index 2c7c92cb79..cd24a3af53 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -614,7 +614,6 @@ def _split_lines(self, text, width): ) troubleshooting.add_argument( '--default-scheme', - choices=["http", "https"], default="http", help=""" Default scheme to use if not specified in the URL. diff --git a/httpie/input.py b/httpie/input.py index e003c30dcb..0c8a0cef03 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -28,8 +28,6 @@ HTTP_POST = 'POST' HTTP_GET = 'GET' -HTTP = 'http://' -HTTPS = 'https://' # Various separators used in args diff --git a/tests/test_cli.py b/tests/test_cli.py index 831d04eab3..c9746ae21a 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -330,8 +330,18 @@ def test_ignore_stdin_cannot_prompt_password(self, httpbin): class TestSchemes: - def test_custom_scheme(self): + def test_invalid_custom_scheme(self): # InvalidSchema is expected because HTTPie # shouldn't touch a formally valid scheme. with pytest.raises(InvalidSchema): http('foo+bar-BAZ.123://bah') + + def test_invalid_scheme_via_via_default_scheme(self): + # InvalidSchema is expected because HTTPie + # shouldn't touch a formally valid scheme. + with pytest.raises(InvalidSchema): + http('bah', '--default=scheme=foo+bar-BAZ.123') + + def test_default_scheme(self, httpbin_secure): + url = '{0}:{1}'.format(httpbin_secure.host, httpbin_secure.port) + assert HTTP_OK in http(url, '--default-scheme=https') From 41e822ca2f66ffc14d03950687375225e896c43f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 12:51:35 +0200 Subject: [PATCH 0240/1182] Clean-up --- README.rst | 2 +- httpie/cli.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index b7a675aba9..6776af0c57 100644 --- a/README.rst +++ b/README.rst @@ -318,7 +318,7 @@ shortcuts for other protocols than HTTP: .. code-block:: bash - $ alias https="http --default-scheme https" + $ alias https='http --default-scheme=https' ============= diff --git a/httpie/cli.py b/httpie/cli.py index cd24a3af53..0b1a1805ac 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -89,7 +89,7 @@ def _split_lines(self, text, width): metavar='URL', help=""" The scheme defaults to 'http://' if the URL does not include one. - (You can override this with: --default-scheme https) + (You can override this with: --default-scheme=https) You can also use a shorthand for localhost @@ -616,7 +616,7 @@ def _split_lines(self, text, width): '--default-scheme', default="http", help=""" - Default scheme to use if not specified in the URL. + The default scheme to use if not specified in the URL. """ ) From 49a0fb6e0fb4fa130db9c5a2c4d3b27a6579cc75 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 14:18:36 +0200 Subject: [PATCH 0241/1182] More liberal default JSON Accept header Closes #470 --- CHANGELOG.rst | 2 ++ README.rst | 12 ++++++------ httpie/client.py | 12 ++++++------ tests/test_defaults.py | 11 ++++++----- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9cb4120f17..ae0229559e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,8 @@ This project adheres to `Semantic Versioning `_. * Added the ability to unset a request header with ``Header:``, and send an empty value with ``Header;``. * Added ``--default-scheme ``. +* Changed the default JSON ``Accept`` header from ``application/json`` + to ``application/json, */*``. `0.9.4`_ (2016-07-01) diff --git a/README.rst b/README.rst index 6776af0c57..6e8cb6d108 100644 --- a/README.rst +++ b/README.rst @@ -183,7 +183,7 @@ with `authentication`_: .. code-block:: bash - $ http -a USERNAME POST https://api.github.com/repos/jkbrzt/httpie/issues/83/comments body='HTTPie is awesome!' + $ http -a USERNAME POST https://api.github.com/repos/jkbrzt/httpie/issues/83/comments body='HTTPie is awesome! :heart:' Upload a file using `redirected input`_: @@ -403,13 +403,13 @@ both of which can be overwritten: ================ ======================================= ``Content-Type`` ``application/json`` -``Accept`` ``application/json`` +``Accept`` ``application/json, */*`` ================ ======================================= You can use ``--json, -j`` to explicitly set ``Accept`` to ``application/json`` regardless of whether you are sending data (it's a shortcut for setting the header via the usual header notation – -``http url Accept:application/json``). Additionally, +``http url Accept:application/json, */*``). Additionally, HTTPie will try to detect JSON responses even when the ``Content-Type`` is incorrectly ``text/plain`` or unknown. @@ -422,7 +422,7 @@ Simple example: .. code-block:: http PUT / HTTP/1.1 - Accept: application/json + Accept: application/json, */* Accept-Encoding: gzip, deflate Content-Type: application/json Host: example.org @@ -449,7 +449,7 @@ fields using ``=@`` and ``:=@``: .. code-block:: http PUT /person/1 HTTP/1.1 - Accept: application/json + Accept: application/json, */* Content-Type: application/json Host: api.example.com @@ -825,7 +825,7 @@ documentation examples: $ http --verbose PUT httpbin.org/put hello=world PUT /put HTTP/1.1 - Accept: application/json + Accept: application/json, */* Accept-Encoding: gzip, deflate Content-Type: application/json Host: httpbin.org diff --git a/httpie/client.py b/httpie/client.py index e8a9ef302e..59bd9beecf 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -24,8 +24,9 @@ pass -FORM = 'application/x-www-form-urlencoded; charset=utf-8' -JSON = 'application/json' +FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8' +JSON_CONTENT_TYPE = 'application/json' +JSON_ACCEPT = '{0}, */*'.format(JSON_CONTENT_TYPE) DEFAULT_UA = 'HTTPie/%s' % __version__ @@ -100,16 +101,15 @@ def get_default_headers(args): } auto_json = args.data and not args.form - # FIXME: Accept is set to JSON with `http url @./file.txt`. if args.json or auto_json: - default_headers['Accept'] = 'application/json' + default_headers['Accept'] = JSON_ACCEPT if args.json or (auto_json and args.data): - default_headers['Content-Type'] = JSON + default_headers['Content-Type'] = JSON_CONTENT_TYPE elif args.form and not args.files: # If sending files, `requests` will set # the `Content-Type` for us. - default_headers['Content-Type'] = FORM + default_headers['Content-Type'] = FORM_CONTENT_TYPE return default_headers diff --git a/tests/test_defaults.py b/tests/test_defaults.py index a82a1151b8..49d5749e66 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -2,6 +2,7 @@ Tests for the provided defaults regarding HTTP method, and --json vs. --form. """ +from httpie.client import JSON_ACCEPT from utils import TestEnvironment, http, HTTP_OK from fixtures import FILE_PATH @@ -58,20 +59,20 @@ def test_POST_no_data_no_auto_headers(self, httpbin): def test_POST_with_data_auto_JSON_headers(self, httpbin): r = http('POST', httpbin.url + '/post', 'a=b') assert HTTP_OK in r - assert '"Accept": "application/json"' in r - assert '"Content-Type": "application/json' in r + assert r.json['headers']['Accept'] == JSON_ACCEPT + assert r.json['headers']['Content-Type'] == 'application/json' def test_GET_with_data_auto_JSON_headers(self, httpbin): # JSON headers should automatically be set also for GET with data. r = http('POST', httpbin.url + '/post', 'a=b') assert HTTP_OK in r - assert '"Accept": "application/json"' in r, r - assert '"Content-Type": "application/json' in r + assert r.json['headers']['Accept'] == JSON_ACCEPT + assert r.json['headers']['Content-Type'] == 'application/json' def test_POST_explicit_JSON_auto_JSON_accept(self, httpbin): r = http('--json', 'POST', httpbin.url + '/post') assert HTTP_OK in r - assert r.json['headers']['Accept'] == 'application/json' + assert r.json['headers']['Accept'] == JSON_ACCEPT # Make sure Content-Type gets set even with no data. # https://github.com/jkbrzt/httpie/issues/137 assert 'application/json' in r.json['headers']['Content-Type'] From 595dc51b2d588291f33d17b5c18dbcc6d55c13d4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 14:33:04 +0200 Subject: [PATCH 0242/1182] Fish shell completion --- CHANGELOG.rst | 2 ++ httpie-completion.bash => extras/httpie-completion.bash | 0 httpie-completion.fish => extras/httpie-completion.fish | 0 3 files changed, 2 insertions(+) rename httpie-completion.bash => extras/httpie-completion.bash (100%) rename httpie-completion.fish => extras/httpie-completion.fish (100%) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ae0229559e..70606c7f2c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,8 @@ This project adheres to `Semantic Versioning `_. * Added the ability to unset a request header with ``Header:``, and send an empty value with ``Header;``. * Added ``--default-scheme ``. +* Added fish shell completion (located in ``extras/httpie-completion.fish`` + in the Github repo). * Changed the default JSON ``Accept`` header from ``application/json`` to ``application/json, */*``. diff --git a/httpie-completion.bash b/extras/httpie-completion.bash similarity index 100% rename from httpie-completion.bash rename to extras/httpie-completion.bash diff --git a/httpie-completion.fish b/extras/httpie-completion.fish similarity index 100% rename from httpie-completion.fish rename to extras/httpie-completion.fish From bfc64bce2110c3624b21d33d5e0cdec247d8b5ac Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 14:58:34 +0200 Subject: [PATCH 0243/1182] Upgrade requests to 2.10.0 to enable optional SOCKS support Closes #86 --- CHANGELOG.rst | 2 ++ README.rst | 17 +++++++++++++++++ setup.py | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 70606c7f2c..270c76d025 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,6 +17,8 @@ This project adheres to `Semantic Versioning `_. * Added ``--default-scheme ``. * Added fish shell completion (located in ``extras/httpie-completion.fish`` in the Github repo). +* Updated ``requests`` to 2.10.0 so that SOCKS support can be added via + ``pip install requests[socks]``. * Changed the default JSON ``Accept`` header from ``application/json`` to ``application/json, */*``. diff --git a/README.rst b/README.rst index 6e8cb6d108..347df35b60 100644 --- a/README.rst +++ b/README.rst @@ -713,6 +713,23 @@ In your ``~/.bash_profile``: export NO_PROXY=localhost,example.com +SOCKS +----- + +To enable SOCKS proxy support please install ``requests[socks]`` using ``pip``: + + +.. code-block::bash + + $ pip install -U requests[socks] + +Usage is the same as for other types of `proxies`_: + +.. code-block::bash + + $ http --proxy=http:socks5://user:pass@host:port --proxy=https:socks5://user:pass@host:port example.org + + ===== HTTPS ===== diff --git a/setup.py b/setup.py index d1d6e793f5..f4b56a3314 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ def run_tests(self): install_requires = [ - 'requests>=2.3.0', + 'requests>=2.10.0', 'Pygments>=1.5' ] From e1fa57d22898814087ad7566eb200e2d49fe63a9 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 15:01:46 +0200 Subject: [PATCH 0244/1182] Added -I as a shortcut for --ignore-stdin --- CHANGELOG.rst | 1 + httpie/cli.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 270c76d025..2ba4d3b71b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,7 @@ This project adheres to `Semantic Versioning `_. * Added the ability to unset a request header with ``Header:``, and send an empty value with ``Header;``. * Added ``--default-scheme ``. +* Added ``-I`` as a shortcut for ``--ignore-stdin``. * Added fish shell completion (located in ``extras/httpie-completion.fish`` in the Github repo). * Updated ``requests`` to 2.10.0 so that SOCKS support can be added via diff --git a/httpie/cli.py b/httpie/cli.py index 0b1a1805ac..a0ec34fb16 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -577,7 +577,7 @@ def _split_lines(self, text, width): troubleshooting = parser.add_argument_group(title='Troubleshooting') troubleshooting.add_argument( - '--ignore-stdin', + '--ignore-stdin', '-I', action='store_true', default=False, help=""" From 3a1726b4ed4669ffba1c56e20d71545159d19965 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 15:04:19 +0200 Subject: [PATCH 0245/1182] Fixed README --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 347df35b60..88f45dae89 100644 --- a/README.rst +++ b/README.rst @@ -713,6 +713,7 @@ In your ``~/.bash_profile``: export NO_PROXY=localhost,example.com +----- SOCKS ----- From bb4881a873fea7bb5785a0ed445dd241971b9621 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 18:30:04 +0200 Subject: [PATCH 0246/1182] Fixed README --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 88f45dae89..bbad1b4abd 100644 --- a/README.rst +++ b/README.rst @@ -720,13 +720,13 @@ SOCKS To enable SOCKS proxy support please install ``requests[socks]`` using ``pip``: -.. code-block::bash +.. code-block:: bash $ pip install -U requests[socks] Usage is the same as for other types of `proxies`_: -.. code-block::bash +.. code-block:: bash $ http --proxy=http:socks5://user:pass@host:port --proxy=https:socks5://user:pass@host:port example.org From 8c0f0b578c1e7dd3520567d1e9fa09f24691e26f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Jul 2016 18:42:23 +0200 Subject: [PATCH 0247/1182] Clean-up --- README.rst | 58 +++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/README.rst b/README.rst index bbad1b4abd..4b1daa85ac 100644 --- a/README.rst +++ b/README.rst @@ -35,7 +35,7 @@ HTTPie is written in Python, and under the hood it uses the excellent ============= -Main Features +Main features ============= * Expressive and intuitive syntax @@ -231,7 +231,7 @@ advanced usage, and also features additional examples.* =========== -HTTP Method +HTTP method =========== The name of the HTTP method comes right before the URL argument: @@ -322,7 +322,7 @@ shortcuts for other protocols than HTTP: ============= -Request Items +Request items ============= There are a few different *request item* types that provide a @@ -489,7 +489,7 @@ via the `config`_ file. ------------- -Regular Forms +Regular forms ------------- .. code-block:: bash @@ -507,7 +507,7 @@ Regular Forms ----------------- -File Upload Forms +File upload forms ----------------- If one or more file fields is present, the serialization and content type is @@ -533,7 +533,7 @@ Note that ``@`` is used to simulate a file upload form field, whereas ============ -HTTP Headers +HTTP headers ============ To set custom headers you can use the ``Header:Value`` notation: @@ -648,7 +648,7 @@ Authorization information from your ``~/.netrc`` file is honored as well: ------------ -Auth Plugins +Auth plugins ------------ * `httpie-oauth `_: OAuth @@ -662,7 +662,7 @@ Auth Plugins ============== -HTTP Redirects +HTTP redirects ============== By default, HTTP redirects are not followed and only the first @@ -820,7 +820,7 @@ You can use the following command to test SNI support: ============== -Output Options +Output options ============== By default, HTTPie only outputs the final response and the whole response @@ -887,11 +887,11 @@ Print request and response headers: --------------------------------------- -Viewing Intermediary Requests/Responses +Viewing intermediary requests/responses --------------------------------------- -To see *all* the HTTP communication, i.e. the final request/resposne as -well as any possible intermediary requests/responses, use the **``--all``** +To see *all* the HTTP communication, i.e. the final request/response as +well as any possible intermediary requests/responses, use the ``--all`` option. The intermediary HTTP communication include followed redirects (with ``--follow``), the first unauthorized request when HTTP digest authentication is used (``--auth=digest``), etc. @@ -915,7 +915,7 @@ arguments as ``--print, -p`` but applies to the intermediary requests only. ------------------------- -Conditional Body Download +Conditional body download ------------------------- As an optimization, the response body is downloaded from the server @@ -1013,9 +1013,9 @@ To prevent HTTPie from reading ``stdin`` data you can use the ``--ignore-stdin`` option. -------------------------- -Body Data From a Filename -------------------------- +---------------------------- +Request data from a filename +---------------------------- **An alternative to redirected** ``stdin`` is specifying a filename (as ``@/path/to/file``) whose content is used as if it came from ``stdin``. @@ -1031,7 +1031,7 @@ verbatim contents of that XML file with ``Content-Type: application/xml``: =============== -Terminal Output +Terminal output =============== HTTPie does several things by default in order to make its terminal output @@ -1039,7 +1039,7 @@ easy to read. --------------------- -Colors and Formatting +Colors and formatting --------------------- Syntax highlighting is applied to HTTP headers and bodies (where it makes @@ -1094,7 +1094,7 @@ You will nearly instantly see something like this: ================= -Redirected Output +Redirected output ================= HTTPie uses **different defaults** for redirected output than for @@ -1145,7 +1145,7 @@ by adding the following to your ``~/.bash_profile``: ============= -Download Mode +Download mode ============= HTTPie features a download mode in which it acts similarly to ``wget``. @@ -1202,7 +1202,7 @@ Other notes: ================== -Streamed Responses +Streamed responses ================== Responses are downloaded and printed in chunks, which allows for streaming @@ -1249,7 +1249,7 @@ ones starting with ``Content-`` or ``If-``), authorization, and cookies to the same host. -------------- -Named Sessions +Named sessions -------------- Create a new session named ``user1`` for ``example.org``: @@ -1280,7 +1280,7 @@ Named sessions' data is stored in JSON files in the directory (``%APPDATA%\httpie\sessions\\.json`` on Windows). ------------------ -Anonymous Sessions +Anonymous sessions ------------------ Instead of a name, you can also directly specify a path to a session file. This @@ -1374,7 +1374,7 @@ Also, the ``--timeout`` option allows to overwrite the default 30s timeout: ================ -Interface Design +Interface design ================ The syntax of the command arguments closely corresponds to the actual HTTP @@ -1448,28 +1448,28 @@ have contributed. Logo ==== -Please see `claudiatd/httpie-artwork`_ +See `claudiatd/httpie-artwork`_ ========== Contribute ========== -Please see `CONTRIBUTING `_. +See `CONTRIBUTING `_. ========== -Change Log +Change log ========== -Please see `CHANGELOG `_. +See `CHANGELOG `_. ======= Licence ======= -Please see `LICENSE `_. +See `LICENSE `_. From aab5cd9da077c3584265d2e4160ca43f84843f3e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 4 Jul 2016 20:30:55 +0200 Subject: [PATCH 0248/1182] PEP8. clean-up --- httpie/client.py | 1 - httpie/compat.py | 11 ++++++++--- httpie/downloads.py | 40 +++++++++++++++++++-------------------- httpie/input.py | 11 ++++++----- httpie/plugins/builtin.py | 1 + 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 59bd9beecf..054783f952 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -1,6 +1,5 @@ import json import sys -from pprint import pformat import requests from requests.adapters import HTTPAdapter diff --git a/httpie/compat.py b/httpie/compat.py index 2e9e329148..d626e98480 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -14,10 +14,14 @@ if is_py2: + # noinspection PyShadowingBuiltins bytes = str + # noinspection PyUnresolvedReferences,PyShadowingBuiltins str = unicode elif is_py3: + # noinspection PyShadowingBuiltins str = str + # noinspection PyShadowingBuiltins bytes = bytes @@ -32,7 +36,7 @@ # noinspection PyCompatibility from urllib.request import urlopen except ImportError: # pragma: no cover - # noinspection PyCompatibility + # noinspection PyCompatibility,PyUnresolvedReferences from urllib2 import urlopen try: # pragma: no cover @@ -40,10 +44,10 @@ except ImportError: # pragma: no cover # Python 2.6 OrderedDict class, needed for headers, parameters, etc .### # - # noinspection PyCompatibility + # noinspection PyCompatibility,PyUnresolvedReferences from UserDict import DictMixin - # noinspection PyShadowingBuiltins + # noinspection PyShadowingBuiltins,PyCompatibility class OrderedDict(dict, DictMixin): # Copyright (c) 2009 Raymond Hettinger # @@ -115,6 +119,7 @@ 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() diff --git a/httpie/downloads.py b/httpie/downloads.py index 58e7b943e9..5c19beae49 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -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 @@ def failed(self): @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 @@ def report_speed(self): 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 @@ def report_speed(self): self._prev_bytes = downloaded self.output.write( - CLEAR_LINE - + ' ' - + SPINNER[self._spinner_pos] - + ' ' - + self._status_line + CLEAR_LINE + + ' ' + + SPINNER[self._spinner_pos] + + ' ' + + self._status_line ) self.output.flush() @@ -447,8 +447,8 @@ def report_speed(self): else 0) def sum_up(self): - actually_downloaded = (self.status.downloaded - - self.status.resumed_from) + actually_downloaded = ( + self.status.downloaded - self.status.resumed_from) time_taken = self.status.time_finished - self.status.time_started self.output.write(CLEAR_LINE) @@ -463,8 +463,8 @@ def sum_up(self): 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, )) diff --git a/httpie/input.py b/httpie/input.py index 0c8a0cef03..99a4849cb8 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -309,9 +309,10 @@ def _guess_method(self): self.args.url = self.args.method # Infer the method has_data = ( - (not self.args.ignore_stdin and not self.env.stdin_isatty) - or any(item.sep in SEP_GROUP_DATA_ITEMS - for item in self.args.items) + (not self.args.ignore_stdin and + not self.env.stdin_isatty) or + any(item.sep in SEP_GROUP_DATA_ITEMS + for item in self.args.items) ) self.args.method = HTTP_POST if has_data else HTTP_GET @@ -439,8 +440,8 @@ def __init__(self, error_message): 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 diff --git a/httpie/plugins/builtin.py b/httpie/plugins/builtin.py index 0f1a806b73..0e3aa26d7d 100644 --- a/httpie/plugins/builtin.py +++ b/httpie/plugins/builtin.py @@ -5,6 +5,7 @@ from httpie.plugins.base import AuthPlugin +# noinspection PyAbstractClass class BuiltinAuthPlugin(AuthPlugin): package_name = '(builtin)' From 702c21aa915a0681e992e8ade77af4c2cc410fd5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 8 Jul 2016 15:02:42 +0200 Subject: [PATCH 0249/1182] Added related projects --- README.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.rst b/README.rst index 4b1daa85ac..a6b3af62ff 100644 --- a/README.rst +++ b/README.rst @@ -1473,6 +1473,17 @@ See `LICENSE `_. +================ +Related projects +================ + +* `jq `_ — a command-line JSON processor that + works great in conjunction with HTTPie +* `http-prompt `_ — an interactive + shell for HTTPie featuring autocomplete and command syntax highlighting + + + .. _Requests: http://python-requests.org .. _Pygments: http://pygments.org/ .. _pip: http://www.pip-installer.org/en/latest/index.html From 6238b59e72caceda31578213073fa5c4dc0774f3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 8 Jul 2016 15:05:43 +0200 Subject: [PATCH 0250/1182] Fix formatting --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index a6b3af62ff..10d6f9e0b3 100644 --- a/README.rst +++ b/README.rst @@ -1478,9 +1478,9 @@ Related projects ================ * `jq `_ — a command-line JSON processor that - works great in conjunction with HTTPie + works great in conjunction with HTTPie * `http-prompt `_ — an interactive - shell for HTTPie featuring autocomplete and command syntax highlighting + shell for HTTPie featuring autocomplete and command syntax highlighting From 9c2c058ae56e70fe77a828d2c17deb6a3d636cf9 Mon Sep 17 00:00:00 2001 From: Pedro Rodrigues Date: Tue, 19 Jul 2016 17:23:18 +0100 Subject: [PATCH 0251/1182] separate environment to test codestyle as proposed by @sigmavirus24 --- tox.ini | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index f746660f28..e45f7c23fd 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ [tox] -envlist = py26, py27, py35, pypy +envlist = py26, py27, py35, pypy, codestyle [testenv] @@ -20,3 +20,9 @@ commands = --verbose \ --doctest-modules \ {posargs:./httpie ./tests} + +[testenv:codestyle] +deps = pycodestyle +commands = + pycodestyle \ + --ignore=E241,E501 From 8f6bee9196f2cacee9cc94de537c63ca15bd75dd Mon Sep 17 00:00:00 2001 From: Pedro Rodrigues Date: Tue, 19 Jul 2016 17:23:40 +0100 Subject: [PATCH 0252/1182] codestyle fixes --- httpie/cli.py | 2 +- httpie/core.py | 2 +- tests/test_cli.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index a0ec34fb16..91d5347285 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -213,7 +213,7 @@ def _split_lines(self, text, width): """.format( default=DEFAULT_STYLE, available='\n'.join( - '{0}{1}'.format(8*' ', line.strip()) + '{0}{1}'.format(8 * ' ', line.strip()) for line in wrap(', '.join(sorted(AVAILABLE_STYLES)), 60) ).rstrip(), ) diff --git a/httpie/core.py b/httpie/core.py index 31e5c48bdc..7d7cca5e0e 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -243,7 +243,7 @@ def log_error(msg, *args, **kwargs): except requests.TooManyRedirects: exit_status = ExitStatus.ERROR_TOO_MANY_REDIRECTS log_error('Too many redirects (--max-redirects=%s).', - parsed_args.max_redirects) + parsed_args.max_redirects) except Exception as e: # TODO: Further distinction between expected and unexpected errors. msg = str(e) diff --git a/tests/test_cli.py b/tests/test_cli.py index c9746ae21a..fa20117cf7 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -108,8 +108,8 @@ def test_valid_items(self): # Parsed file fields assert 'file' in items.files - assert (items.files['file'][1].read().strip().decode('utf8') - == FILE_CONTENT) + assert (items.files['file'][1].read().strip(). + decode('utf8') == FILE_CONTENT) def test_multiple_file_fields_with_same_field_name(self): items = input.parse_items([ From 86c8abc4859eda944b351347ff704186f1ac3755 Mon Sep 17 00:00:00 2001 From: Pedro Rodrigues Date: Tue, 26 Jul 2016 20:46:55 +0100 Subject: [PATCH 0253/1182] force os to be linux (+1 squashed commit) Squashed commits: [444c56d] no vars for you (+1 squashed commit) Squashed commits: [c7d1bf9] added pycodestyle environment to travis config --- .travis.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3406262c9b..478e4f061c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,6 +45,11 @@ matrix: - TOXENV=py35 - BREW_INSTALL=python3 + # Python Codestyle + - os: linux + python: 3.5 + env: CODESTYLE=true + install: - | if [[ $TRAVIS_OS_NAME == 'osx' ]]; then @@ -54,11 +59,18 @@ install: fi sudo pip install tox fi + if [[ $CODESTYLE ]]; then + pip install pycodestyle + fi script: - | if [[ $TRAVIS_OS_NAME == 'linux' ]]; then - make + if [[ $CODESTYLE ]]; then + pycodestyle --ignore=E241,E501 + else + make + fi else PATH="/usr/local/bin:$PATH" tox -e "$TOXENV" fi From becb63de9a0c0ccedd5c2e1073045b088cd76f98 Mon Sep 17 00:00:00 2001 From: Pedro Rodrigues Date: Tue, 26 Jul 2016 21:59:34 +0100 Subject: [PATCH 0254/1182] useful info --- .travis.yml | 2 ++ tox.ini | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 478e4f061c..f0a6ca02ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -67,6 +67,8 @@ script: - | if [[ $TRAVIS_OS_NAME == 'linux' ]]; then if [[ $CODESTYLE ]]; then + # 241 - multiple spaces after ‘,’ + # 501 - line too long pycodestyle --ignore=E241,E501 else make diff --git a/tox.ini b/tox.ini index e45f7c23fd..57cc5d9dd8 100644 --- a/tox.ini +++ b/tox.ini @@ -26,3 +26,5 @@ deps = pycodestyle commands = pycodestyle \ --ignore=E241,E501 + # 241 - multiple spaces after ‘,’ + # 501 - line too long From 6b06d92a59762233e19ec4fb308d6952f2d5ba46 Mon Sep 17 00:00:00 2001 From: KATO Kei Date: Wed, 27 Jul 2016 09:54:26 +0900 Subject: [PATCH 0255/1182] Fix typo --- httpie/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/core.py b/httpie/core.py index 31e5c48bdc..6caf9f2a53 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -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. """ From af737fd3384aeb973fb97b4aea0de9cafd299bc8 Mon Sep 17 00:00:00 2001 From: ii-v Date: Thu, 11 Aug 2016 01:43:15 +0200 Subject: [PATCH 0256/1182] Fixed spelling mistage `GitHib` to `GitHub` --- AUTHORS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index e074d415a9..542191ffcf 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -8,7 +8,7 @@ HTTPie authors Patches and ideas ----------------- -`Complete list of contributors on GitHib `_ +`Complete list of contributors on GitHub `_ * `Cláudia T. Delgado `_ (logo) * `Hank Gay `_ From 6d65668355dd2b5e8bf385065677595c4e987e68 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 13 Aug 2016 22:40:01 +0200 Subject: [PATCH 0257/1182] Strip request header values --- extras/get-homebrew-formula-vars.py | 55 +++++++++++++++++++++++++++++ httpie/client.py | 26 +++++++++----- 2 files changed, 73 insertions(+), 8 deletions(-) create mode 100755 extras/get-homebrew-formula-vars.py diff --git a/extras/get-homebrew-formula-vars.py b/extras/get-homebrew-formula-vars.py new file mode 100755 index 0000000000..c2c80dc27d --- /dev/null +++ b/extras/get-homebrew-formula-vars.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +""" +Generate URLs and file hashes to be included in the Homebrew formula +after a new release of HTTPie is published on PyPi. + +https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb + +""" +import hashlib +import requests + + +PACKAGES = [ + 'httpie', + 'requests', + 'pygments', +] + + +def get_info(package_name): + api_url = 'https://pypi.python.org/pypi/{}/json'.format(package_name) + resp = requests.get(api_url).json() + hasher = hashlib.sha256() + for release in resp['urls']: + download_url = release['url'] + if download_url.endswith('.tar.gz'): + hasher.update(requests.get(download_url).content) + return { + 'name': package_name, + 'url': download_url, + 'sha256': hasher.hexdigest(), + } + else: + raise RuntimeError( + '{}: download not found: {}'.format(package_name, resp)) + + +packages = { + package_name: get_info(package_name) for package_name in PACKAGES +} + + +httpie_info = packages.pop('httpie') +print(""" + url "{url}" + sha256 "{sha256}" +""".format(**httpie_info)) + + +for package_info in packages.values(): + print(""" + resource "{name}" do + url "{url}" + sha256 "{sha256}" + end""".format(**package_info)) diff --git a/httpie/client.py b/httpie/client.py index 054783f952..fb0fc62ca3 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -85,13 +85,23 @@ def dump_request(kwargs): % repr_dict_nice(kwargs)) -def encode_headers(headers): - # This allows for unicode headers which is non-standard but practical. - # See: https://github.com/jkbrzt/httpie/issues/212 - return dict( - (name, value.encode('utf8') if isinstance(value, str) else value) - for name, value in headers.items() - ) +def finalize_headers(headers): + final_headers = {} + for name, value in headers.items(): + if value is not None: + + # >leading or trailing LWS MAY be removed without + # >changing the semantics of the field value" + # -https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html + # Also, requests raises `InvalidHeader` for leading spaces. + value = value.strip() + + if isinstance(value, str): + # See: https://github.com/jkbrzt/httpie/issues/212 + value = value.encode('utf8') + + final_headers[name] = value + return final_headers def get_default_headers(args): @@ -133,7 +143,7 @@ def get_requests_kwargs(args, base_headers=None): if base_headers: headers.update(base_headers) headers.update(args.headers) - headers = encode_headers(headers) + headers = finalize_headers(headers) credentials = None if args.auth: From 487c7a9221b02541dde927327c1eb79995e26b69 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 13 Aug 2016 22:51:42 +0200 Subject: [PATCH 0258/1182] v0.9.5 --- CHANGELOG.rst | 10 +++++++++- Makefile | 10 ++++++++-- httpie/__init__.py | 2 +- setup.py | 3 ++- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2ba4d3b71b..5ddb596f64 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,12 +9,17 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (Unreleased) ------------------------- + +`0.9.5`_ (2016-08-13) +--------------------- + * Added Python 3 as a dependency for Homebrew installations to ensure some of the newer HTTP features work out of the box for macOS users (starting with HTTPie 0.9.4.). * Added the ability to unset a request header with ``Header:``, and send an empty value with ``Header;``. -* Added ``--default-scheme ``. +* Added ``--default-scheme `` to enable things like + ``$ alias https='http --default-scheme=https``. * Added ``-I`` as a shortcut for ``--ignore-stdin``. * Added fish shell completion (located in ``extras/httpie-completion.fish`` in the Github repo). @@ -22,6 +27,8 @@ This project adheres to `Semantic Versioning `_. ``pip install requests[socks]``. * Changed the default JSON ``Accept`` header from ``application/json`` to ``application/json, */*``. +* Changed the pre-processing of request HTTP headers so that any leading + and trailing whitespace is removed. `0.9.4`_ (2016-07-01) @@ -303,4 +310,5 @@ This project adheres to `Semantic Versioning `_. .. _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.5: https://github.com/jkbrzt/httpie/compare/0.9.3...0.9.5 .. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.4...master diff --git a/Makefile b/Makefile index 89e0342e8a..80767349d2 100644 --- a/Makefile +++ b/Makefile @@ -57,10 +57,12 @@ test-bdist-wheel: clean uninstall-httpie test-all: uninstall-all clean init test test-tox test-dist -publish: test-all +publish: test-all publish-no-test + +publish-no-test: @echo $(TAG)Testing wheel build an installation$(END) @echo "$(VERSION)" - @echo "$(VERSION)" | grep -q "dev" && echo "!!!Not publishing dev version!!!" && exit 1 + @echo "$(VERSION)" | grep -q "dev" && echo '!!!Not publishing dev version!!!' && exit 1 || echo ok python setup.py register python setup.py sdist upload python setup.py bdist_wheel upload @@ -92,3 +94,7 @@ uninstall-all: uninstall-httpie @echo $(TAG)Uninstalling development requirements$(END) - pip uninstall --yes -r $(REQUIREMENTS) + + +homebrew-formula-vars: + extras/get-homebrew-formula-variables.py diff --git a/httpie/__init__.py b/httpie/__init__.py index 6c7fe03bd7..8a0a154358 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '1.0.0-dev' +__version__ = '0.9.5' __licence__ = 'BSD' diff --git a/setup.py b/setup.py index f4b56a3314..a508d483e0 100644 --- a/setup.py +++ b/setup.py @@ -35,10 +35,11 @@ def run_tests(self): install_requires = [ - 'requests>=2.10.0', + 'requests>=2.11.0', 'Pygments>=1.5' ] + # Conditional dependencies: # sdist From 8ac3c5961ca96500034c34d589f4ecab77bcce97 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 13 Aug 2016 22:57:33 +0200 Subject: [PATCH 0259/1182] Upgrade Pygments version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a508d483e0..3dc8862095 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ def run_tests(self): install_requires = [ 'requests>=2.11.0', - 'Pygments>=1.5' + 'Pygments>=2.1.3' ] From 8a9206eceb705c5665c68d80b26a2540a0f038d8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 13 Aug 2016 22:57:44 +0200 Subject: [PATCH 0260/1182] Fixed Makefile --- Makefile | 2 +- extras/get-homebrew-formula-vars.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 80767349d2..ce83fcde54 100644 --- a/Makefile +++ b/Makefile @@ -97,4 +97,4 @@ uninstall-all: uninstall-httpie homebrew-formula-vars: - extras/get-homebrew-formula-variables.py + extras/get-homebrew-formula-vars.py diff --git a/extras/get-homebrew-formula-vars.py b/extras/get-homebrew-formula-vars.py index c2c80dc27d..158d07008e 100755 --- a/extras/get-homebrew-formula-vars.py +++ b/extras/get-homebrew-formula-vars.py @@ -42,14 +42,14 @@ def get_info(package_name): httpie_info = packages.pop('httpie') print(""" - url "{url}" - sha256 "{sha256}" + 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)) + resource "{name}" do + url "{url}" + sha256 "{sha256}" + end""".format(**package_info)) From 8e962383235badcdc56118385edb343df3f624fe Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 13 Aug 2016 23:01:05 +0200 Subject: [PATCH 0261/1182] v0.9.6 --- CHANGELOG.rst | 4 ++-- httpie/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5ddb596f64..8c3f97e721 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,7 +10,7 @@ This project adheres to `Semantic Versioning `_. ------------------------- -`0.9.5`_ (2016-08-13) +`0.9.6`_ (2016-08-13) --------------------- * Added Python 3 as a dependency for Homebrew installations @@ -310,5 +310,5 @@ This project adheres to `Semantic Versioning `_. .. _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.5: https://github.com/jkbrzt/httpie/compare/0.9.3...0.9.5 +.. _0.9.6: https://github.com/jkbrzt/httpie/compare/0.9.3...0.9.6 .. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.4...master diff --git a/httpie/__init__.py b/httpie/__init__.py index 8a0a154358..7f8a64f413 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '0.9.5' +__version__ = '0.9.6' __licence__ = 'BSD' From c4b309164f0ca7ea4819b1d27a02fb9c4e16833f Mon Sep 17 00:00:00 2001 From: Josh Ellithorpe Date: Sat, 13 Aug 2016 19:08:37 -0700 Subject: [PATCH 0262/1182] Updated README.rst to add Arch Linux install docs. --- README.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.rst b/README.rst index 10d6f9e0b3..e6c4ff05fb 100644 --- a/README.rst +++ b/README.rst @@ -84,6 +84,9 @@ system package manager, e.g.: # RPM-based distributions: $ yum install httpie + + # Arch Linux + $ pacman -S httpie A **universal installation method** (that works on **Windows**, Mac OS X, Linux, …, From 5efc9010ccc260d99e5790fa1a9fe5b06039ae96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Sun, 14 Aug 2016 11:36:21 +0200 Subject: [PATCH 0263/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8c3f97e721..460a9b7c20 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -310,5 +310,5 @@ This project adheres to `Semantic Versioning `_. .. _0.9.2: https://github.com/jkbrzt/httpie/compare/0.9.1...0.9.2 .. _0.9.3: https://github.com/jkbrzt/httpie/compare/0.9.2...0.9.3 .. _0.9.4: https://github.com/jkbrzt/httpie/compare/0.9.3...0.9.4 -.. _0.9.6: https://github.com/jkbrzt/httpie/compare/0.9.3...0.9.6 -.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.4...master +.. _0.9.6: https://github.com/jkbrzt/httpie/compare/0.9.4...0.9.6 +.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.6...master From c53a778f60186b8a594286527ed52abc783c6b3c Mon Sep 17 00:00:00 2001 From: dongweiming Date: Thu, 1 Sep 2016 17:14:23 +0800 Subject: [PATCH 0264/1182] Fix Issue #496 --- httpie/cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/httpie/cli.py b/httpie/cli.py index 91d5347285..e78b59f275 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -102,6 +102,7 @@ def _split_lines(self, text, width): 'items', metavar='REQUEST_ITEM', nargs=ZERO_OR_MORE, + default=None, type=KeyValueArgType(*SEP_GROUP_ALL_ITEMS), help=r""" Optional key-value pairs to be included in the request. The separator used From 87e44ae639bbf1d91f1ef80eed661bfa229cec4c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 6 Sep 2016 11:07:52 +0100 Subject: [PATCH 0265/1182] Handle curses-free Pythons --- httpie/__init__.py | 2 +- httpie/context.py | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/httpie/__init__.py b/httpie/__init__.py index 7f8a64f413..6c7fe03bd7 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '0.9.6' +__version__ = '1.0.0-dev' __licence__ = 'BSD' diff --git a/httpie/context.py b/httpie/context.py index f14de856d1..bc555863f2 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -1,4 +1,8 @@ import sys +try: + import curses +except ImportError: + curses = None # Compiled w/o curses from httpie.compat import is_windows from httpie.config import DEFAULT_CONFIG_DIR, Config @@ -28,17 +32,12 @@ class Environment(object): stderr_isatty = stderr.isatty() colors = 256 if not is_windows: - import curses - try: - curses.setupterm() + if curses: try: + curses.setupterm() colors = curses.tigetnum('colors') - except TypeError: - # pypy3 (2.4.0) - colors = curses.tigetnum(b'colors') - except curses.error: - pass - del curses + except curses.error: + pass else: # noinspection PyUnresolvedReferences import colorama.initialise From b565be43182992d9519d3d2319a37df8084b7611 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 6 Sep 2016 11:53:52 +0100 Subject: [PATCH 0266/1182] CHANGELOG --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 460a9b7c20..0e347207d6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,9 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (Unreleased) ------------------------- +* Added support for ``curses``-less Python installations. +* Fixed ``REQUEST_ITEM`` arg incorrectly being reported as required. + `0.9.6`_ (2016-08-13) --------------------- From d584686744756d3137c64921e1d1f3af42ed007b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 11 Sep 2016 01:16:07 +0200 Subject: [PATCH 0267/1182] README --- README.rst | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/README.rst b/README.rst index e6c4ff05fb..d6e21bab02 100644 --- a/README.rst +++ b/README.rst @@ -1,37 +1,40 @@ -**************************************** +######################################## HTTPie: a CLI, cURL-like tool for humans -**************************************** +######################################## -HTTPie (pronounced *aitch-tee-tee-pie*) is a **command line HTTP client**. -Its goal is to make CLI interaction with web services as **human-friendly** -as possible. It provides a simple ``http`` command that allows for sending -arbitrary HTTP requests using a simple and natural syntax, and displays -colorized output. HTTPie can be used for **testing, debugging**, and -generally **interacting** with HTTP servers. +.. class:: no-web + HTTPie (pronounced *aitch-tee-tee-pie*) is a **command line HTTP client**. + Its goal is to make CLI interaction with web services as **human-friendly** + as possible. It provides a simple ``http`` command that allows for sending + arbitrary HTTP requests using a simple and natural syntax, and displays + colorized output. HTTPie can be used for **testing, debugging**, and + generally **interacting** with HTTP servers. -.. image:: https://raw.githubusercontent.com/jkbrzt/httpie/master/httpie.png - :alt: HTTPie compared to cURL - :width: 679 - :height: 781 - :align: center + .. image:: https://raw.githubusercontent.com/jkbrzt/httpie/master/httpie.png + :alt: HTTPie compared to cURL + :width: 100% + :align: center -HTTPie is written in Python, and under the hood it uses the excellent -`Requests`_ and `Pygments`_ libraries. + HTTPie is written in Python, and under the hood it uses the excellent + `Requests`_ and `Pygments`_ libraries. ------ + +.. class:: no-web no-pdf |pypi| |unix_build| |windows_build| |coverage| |gitter| ------ .. contents:: - :local: - :depth: 1 - :backlinks: none + +.. section-numbering:: + +.. raw:: pdf + + PageBreak oneColumn ============= @@ -84,7 +87,7 @@ system package manager, e.g.: # RPM-based distributions: $ yum install httpie - + # Arch Linux $ pacman -S httpie @@ -1472,7 +1475,7 @@ See `CHANGELOG `_. Licence ======= -See `LICENSE `_. +BSD-3-Clause: `LICENSE `_. From fc6d89913fe7b4f4f286450fa098670572fd5cef Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 11 Sep 2016 11:39:03 +0200 Subject: [PATCH 0268/1182] README --- README.rst | 58 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/README.rst b/README.rst index d6e21bab02..a3a3462f13 100644 --- a/README.rst +++ b/README.rst @@ -1379,9 +1379,13 @@ Also, the ``--timeout`` option allows to overwrite the default 30s timeout: fi -================ +==== +Meta +==== + +---------------- Interface design -================ +---------------- The syntax of the command arguments closely corresponds to the actual HTTP requests sent over the wire. It has the advantage that it's easy to remember @@ -1426,9 +1430,9 @@ HTTPie reaches its final version ``1.0``. All changes are recorded in the -======= -Support -======= +------------ +User support +------------ Please use the following support channels: @@ -1441,47 +1445,45 @@ Please use the following support channels: `httpie `_ tag). * You can also tweet directly to `@jkbrzt`_. -======= -Authors -======= - -`Jakub Roztocil`_ (`@jkbrzt`_) created HTTPie and `these fine people`_ -have contributed. - - -==== -Logo -==== - -See `claudiatd/httpie-artwork`_ - - -========== +---------- Contribute -========== +---------- See `CONTRIBUTING `_. -========== +---------- Change log -========== +---------- See `CHANGELOG `_. -======= +------- +Artwork +------- + +See `claudiatd/httpie-artwork`_ + + +------- Licence -======= +------- BSD-3-Clause: `LICENSE `_. +------- +Authors +------- -================ +`Jakub Roztocil`_ (`@jkbrzt`_) created HTTPie and `these fine people`_ +have contributed. + +---------------- Related projects -================ +---------------- * `jq `_ — a command-line JSON processor that works great in conjunction with HTTPie From e387c1d43ec07fcfcebb94db8455894e3ce74518 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 11 Sep 2016 18:46:33 +0200 Subject: [PATCH 0269/1182] Updated config docs --- README.rst | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/README.rst b/README.rst index a3a3462f13..aa2c8f8926 100644 --- a/README.rst +++ b/README.rst @@ -1313,20 +1313,22 @@ See also `Config`_. Config ====== -HTTPie uses a simple configuration file that contains a JSON object with the -following keys: - +HTTPie uses a simple JSON config file. The default location of the +configuration file is ``~/.httpie/config.json`` +(or ``%APPDATA%\httpie\config.json`` on Windows). The config directory +location can be changed by setting the +``HTTPIE_CONFIG_DIR`` environment variable. ------------- -``__meta__`` ------------- +-------------------- +Configurable options +-------------------- -HTTPie automatically stores some of its metadata here. Do not change. +The JSON file contains an object with the following keys: -------------------- ``default_options`` -------------------- +~~~~~~~~~~~~~~~~~~~ + An ``Array`` (by default empty) of default options that should be applied to every invocation of HTTPie. @@ -1338,12 +1340,22 @@ use `sessions`_ (one named ``default`` will automatically be used). Or you could change the implicit request content type from JSON to form by adding ``--form`` to the list. -Default options from config file can be unset for a particular invocation via -``--no-OPTION`` arguments passed on the command line (e.g., ``--no-style`` -or ``--no-session``). The default location of the configuration file is -``~/.httpie/config.json`` (or ``%APPDATA%\httpie\config.json`` on Windows). -The config directory location can be changed by setting the -``HTTPIE_CONFIG_DIR`` environment variable. + +``__meta__`` +~~~~~~~~~~~~ + +HTTPie automatically stores some of its metadata here. Please do not change. + + + +--------------------------------------- +Un-setting previously specified options +--------------------------------------- + +Default options from the config file, or specified any other way, +can be unset for a particular invocation via ``--no-OPTION`` arguments passed +on the command line (e.g., ``--no-style`` or ``--no-session``). + ========= From 1847eaa29996b96ec78af6b037baeccad8330485 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 11 Sep 2016 18:48:56 +0200 Subject: [PATCH 0270/1182] Updated config docs --- README.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index aa2c8f8926..f3749b7883 100644 --- a/README.rst +++ b/README.rst @@ -1313,11 +1313,19 @@ See also `Config`_. Config ====== -HTTPie uses a simple JSON config file. The default location of the -configuration file is ``~/.httpie/config.json`` +HTTPie uses a simple JSON config file. + + + +-------------------- +Config file location +-------------------- + + +The default location of the configuration file is ``~/.httpie/config.json`` (or ``%APPDATA%\httpie\config.json`` on Windows). The config directory -location can be changed by setting the -``HTTPIE_CONFIG_DIR`` environment variable. +location can be changed by setting the ``HTTPIE_CONFIG_DIR`` +environment variable. To view the exact location run ``http --debug``. -------------------- Configurable options From 22a2fddc799eb5adf66b01a6d869b65fac80232b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 12 Sep 2016 08:59:55 +0200 Subject: [PATCH 0271/1182] README --- README.rst | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/README.rst b/README.rst index f3749b7883..6790595858 100644 --- a/README.rst +++ b/README.rst @@ -17,8 +17,7 @@ HTTPie: a CLI, cURL-like tool for humans :width: 100% :align: center - HTTPie is written in Python, and under the hood it uses the excellent - `Requests`_ and `Pygments`_ libraries. + @@ -1466,6 +1465,29 @@ Please use the following support channels: * You can also tweet directly to `@jkbrzt`_. +---------------- +Related projects +---------------- + +Dependencies +~~~~~~~~~~~~ + +* `Requests `_ + — Python HTTP library for humans +* `Pygments `_ + — Python syntax highlighter + +Friends +~~~~~~~ + +* `jq `_ + — CLI JSON processor that + works great in conjunction with HTTPie +* `http-prompt `_ + — interactive shell for HTTPie featuring autocomplete + and command syntax highlighting + + ---------- Contribute ---------- @@ -1494,6 +1516,7 @@ Licence BSD-3-Clause: `LICENSE `_. + ------- Authors ------- @@ -1501,19 +1524,7 @@ Authors `Jakub Roztocil`_ (`@jkbrzt`_) created HTTPie and `these fine people`_ have contributed. ----------------- -Related projects ----------------- - -* `jq `_ — a command-line JSON processor that - works great in conjunction with HTTPie -* `http-prompt `_ — an interactive - shell for HTTPie featuring autocomplete and command syntax highlighting - - -.. _Requests: http://python-requests.org -.. _Pygments: http://pygments.org/ .. _pip: http://www.pip-installer.org/en/latest/index.html .. _Github API: http://developer.github.com/v3/issues/comments/#create-a-comment .. _these fine people: https://github.com/jkbrzt/httpie/contributors From f515ef72d0b2365f1cafb26c99b50e973af69b73 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 12 Sep 2016 09:12:07 +0200 Subject: [PATCH 0272/1182] README --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6790595858..44df06f957 100644 --- a/README.rst +++ b/README.rst @@ -414,7 +414,7 @@ both of which can be overwritten: You can use ``--json, -j`` to explicitly set ``Accept`` to ``application/json`` regardless of whether you are sending data (it's a shortcut for setting the header via the usual header notation – -``http url Accept:application/json, */*``). Additionally, +``http url Accept:'application/json, */*'``). Additionally, HTTPie will try to detect JSON responses even when the ``Content-Type`` is incorrectly ``text/plain`` or unknown. From 497a91711af7c97dcb70fe113a11cd90a7e070fd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 12 Sep 2016 09:13:37 +0200 Subject: [PATCH 0273/1182] README --- README.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 44df06f957..92fe8adbe6 100644 --- a/README.rst +++ b/README.rst @@ -499,8 +499,7 @@ Regular forms .. code-block:: bash - $ http --form POST api.example.org/person/1 name='John Smith' \ - email=john@example.org cv=@~/Documents/cv.txt + $ http --form POST api.example.org/person/1 name='John Smith' .. code-block:: http @@ -508,7 +507,7 @@ Regular forms POST /person/1 HTTP/1.1 Content-Type: application/x-www-form-urlencoded; charset=utf-8 - name=John+Smith&email=john%40example.org&cv=John's+CV+... + name=John+Smith ----------------- From 6bdfc7a071607308f9bbf2bfb301bdf0de29c080 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 12 Sep 2016 10:57:30 +0200 Subject: [PATCH 0274/1182] Update config and session file help URLs --- httpie/config.py | 2 +- httpie/sessions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/httpie/config.py b/httpie/config.py index f7282387d0..9cb6c4af36 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -80,7 +80,7 @@ def delete(self): class Config(BaseConfigDict): name = 'config' - helpurl = 'https://github.com/jkbrzt/httpie#config' + helpurl = 'https://httpie.org/docs#config' about = 'HTTPie configuration file' DEFAULTS = { diff --git a/httpie/sessions.py b/httpie/sessions.py index 9cfd7eea1d..249b78ba26 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -75,7 +75,7 @@ def get_response(requests_session, session_name, class Session(BaseConfigDict): - helpurl = 'https://github.com/jkbrzt/httpie#sessions' + helpurl = 'https://httpie.org/docs#sessions' about = 'HTTPie session file' def __init__(self, path, *args, **kwargs): From 64f6f69037082581743a736439be731eb4345f96 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 17 Sep 2016 15:58:05 +0200 Subject: [PATCH 0275/1182] Add Twitter link --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 92fe8adbe6..4ab4b2e382 100644 --- a/README.rst +++ b/README.rst @@ -1461,6 +1461,7 @@ Please use the following support channels: * `StackOverflow `_ to ask questions (please make sure to use the `httpie `_ tag). +* Tweet directly to `@clihttp `_. * You can also tweet directly to `@jkbrzt`_. From c6f2b32e367fc6fc00c926ccda56c8387fb11313 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 26 Oct 2016 11:16:34 +0200 Subject: [PATCH 0276/1182] Stricter KeyboardInterrupt silencing Relates to #531, but doesn't solve it completely. --- httpie/__main__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/httpie/__main__.py b/httpie/__main__.py index bed0ec7b55..83f3c690df 100644 --- a/httpie/__main__.py +++ b/httpie/__main__.py @@ -3,8 +3,11 @@ """ import sys -from .core import main if __name__ == '__main__': - sys.exit(main()) + try: + from .core import main + sys.exit(main()) + except KeyboardInterrupt: + sys.exit(1) From 48a6d234cb2accf501da109cce7898a1e4cc340c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 26 Oct 2016 11:21:30 +0200 Subject: [PATCH 0277/1182] Need a `main()` #531 --- httpie/__main__.py | 6 +++++- tests/test_regressions.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/httpie/__main__.py b/httpie/__main__.py index 83f3c690df..4191394287 100644 --- a/httpie/__main__.py +++ b/httpie/__main__.py @@ -5,9 +5,13 @@ import sys -if __name__ == '__main__': +def main(): try: from .core import main sys.exit(main()) except KeyboardInterrupt: sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/tests/test_regressions.py b/tests/test_regressions.py index 3ad441307f..c452a7cd31 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -11,7 +11,7 @@ def test_Host_header_overwrite(httpbin): """ host = 'httpbin.org' - url = httpbin.url + '/get' + url = httpbin.url + '/set?k2=v2&k1=v1' r = http('--print=hH', url, 'host:{0}'.format(host)) assert HTTP_OK in r assert r.lower().count('host:') == 1 From b96eba336dc6a963a56ad25d1a272535f38559ef Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 26 Oct 2016 11:28:17 +0200 Subject: [PATCH 0278/1182] Fixed test --- tests/test_regressions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_regressions.py b/tests/test_regressions.py index c452a7cd31..3ad441307f 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -11,7 +11,7 @@ def test_Host_header_overwrite(httpbin): """ host = 'httpbin.org' - url = httpbin.url + '/set?k2=v2&k1=v1' + url = httpbin.url + '/get' r = http('--print=hH', url, 'host:{0}'.format(host)) assert HTTP_OK in r assert r.lower().count('host:') == 1 From 9b23a4ac9a08e3f63677b328b3838816b08d8459 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 26 Oct 2016 11:53:01 +0200 Subject: [PATCH 0279/1182] Exit with status 130 on CTRL-C http://www.tldp.org/LDP/abs/html/exitcodes.html #531 --- CHANGELOG.rst | 1 + httpie/__init__.py | 4 ++++ httpie/__main__.py | 3 ++- httpie/core.py | 4 ++-- tests/test_exit_status.py | 18 +++++++++++++++++- tests/utils.py | 2 +- 6 files changed, 27 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0e347207d6..b3d4ee44d9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,7 @@ This project adheres to `Semantic Versioning `_. * Added support for ``curses``-less Python installations. * Fixed ``REQUEST_ITEM`` arg incorrectly being reported as required. +* Added 130 ``REQUEST_ITEM`` arg incorrectly being reported as required. `0.9.6`_ (2016-08-13) diff --git a/httpie/__init__.py b/httpie/__init__.py index 6c7fe03bd7..05b4cc0e19 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -11,6 +11,10 @@ class ExitStatus: """Exit status code constants.""" OK = 0 ERROR = 1 + + # 128+2 SIGINT + ERROR_CTRL_C = 130 + ERROR_TIMEOUT = 2 ERROR_TOO_MANY_REDIRECTS = 6 diff --git a/httpie/__main__.py b/httpie/__main__.py index 4191394287..052d0d1d35 100644 --- a/httpie/__main__.py +++ b/httpie/__main__.py @@ -10,7 +10,8 @@ def main(): from .core import main sys.exit(main()) except KeyboardInterrupt: - sys.exit(1) + from . import ExitStatus + sys.exit(ExitStatus.ERROR_CTRL_C) if __name__ == '__main__': diff --git a/httpie/core.py b/httpie/core.py index 7d7cca5e0e..1701750258 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -212,7 +212,7 @@ def log_error(msg, *args, **kwargs): env.stderr.write('\n') if include_traceback: raise - exit_status = ExitStatus.ERROR + exit_status = ExitStatus.ERROR_CTRL_C except SystemExit as e: if e.code != ExitStatus.OK: env.stderr.write('\n') @@ -230,7 +230,7 @@ def log_error(msg, *args, **kwargs): env.stderr.write('\n') if include_traceback: raise - exit_status = ExitStatus.ERROR + exit_status = ExitStatus.ERROR_CTRL_C except SystemExit as e: if e.code != ExitStatus.OK: env.stderr.write('\n') diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index 9249c87baa..8a73ff2bf6 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -1,9 +1,25 @@ +import mock + from httpie import ExitStatus from utils import TestEnvironment, http, HTTP_OK +def test_keyboard_interrupt_during_arg_parsing_exit_status(httpbin): + with mock.patch('httpie.cli.parser.parse_args', + side_effect=KeyboardInterrupt()): + r = http('GET', httpbin.url + '/status/200', error_exit_ok=True) + assert r.exit_status == ExitStatus.ERROR_CTRL_C + + +def test_keyboard_interrupt_in_program_exit_status(httpbin): + with mock.patch('httpie.core.program', + side_effect=KeyboardInterrupt()): + r = http('GET', httpbin.url + '/status/200', error_exit_ok=True) + assert r.exit_status == ExitStatus.ERROR_CTRL_C + + def test_ok_response_exits_0(httpbin): - r = http('GET', httpbin.url + '/status/200') + r = http('GET', httpbin.url + '/get') assert HTTP_OK in r assert r.exit_status == ExitStatus.OK diff --git a/tests/utils.py b/tests/utils.py index feede79058..63a4288ab9 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -192,7 +192,7 @@ def http(*args, **kwargs): args_with_config_defaults = args + env.config.default_options add_to_args = [] if '--debug' not in args_with_config_defaults: - if '--traceback' not in args_with_config_defaults: + if not error_exit_ok and '--traceback' not in args_with_config_defaults: add_to_args.append('--traceback') if not any('--timeout' in arg for arg in args_with_config_defaults): add_to_args.append('--timeout=3') From e9aba543b1fe92a1294f4c1b6d13c74e662c8c7d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 26 Oct 2016 11:54:35 +0200 Subject: [PATCH 0280/1182] Changelog --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b3d4ee44d9..1d2f8b9921 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,7 +11,7 @@ This project adheres to `Semantic Versioning `_. * Added support for ``curses``-less Python installations. * Fixed ``REQUEST_ITEM`` arg incorrectly being reported as required. -* Added 130 ``REQUEST_ITEM`` arg incorrectly being reported as required. +* Changed the exit status code to ``130`` for CTRL-C keyboard interrupts. `0.9.6`_ (2016-08-13) From 6267f21f2148505634e8727d1e1f2e7193dd5b47 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 26 Oct 2016 11:58:47 +0200 Subject: [PATCH 0281/1182] Clean-up --- tests/test_exit_status.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index 8a73ff2bf6..e3f89c14f5 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -7,14 +7,14 @@ def test_keyboard_interrupt_during_arg_parsing_exit_status(httpbin): with mock.patch('httpie.cli.parser.parse_args', side_effect=KeyboardInterrupt()): - r = http('GET', httpbin.url + '/status/200', error_exit_ok=True) + r = http('GET', httpbin.url + '/get', error_exit_ok=True) assert r.exit_status == ExitStatus.ERROR_CTRL_C def test_keyboard_interrupt_in_program_exit_status(httpbin): with mock.patch('httpie.core.program', side_effect=KeyboardInterrupt()): - r = http('GET', httpbin.url + '/status/200', error_exit_ok=True) + r = http('GET', httpbin.url + '/get', error_exit_ok=True) assert r.exit_status == ExitStatus.ERROR_CTRL_C From bfc23b1412883609966fc714355adfd9b4b1c5a7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 26 Oct 2016 12:18:53 +0200 Subject: [PATCH 0282/1182] Changelog --- CHANGELOG.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1d2f8b9921..14e1752dfe 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,7 +11,8 @@ This project adheres to `Semantic Versioning `_. * Added support for ``curses``-less Python installations. * Fixed ``REQUEST_ITEM`` arg incorrectly being reported as required. -* Changed the exit status code to ``130`` for CTRL-C keyboard interrupts. +* Improved ``CTRL-C`` interrupt handling. +* Added the standard exit status code ``130`` for keyboard interrupts. `0.9.6`_ (2016-08-13) From 4fef4b9a751fe9794332522689a08f8c0feeb41a Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Fri, 28 Oct 2016 12:02:21 +0800 Subject: [PATCH 0283/1182] Update README.rst Change "you shell" to "your shell" --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 4ab4b2e382..526b365067 100644 --- a/README.rst +++ b/README.rst @@ -304,7 +304,7 @@ If the port is omitted, then port 80 is assumed. 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 you shell. Also, special characters in parameter values, +separators for your shell. Also, special characters in parameter values, will also automatically escaped (HTTPie otherwise expects the URL to be already escaped). To search for ``HTTPie logo`` on Google Images you could use this command: From b879d38b072cf5d84ab8e8c82e71d6fabf883d38 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 23 Nov 2016 21:47:06 +0100 Subject: [PATCH 0284/1182] Test case for `Host` header removal (unimplemented feature) --- tests/test_httpie.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 37cc152c66..5cef1158c1 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -85,6 +85,15 @@ def test_headers_unset(httpbin_both): assert 'Accept' not in r.json['headers'] # default Accept unset +@pytest.mark.skip('unimplemented') +def test_unset_host_header(httpbin_both): + r = http('GET', httpbin_both + '/headers') + assert 'Host' in r.json['headers'] # default Host present + + r = http('GET', httpbin_both + '/headers', 'Host:') + assert 'Host' not in r.json['headers'] # default Host unset + + def test_headers_empty_value(httpbin_both): r = http('GET', httpbin_both + '/headers') assert r.json['headers']['Accept'] # default Accept has value From a49774d3abedd0da3a882728a073bec974c149e5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 23 Nov 2016 22:01:58 +0100 Subject: [PATCH 0285/1182] Extend auth plugin API This extends the `AuthPlugin` API by the following attributes: * `auth_require`: set to `False` to make `--auth, -a` optional * `auth_parse`: set to `False` to disable `username:password` parsing (access the raw value passed to `-a` via `self.raw_auth`). * `prompt_password`: set to`False` to disable password prompt when no password provided (only relevant when `auth_parse == True`) These changes should be 100% backwards-compatible. What needs more testing is auth support in sessions. Close #433 Close #431 Close #378 Ping teracyhq/httpie-jwt-auth#3 --- CHANGELOG.rst | 1 + httpie/cli.py | 38 +++++++++++----- httpie/client.py | 7 +-- httpie/input.py | 75 ++++++++++++++++++++++---------- httpie/plugins/base.py | 25 ++++++++++- httpie/plugins/builtin.py | 2 + httpie/plugins/manager.py | 3 ++ httpie/sessions.py | 34 ++++++++++++--- tests/test_auth.py | 4 +- tests/test_auth_plugins.py | 89 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 227 insertions(+), 51 deletions(-) create mode 100644 tests/test_auth_plugins.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 14e1752dfe..c919a4b72a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,7 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (Unreleased) ------------------------- +* Extended auth plugin API. * Added support for ``curses``-less Python installations. * Fixed ``REQUEST_ITEM`` arg incorrectly being reported as required. * Improved ``CTRL-C`` interrupt handling. diff --git a/httpie/cli.py b/httpie/cli.py index e78b59f275..05c4ac0cec 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -5,22 +5,25 @@ """ from textwrap import dedent, wrap # noinspection PyCompatibility -from argparse import (RawDescriptionHelpFormatter, FileType, - OPTIONAL, ZERO_OR_MORE, SUPPRESS) +from argparse import ( + RawDescriptionHelpFormatter, FileType, + OPTIONAL, ZERO_OR_MORE, SUPPRESS +) from httpie import __doc__, __version__ from httpie.plugins.builtin import BuiltinAuthPlugin from httpie.plugins import plugin_manager from httpie.sessions import DEFAULT_SESSIONS_DIR from httpie.output.formatters.colors import AVAILABLE_STYLES, DEFAULT_STYLE -from httpie.input import (HTTPieArgumentParser, - AuthCredentialsArgType, KeyValueArgType, - SEP_PROXY, SEP_CREDENTIALS, SEP_GROUP_ALL_ITEMS, - OUT_REQ_HEAD, OUT_REQ_BODY, OUT_RESP_HEAD, - OUT_RESP_BODY, OUTPUT_OPTIONS, - OUTPUT_OPTIONS_DEFAULT, PRETTY_MAP, - PRETTY_STDOUT_TTY_ONLY, SessionNameValidator, - readable_file_arg, SSL_VERSION_ARG_MAPPING) +from httpie.input import ( + HTTPieArgumentParser, KeyValueArgType, + SEP_PROXY, SEP_GROUP_ALL_ITEMS, + OUT_REQ_HEAD, OUT_REQ_BODY, OUT_RESP_HEAD, + OUT_RESP_BODY, OUTPUT_OPTIONS, + OUTPUT_OPTIONS_DEFAULT, PRETTY_MAP, + PRETTY_STDOUT_TTY_ONLY, SessionNameValidator, + readable_file_arg, SSL_VERSION_ARG_MAPPING +) class HTTPieHelpFormatter(RawDescriptionHelpFormatter): @@ -414,8 +417,8 @@ def _split_lines(self, text, width): auth = parser.add_argument_group(title='Authentication') auth.add_argument( '--auth', '-a', + default=None, metavar='USER[:PASS]', - type=AuthCredentialsArgType(SEP_CREDENTIALS), help=""" If only the username is provided (-a username), HTTPie will prompt for the password. @@ -423,10 +426,21 @@ def _split_lines(self, text, width): """, ) + +class _AuthTypeLazyChoices(object): + # Needed for plugin testing + + def __contains__(self, item): + return item in plugin_manager.get_auth_plugin_mapping() + + def __iter__(self): + return iter(plugin_manager.get_auth_plugins()) + + _auth_plugins = plugin_manager.get_auth_plugins() auth.add_argument( '--auth-type', '-A', - choices=[plugin.auth_type for plugin in _auth_plugins], + choices=_AuthTypeLazyChoices(), default=_auth_plugins[0].auth_type, help=""" The authentication mechanism to be used. Defaults to "{default}". diff --git a/httpie/client.py b/httpie/client.py index fb0fc62ca3..894a40d70b 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -145,11 +145,6 @@ def get_requests_kwargs(args, base_headers=None): headers.update(args.headers) headers = finalize_headers(headers) - credentials = None - if args.auth: - auth_plugin = plugin_manager.get_auth_plugin(args.auth_type)() - credentials = auth_plugin.get_auth(args.auth.key, args.auth.value) - cert = None if args.cert: cert = args.cert @@ -168,7 +163,7 @@ def get_requests_kwargs(args, base_headers=None): }.get(args.verify, args.verify), 'cert': cert, 'timeout': args.timeout, - 'auth': credentials, + 'auth': args.auth, 'proxies': dict((p.key, p.value) for p in args.proxy), 'files': args.files, 'allow_redirects': args.follow, diff --git a/httpie/input.py b/httpie/input.py index 99a4849cb8..a323e4ee82 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -15,6 +15,7 @@ # TODO: Use MultiDict for headers once added to `requests`. # https://github.com/jkbrzt/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 @@ -214,31 +215,56 @@ def _setup_standard_streams(self): self.env.stdout_isatty = False def _process_auth(self): - """ - If only a username provided via --auth, then ask for a password. - Or, take credentials from the URL, if provided. - - """ + # TODO: refactor + self.args.auth_plugin = None + default_auth_plugin = plugin_manager.get_auth_plugins()[0] + auth_type_set = self.args.auth_type != default_auth_plugin.auth_type url = urlsplit(self.args.url) - if self.args.auth: - if not self.args.auth.has_password(): - # Stdin already read (if not a tty) so it's save to prompt. - if self.args.ignore_stdin: - self.error('Unable to prompt for passwords because' - ' --ignore-stdin is set.') - self.args.auth.prompt_password(url.netloc) - - elif url.username is not None: - # Handle http://username:password@hostname/ - username = url.username - password = url.password or '' - self.args.auth = AuthCredentials( - key=username, - value=password, - sep=SEP_CREDENTIALS, - orig=SEP_CREDENTIALS.join([username, password]) - ) + if self.args.auth is None and not auth_type_set: + if url.username is not None: + # Handle http://username:password@hostname/ + username = url.username + password = url.password or '' + self.args.auth = AuthCredentials( + key=username, + value=password, + sep=SEP_CREDENTIALS, + orig=SEP_CREDENTIALS.join([username, password]) + ) + + if self.args.auth is not None or auth_type_set: + plugin = plugin_manager.get_auth_plugin(self.args.auth_type)() + + if plugin.auth_require and self.args.auth is None: + self.error('--auth required') + + plugin.raw_auth = self.args.auth + self.args.auth_plugin = plugin + already_parsed = isinstance(self.args.auth, AuthCredentials) + + if self.args.auth is None or not plugin.auth_parse: + self.args.auth = plugin.get_auth() + else: + if already_parsed: + # from the URL + credentials = self.args.auth + else: + credentials = parse_auth(self.args.auth) + + if (not credentials.has_password() + and plugin.prompt_password): + if self.args.ignore_stdin: + # Non-tty stdin read by now + self.error( + 'Unable to prompt for passwords because' + ' --ignore-stdin is set.' + ) + credentials.prompt_password(url.netloc) + self.args.auth = plugin.get_auth( + username=credentials.key, + password=credentials.value, + ) def _apply_no_options(self, no_options): """For every `--no-OPTION` in `no_options`, set `args.OPTION` to @@ -578,6 +604,9 @@ def __call__(self, string): ) +parse_auth = AuthCredentialsArgType(SEP_CREDENTIALS) + + class RequestItemsDict(OrderedDict): """Multi-value dict for URL parameters and form data.""" diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index ff6e6a2044..3129a80c06 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -17,13 +17,36 @@ class AuthPlugin(BasePlugin): See for an example auth plugin. + See also `test_auth_plugins.py` + """ # The value that should be passed to --auth-type # to use this auth plugin. Eg. "my-auth" auth_type = None - def get_auth(self, username, password): + # Set to `False` to make it possible to invoke this auth + # plugin without requiring the user to specify credentials + # through `--auth, -a`. + auth_require = True + + # By default the `-a` argument is parsed for `username:password`. + # Set this to `False` to disable the parsing and error handling. + auth_parse = True + + # If both `auth_parse` and `prompt_password` are set to `True`, + # and the value of `-a` lacks the password part, + # then the user will be prompted to type the password in. + prompt_password = True + + # Will be set to the raw value of `-a` (if provided) before + # `get_auth()` gets called. + raw_auth = None + + def get_auth(self, username=None, password=None): """ + If `auth_parse` is set to `True`, then `username` + and `password` contain the parsed credentials. + Return a ``requests.auth.AuthBase`` subclass instance. """ diff --git a/httpie/plugins/builtin.py b/httpie/plugins/builtin.py index 0e3aa26d7d..6b9640d1e9 100644 --- a/httpie/plugins/builtin.py +++ b/httpie/plugins/builtin.py @@ -36,6 +36,7 @@ class BasicAuthPlugin(BuiltinAuthPlugin): name = 'Basic HTTP auth' auth_type = 'basic' + # noinspection PyMethodOverriding def get_auth(self, username, password): return HTTPBasicAuth(username, password) @@ -45,5 +46,6 @@ class DigestAuthPlugin(BuiltinAuthPlugin): name = 'Digest HTTP auth' auth_type = 'digest' + # noinspection PyMethodOverriding def get_auth(self, username, password): return requests.auth.HTTPDigestAuth(username, password) diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index 239d32ae96..f7a2a063f4 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -24,6 +24,9 @@ def register(self, *plugins): for plugin in plugins: self._plugins.append(plugin) + def unregister(self, plugin): + self._plugins.remove(plugin) + def load_installed_plugins(self): for entry_point_name in ENTRY_POINT_NAMES: for entry_point in iter_entry_points(entry_point_name): diff --git a/httpie/sessions.py b/httpie/sessions.py index 249b78ba26..ff3969be3b 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -51,11 +51,10 @@ def get_response(requests_session, session_name, dump_request(kwargs) session.update_headers(kwargs['headers']) - if args.auth: + if args.auth_plugin: session.auth = { - 'type': args.auth_type, - 'username': args.auth.key, - 'password': args.auth.value, + 'type': args.auth_plugin.auth_type, + 'raw_auth': args.auth_plugin.raw_auth, } elif session.auth: kwargs['auth'] = session.auth @@ -147,10 +146,31 @@ def auth(self): auth = self.get('auth', None) if not auth or not auth['type']: return - auth_plugin = plugin_manager.get_auth_plugin(auth['type'])() - return auth_plugin.get_auth(auth['username'], auth['password']) + + plugin = plugin_manager.get_auth_plugin(auth['type'])() + + credentials = {'username': None, 'password': None} + try: + # New style + plugin.raw_auth = auth['raw_auth'] + except KeyError: + # Old style + credentials = { + 'username': auth['username'], + 'password': auth['password'], + } + else: + if plugin.auth_parse: + from httpie.input import parse_auth + parsed = parse_auth(plugin.raw_auth) + credentials = { + 'username': parsed.key, + 'password': parsed.value, + } + + return plugin.get_auth(**credentials) @auth.setter def auth(self, auth): - assert set(['type', 'username', 'password']) == set(auth.keys()) + assert set(['type', 'raw_auth']) == set(auth.keys()) self['auth'] = auth diff --git a/tests/test_auth.py b/tests/test_auth.py index 1d7395b6b2..c279e1cdb0 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -60,5 +60,5 @@ def test_only_username_in_url(url): """ args = httpie.cli.parser.parse_args(args=[url], env=TestEnvironment()) assert args.auth - assert args.auth.key == 'username' - assert args.auth.value == '' + assert args.auth.username == 'username' + assert args.auth.password == '' diff --git a/tests/test_auth_plugins.py b/tests/test_auth_plugins.py new file mode 100644 index 0000000000..233c599bb1 --- /dev/null +++ b/tests/test_auth_plugins.py @@ -0,0 +1,89 @@ +from utils import http, HTTP_OK +from httpie.plugins import AuthPlugin, plugin_manager + +# TODO: run all these tests in session mode as well + +# Basic auth encoded 'username' and 'password' +BASIC_AUTH_HEADER_VALUE = 'Basic dXNlcm5hbWU6cGFzc3dvcmQ=' +BASIC_AUTH_URL = '/basic-auth/username/password' + + +def dummy_auth(auth_header=BASIC_AUTH_HEADER_VALUE): + + def inner(r): + r.headers['Authorization'] = auth_header + return r + + return inner + + +def test_auth_plugin_parse_false(httpbin): + + class ParseFalseAuthPlugin(AuthPlugin): + auth_type = 'parse-false' + auth_parse = False + + def get_auth(self, username=None, password=None): + assert username is None + assert password is None + assert self.raw_auth == BASIC_AUTH_HEADER_VALUE + return dummy_auth(self.raw_auth) + + plugin_manager.register(ParseFalseAuthPlugin) + try: + r = http( + httpbin + BASIC_AUTH_URL, + '--auth-type', 'parse-false', + '--auth', BASIC_AUTH_HEADER_VALUE + ) + assert HTTP_OK in r + finally: + plugin_manager.unregister(ParseFalseAuthPlugin) + + +def test_auth_plugin_require_false(httpbin): + + class RequireFalseAuthPlugin(AuthPlugin): + auth_type = 'require-false' + auth_require = False + + def get_auth(self, username=None, password=None): + assert self.raw_auth is None + assert username is None + assert password is None + return dummy_auth() + + plugin_manager.register(RequireFalseAuthPlugin) + try: + r = http( + httpbin + BASIC_AUTH_URL, + '--auth-type', 'require-false', + ) + assert HTTP_OK in r + finally: + plugin_manager.unregister(RequireFalseAuthPlugin) + + +def test_auth_plugin_prompt_false(httpbin): + + class PromptFalseAuthPlugin(AuthPlugin): + auth_type = 'prompt-false' + prompt_password = False + + def get_auth(self, username=None, password=None): + assert self.raw_auth == 'username:' + assert username == 'username' + assert password == '' + return dummy_auth() + + plugin_manager.register(PromptFalseAuthPlugin) + + try: + r = http( + httpbin + BASIC_AUTH_URL, + '--auth-type', 'prompt-false', + '--auth', 'username:' + ) + assert HTTP_OK in r + finally: + plugin_manager.unregister(PromptFalseAuthPlugin) From 54a63a810e49f2333ae4e556639f2b6655ce9ba4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 23 Nov 2016 22:29:36 +0100 Subject: [PATCH 0286/1182] Cleanup/docstring --- httpie/plugins/base.py | 3 +++ tests/test_auth_plugins.py | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index 3129a80c06..30d88595af 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -47,6 +47,9 @@ def get_auth(self, username=None, password=None): If `auth_parse` is set to `True`, then `username` and `password` contain the parsed credentials. + Use `self.raw_auth` to access the raw value passed through + `--auth, -a`. + Return a ``requests.auth.AuthBase`` subclass instance. """ diff --git a/tests/test_auth_plugins.py b/tests/test_auth_plugins.py index 233c599bb1..efd2232c64 100644 --- a/tests/test_auth_plugins.py +++ b/tests/test_auth_plugins.py @@ -17,7 +17,7 @@ def inner(r): return inner -def test_auth_plugin_parse_false(httpbin): +def test_auth_plugin_parse_auth_false(httpbin): class ParseFalseAuthPlugin(AuthPlugin): auth_type = 'parse-false' @@ -41,7 +41,7 @@ def get_auth(self, username=None, password=None): plugin_manager.unregister(ParseFalseAuthPlugin) -def test_auth_plugin_require_false(httpbin): +def test_auth_plugin_require_auth_false(httpbin): class RequireFalseAuthPlugin(AuthPlugin): auth_type = 'require-false' @@ -64,7 +64,7 @@ def get_auth(self, username=None, password=None): plugin_manager.unregister(RequireFalseAuthPlugin) -def test_auth_plugin_prompt_false(httpbin): +def test_auth_plugin_prompt_password_false(httpbin): class PromptFalseAuthPlugin(AuthPlugin): auth_type = 'prompt-false' From 47fd392c74f5f99e3cb1d1707adb4aafcd72d176 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 23 Nov 2016 22:33:22 +0100 Subject: [PATCH 0287/1182] Cleanup --- httpie/cli.py | 1 + setup.py | 1 + 2 files changed, 2 insertions(+) diff --git a/httpie/cli.py b/httpie/cli.py index 05c4ac0cec..996a61facd 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -44,6 +44,7 @@ def _split_lines(self, text, width): text = dedent(text).strip() + '\n\n' return text.splitlines() + parser = HTTPieArgumentParser( formatter_class=HTTPieHelpFormatter, description='%s ' % __doc__.strip(), diff --git a/setup.py b/setup.py index 3dc8862095..0a15862a55 100644 --- a/setup.py +++ b/setup.py @@ -69,6 +69,7 @@ def long_description(): with codecs.open('README.rst', encoding='utf8') as f: return f.read() + setup( name='httpie', version=httpie.__version__, From 3f7ed3523848ad942fc3f55c969118e92ba6b344 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 23 Nov 2016 23:09:45 +0100 Subject: [PATCH 0288/1182] Add more plugin API tests --- httpie/cli.py | 2 +- httpie/input.py | 4 +- tests/test_auth.py | 11 +++++ tests/test_auth_plugins.py | 83 +++++++++++++++++++++++++++++--------- 4 files changed, 78 insertions(+), 22 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 996a61facd..038efd6e8a 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -442,7 +442,7 @@ def __iter__(self): auth.add_argument( '--auth-type', '-A', choices=_AuthTypeLazyChoices(), - default=_auth_plugins[0].auth_type, + default=None, help=""" The authentication mechanism to be used. Defaults to "{default}". diff --git a/httpie/input.py b/httpie/input.py index a323e4ee82..9d5ecd1a79 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -218,7 +218,7 @@ def _process_auth(self): # TODO: refactor self.args.auth_plugin = None default_auth_plugin = plugin_manager.get_auth_plugins()[0] - auth_type_set = self.args.auth_type != default_auth_plugin.auth_type + auth_type_set = self.args.auth_type is not None url = urlsplit(self.args.url) if self.args.auth is None and not auth_type_set: @@ -234,6 +234,8 @@ def _process_auth(self): ) if self.args.auth is not None or auth_type_set: + if not self.args.auth_type: + self.args.auth_type = default_auth_plugin.auth_type plugin = plugin_manager.get_auth_plugin(self.args.auth_type)() if plugin.auth_require and self.args.auth is None: diff --git a/tests/test_auth.py b/tests/test_auth.py index c279e1cdb0..a5fd5da34b 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -62,3 +62,14 @@ def test_only_username_in_url(url): assert args.auth assert args.auth.username == 'username' assert args.auth.password == '' + + +def test_missing_auth(httpbin): + r = http( + '--auth-type=basic', + 'GET', + httpbin + '/basic-auth/user/password', + error_exit_ok=True + ) + assert HTTP_OK not in r + assert '--auth required' in r.stderr diff --git a/tests/test_auth_plugins.py b/tests/test_auth_plugins.py index efd2232c64..84cff2873a 100644 --- a/tests/test_auth_plugins.py +++ b/tests/test_auth_plugins.py @@ -1,11 +1,17 @@ +from mock import mock + from utils import http, HTTP_OK +from httpie.input import SEP_CREDENTIALS from httpie.plugins import AuthPlugin, plugin_manager # TODO: run all these tests in session mode as well -# Basic auth encoded 'username' and 'password' -BASIC_AUTH_HEADER_VALUE = 'Basic dXNlcm5hbWU6cGFzc3dvcmQ=' -BASIC_AUTH_URL = '/basic-auth/username/password' +USERNAME = 'user' +PASSWORD = 'password' +# Basic auth encoded `USERNAME` and `PASSWORD` +BASIC_AUTH_HEADER_VALUE = 'Basic dXNlcjpwYXNzd29yZA==' +BASIC_AUTH_URL = '/basic-auth/{}/{}'.format(USERNAME, PASSWORD) +AUTH_OK = {'authenticated': True, 'user': USERNAME} def dummy_auth(auth_header=BASIC_AUTH_HEADER_VALUE): @@ -19,7 +25,7 @@ def inner(r): def test_auth_plugin_parse_auth_false(httpbin): - class ParseFalseAuthPlugin(AuthPlugin): + class Plugin(AuthPlugin): auth_type = 'parse-false' auth_parse = False @@ -29,21 +35,24 @@ def get_auth(self, username=None, password=None): assert self.raw_auth == BASIC_AUTH_HEADER_VALUE return dummy_auth(self.raw_auth) - plugin_manager.register(ParseFalseAuthPlugin) + plugin_manager.register(Plugin) try: r = http( httpbin + BASIC_AUTH_URL, - '--auth-type', 'parse-false', - '--auth', BASIC_AUTH_HEADER_VALUE + '--auth-type', + Plugin.auth_type, + '--auth', + BASIC_AUTH_HEADER_VALUE, ) assert HTTP_OK in r + assert r.json == AUTH_OK finally: - plugin_manager.unregister(ParseFalseAuthPlugin) + plugin_manager.unregister(Plugin) def test_auth_plugin_require_auth_false(httpbin): - class RequireFalseAuthPlugin(AuthPlugin): + class Plugin(AuthPlugin): auth_type = 'require-false' auth_require = False @@ -53,37 +62,71 @@ def get_auth(self, username=None, password=None): assert password is None return dummy_auth() - plugin_manager.register(RequireFalseAuthPlugin) + plugin_manager.register(Plugin) + try: + r = http( + httpbin + BASIC_AUTH_URL, + '--auth-type', + Plugin.auth_type, + ) + assert HTTP_OK in r + assert r.json == AUTH_OK + finally: + plugin_manager.unregister(Plugin) + + +def test_auth_plugin_require_auth_false_and_auth_provided(httpbin): + + class Plugin(AuthPlugin): + auth_type = 'require-false-yet-provided' + auth_require = False + + def get_auth(self, username=None, password=None): + assert self.raw_auth == USERNAME + SEP_CREDENTIALS + PASSWORD + assert username == USERNAME + assert password == PASSWORD + return dummy_auth() + + plugin_manager.register(Plugin) try: r = http( httpbin + BASIC_AUTH_URL, - '--auth-type', 'require-false', + '--auth-type', + Plugin.auth_type, + '--auth', + USERNAME + SEP_CREDENTIALS + PASSWORD, ) assert HTTP_OK in r + assert r.json == AUTH_OK finally: - plugin_manager.unregister(RequireFalseAuthPlugin) + plugin_manager.unregister(Plugin) +@mock.patch('httpie.input.AuthCredentials._getpass', + new=lambda self, prompt: 'unexpected prompt response') def test_auth_plugin_prompt_password_false(httpbin): - class PromptFalseAuthPlugin(AuthPlugin): + class Plugin(AuthPlugin): auth_type = 'prompt-false' prompt_password = False def get_auth(self, username=None, password=None): - assert self.raw_auth == 'username:' - assert username == 'username' - assert password == '' + assert self.raw_auth == USERNAME + assert username == USERNAME + assert password is None return dummy_auth() - plugin_manager.register(PromptFalseAuthPlugin) + plugin_manager.register(Plugin) try: r = http( httpbin + BASIC_AUTH_URL, - '--auth-type', 'prompt-false', - '--auth', 'username:' + '--auth-type', + Plugin.auth_type, + '--auth', + USERNAME, ) assert HTTP_OK in r + assert r.json == AUTH_OK finally: - plugin_manager.unregister(PromptFalseAuthPlugin) + plugin_manager.unregister(Plugin) From 5a1bd4ba83022e0c85ead6e410d2d8085349c7bb Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 23 Nov 2016 23:15:18 +0100 Subject: [PATCH 0289/1182] Cleanup --- tests/test_auth_plugins.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/test_auth_plugins.py b/tests/test_auth_plugins.py index 84cff2873a..854a5676c1 100644 --- a/tests/test_auth_plugins.py +++ b/tests/test_auth_plugins.py @@ -14,10 +14,10 @@ AUTH_OK = {'authenticated': True, 'user': USERNAME} -def dummy_auth(auth_header=BASIC_AUTH_HEADER_VALUE): +def basic_auth(header=BASIC_AUTH_HEADER_VALUE): def inner(r): - r.headers['Authorization'] = auth_header + r.headers['Authorization'] = header return r return inner @@ -26,14 +26,14 @@ def inner(r): def test_auth_plugin_parse_auth_false(httpbin): class Plugin(AuthPlugin): - auth_type = 'parse-false' + auth_type = 'test-parse-false' auth_parse = False def get_auth(self, username=None, password=None): assert username is None assert password is None assert self.raw_auth == BASIC_AUTH_HEADER_VALUE - return dummy_auth(self.raw_auth) + return basic_auth(self.raw_auth) plugin_manager.register(Plugin) try: @@ -53,14 +53,14 @@ def get_auth(self, username=None, password=None): def test_auth_plugin_require_auth_false(httpbin): class Plugin(AuthPlugin): - auth_type = 'require-false' + auth_type = 'test-require-false' auth_require = False def get_auth(self, username=None, password=None): assert self.raw_auth is None assert username is None assert password is None - return dummy_auth() + return basic_auth() plugin_manager.register(Plugin) try: @@ -78,14 +78,14 @@ def get_auth(self, username=None, password=None): def test_auth_plugin_require_auth_false_and_auth_provided(httpbin): class Plugin(AuthPlugin): - auth_type = 'require-false-yet-provided' + auth_type = 'test-require-false-yet-provided' auth_require = False def get_auth(self, username=None, password=None): assert self.raw_auth == USERNAME + SEP_CREDENTIALS + PASSWORD assert username == USERNAME assert password == PASSWORD - return dummy_auth() + return basic_auth() plugin_manager.register(Plugin) try: @@ -103,18 +103,18 @@ def get_auth(self, username=None, password=None): @mock.patch('httpie.input.AuthCredentials._getpass', - new=lambda self, prompt: 'unexpected prompt response') + new=lambda self, prompt: 'UNEXPECTED_PROMPT_RESPONSE') def test_auth_plugin_prompt_password_false(httpbin): class Plugin(AuthPlugin): - auth_type = 'prompt-false' + auth_type = 'test-prompt-false' prompt_password = False def get_auth(self, username=None, password=None): assert self.raw_auth == USERNAME assert username == USERNAME assert password is None - return dummy_auth() + return basic_auth() plugin_manager.register(Plugin) From 0b84180485672f978e90bfa39f28f7cb799e9795 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 23 Nov 2016 23:20:52 +0100 Subject: [PATCH 0290/1182] Fix Python 2.6 --- tests/test_auth_plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_auth_plugins.py b/tests/test_auth_plugins.py index 854a5676c1..725f0af4b1 100644 --- a/tests/test_auth_plugins.py +++ b/tests/test_auth_plugins.py @@ -10,7 +10,7 @@ PASSWORD = 'password' # Basic auth encoded `USERNAME` and `PASSWORD` BASIC_AUTH_HEADER_VALUE = 'Basic dXNlcjpwYXNzd29yZA==' -BASIC_AUTH_URL = '/basic-auth/{}/{}'.format(USERNAME, PASSWORD) +BASIC_AUTH_URL = '/basic-auth/{0}/{1}'.format(USERNAME, PASSWORD) AUTH_OK = {'authenticated': True, 'user': USERNAME} From 2bf71af28665ded43c2bb394be373ddf4ec89cc1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 23 Nov 2016 23:36:46 +0100 Subject: [PATCH 0291/1182] pep8 --- httpie/input.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httpie/input.py b/httpie/input.py index 9d5ecd1a79..97f83edc48 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -254,8 +254,8 @@ def _process_auth(self): 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( From 2efc0db8d4f14d30b38eaafa165e0b74215a95d1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 24 Nov 2016 00:58:41 +0100 Subject: [PATCH 0292/1182] Cleanup --- httpie/cli.py | 10 +++++----- tests/test_auth_plugins.py | 3 ++- tests/test_binary.py | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 038efd6e8a..2194321baf 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -3,18 +3,14 @@ NOTE: the CLI interface may change before reaching v1.0. """ -from textwrap import dedent, wrap # noinspection PyCompatibility from argparse import ( RawDescriptionHelpFormatter, FileType, OPTIONAL, ZERO_OR_MORE, SUPPRESS ) +from textwrap import dedent, wrap from httpie import __doc__, __version__ -from httpie.plugins.builtin import BuiltinAuthPlugin -from httpie.plugins import plugin_manager -from httpie.sessions import DEFAULT_SESSIONS_DIR -from httpie.output.formatters.colors import AVAILABLE_STYLES, DEFAULT_STYLE from httpie.input import ( HTTPieArgumentParser, KeyValueArgType, SEP_PROXY, SEP_GROUP_ALL_ITEMS, @@ -24,6 +20,10 @@ PRETTY_STDOUT_TTY_ONLY, SessionNameValidator, readable_file_arg, SSL_VERSION_ARG_MAPPING ) +from httpie.output.formatters.colors import AVAILABLE_STYLES, DEFAULT_STYLE +from httpie.plugins import plugin_manager +from httpie.plugins.builtin import BuiltinAuthPlugin +from httpie.sessions import DEFAULT_SESSIONS_DIR class HTTPieHelpFormatter(RawDescriptionHelpFormatter): diff --git a/tests/test_auth_plugins.py b/tests/test_auth_plugins.py index 725f0af4b1..0d0fa26dbc 100644 --- a/tests/test_auth_plugins.py +++ b/tests/test_auth_plugins.py @@ -1,14 +1,15 @@ from mock import mock -from utils import http, HTTP_OK from httpie.input import SEP_CREDENTIALS from httpie.plugins import AuthPlugin, plugin_manager +from utils import http, HTTP_OK # TODO: run all these tests in session mode as well USERNAME = 'user' PASSWORD = 'password' # Basic auth encoded `USERNAME` and `PASSWORD` +# noinspection SpellCheckingInspection BASIC_AUTH_HEADER_VALUE = 'Basic dXNlcjpwYXNzd29yZA==' BASIC_AUTH_URL = '/basic-auth/{0}/{1}'.format(USERNAME, PASSWORD) AUTH_OK = {'authenticated': True, 'user': USERNAME} diff --git a/tests/test_binary.py b/tests/test_binary.py index 9d4702e97e..a76b9cfab8 100644 --- a/tests/test_binary.py +++ b/tests/test_binary.py @@ -1,8 +1,8 @@ """Tests for dealing with binary request and response data.""" +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 fixtures import BIN_FILE_PATH, BIN_FILE_CONTENT, BIN_FILE_PATH_ARG class TestBinaryRequestData: From 923b7acbe69ece942eac543fd3359ea15e0a3dbe Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 7 Dec 2016 05:56:53 +0100 Subject: [PATCH 0293/1182] Docs --- README.rst | 459 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 266 insertions(+), 193 deletions(-) diff --git a/README.rst b/README.rst index 526b365067..138c9da119 100644 --- a/README.rst +++ b/README.rst @@ -1,16 +1,15 @@ -######################################## HTTPie: a CLI, cURL-like tool for humans ######################################## -.. class:: no-web +HTTPie (pronounced *aitch-tee-tee-pie*) is a command line HTTP client. +Its goal is to make CLI interaction with web services as human-friendly +as possible. It provides a simple ``http`` command that allows for sending +arbitrary HTTP requests using a simple and natural syntax, and displays +colorized output. HTTPie can be used for testing, debugging, and +generally interacting with HTTP servers. - HTTPie (pronounced *aitch-tee-tee-pie*) is a **command line HTTP client**. - Its goal is to make CLI interaction with web services as **human-friendly** - as possible. It provides a simple ``http`` command that allows for sending - arbitrary HTTP requests using a simple and natural syntax, and displays - colorized output. HTTPie can be used for **testing, debugging**, and - generally **interacting** with HTTP servers. +.. class:: no-web .. image:: https://raw.githubusercontent.com/jkbrzt/httpie/master/httpie.png :alt: HTTPie compared to cURL @@ -18,9 +17,6 @@ HTTPie: a CLI, cURL-like tool for humans :align: center - - - .. class:: no-web no-pdf |pypi| |unix_build| |windows_build| |coverage| |gitter| @@ -36,7 +32,6 @@ HTTPie: a CLI, cURL-like tool for humans PageBreak oneColumn -============= Main features ============= @@ -56,12 +51,15 @@ Main features * Test coverage -============ Installation ============ -On **Mac OS X**, HTTPie can be installed via `Homebrew `_ +macOS +----- + + +On macOS, HTTPie can be installed via `Homebrew `_ (recommended): .. code-block:: bash @@ -75,8 +73,10 @@ A MacPorts *port* is also available: $ port install httpie +Linux +----- -Most **Linux** distributions provide a package that can be installed using the +Most Linux distributions provide a package that can be installed using the system package manager, e.g.: .. code-block:: bash @@ -91,8 +91,11 @@ system package manager, e.g.: $ pacman -S httpie -A **universal installation method** (that works on **Windows**, Mac OS X, Linux, …, -and provides the latest version) is to use `pip`_: +Windows, etc. +------------- + +A universal installation method (that works on Windows, Mac OS X, Linux, …, +and always provides the latest version) is to use `pip`_: .. code-block:: bash @@ -107,11 +110,10 @@ and 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: +The latest development version can be installed directly from GitHub: .. code-block:: bash @@ -122,7 +124,6 @@ The **latest development version** can be installed directly from GitHub: $ pip install --upgrade https://github.com/jkbrzt/httpie/archive/master.tar.gz --------------- Python version -------------- @@ -134,7 +135,6 @@ Python 3 is the default for Homebrew installations starting with version 0.9.4. To see which version HTTPie uses, run ``http --debug``. -===== Usage ===== @@ -157,7 +157,6 @@ Synopsis: See also ``http --help``. --------- Examples -------- @@ -229,13 +228,7 @@ Set a custom ``Host`` header to work around missing DNS records: .. --------- - -*What follows is a detailed documentation. It covers the command syntax, -advanced usage, and also features additional examples.* - -=========== HTTP method =========== @@ -253,11 +246,10 @@ Which looks similar to the actual ``Request-Line`` that is sent: DELETE /todos/7 HTTP/1.1 -When the ``METHOD`` argument is **omitted** from the command, HTTPie defaults to +When the ``METHOD`` argument is omitted from the command, HTTPie defaults to either ``GET`` (with no request data) or ``POST`` (with request data). -=========== Request URL =========== @@ -265,6 +257,39 @@ The only information HTTPie needs to perform a request is a URL. The default scheme is, somewhat unsurprisingly, ``http://``, and can be omitted from the argument – ``http example.org`` works just fine. + +Querystring parameters +---------------------- + +If you find yourself manually constructing URLs with +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, +will also automatically escaped (HTTPie otherwise expects the URL to be +already escaped). To search for ``HTTPie logo`` on Google Images you could use +this command: + +.. code-block:: bash + + $ http www.google.com search=='HTTPie logo' tbm==isch + + +.. code-block:: http + + GET /?search=HTTPie+logo&tbm=isch HTTP/1.1 + +You can use the ``--default-scheme `` option to create +shortcuts for other protocols than HTTP: + +.. code-block:: bash + + $ alias https='http --default-scheme=https' + + + +URL shortcuts for ``localhost`` +------------------------------- + Additionally, curl-like shorthand for localhost is supported. This means that, for example ``:3000`` would expand to ``http://localhost:3000`` If the port is omitted, then port 80 is assumed. @@ -301,32 +326,8 @@ If the port is omitted, then port 80 is assumed. GET / HTTP/1.1 Host: localhost -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, -will also automatically escaped (HTTPie otherwise expects the URL to be -already escaped). To search for ``HTTPie logo`` on Google Images you could use -this command: - -.. code-block:: bash - - $ http www.google.com search=='HTTPie logo' tbm==isch - -.. code-block:: http - - GET /?search=HTTPie+logo&tbm=isch HTTP/1.1 - -You can use the ``--default-scheme `` option to create -shortcuts for other protocols than HTTP: - -.. code-block:: bash - $ alias https='http --default-scheme=https' - - -============= Request items ============= @@ -367,6 +368,14 @@ 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. + + +Escaping rules +-------------- + You can use ``\`` to escape characters that shouldn't be used as separators (or parts thereof). For instance, ``foo\==bar`` will become a data key/value pair (``foo=`` and ``bar``) instead of a URL parameter. @@ -379,44 +388,26 @@ token ``--`` to prevent confusion with ``--arguments``: .. code-block:: bash - $ http httpbin.org/post -- -name-starting-with-dash=foo --Weird-Header:bar + $ http httpbin.org/post -- -name-starting-with-dash=foo -Unusual-Header:bar .. code-block:: http POST /post HTTP/1.1 - --Weird-Header: bar + -Unusual-Header: bar + Content-Type: application/json { "-name-starting-with-dash": "value" } -Note that data fields aren't the only way to specify request data: -`Redirected input`_ allows for passing arbitrary data to be sent with the -request. -==== 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 by default uses. -If your command includes some data items, they are serialized as a JSON -object by default. HTTPie also automatically sets the following headers, -both of which can be overwritten: - -================ ======================================= -``Content-Type`` ``application/json`` -``Accept`` ``application/json, */*`` -================ ======================================= - -You can use ``--json, -j`` to explicitly set ``Accept`` -to ``application/json`` regardless of whether you are sending data -(it's a shortcut for setting the header via the usual header notation – -``http url Accept:'application/json, */*'``). Additionally, -HTTPie will try to detect JSON responses even when the -``Content-Type`` is incorrectly ``text/plain`` or unknown. Simple example: @@ -438,6 +429,35 @@ Simple example: } +Default behaviour +----------------- + + +If your command includes some data `request items`_, they are serialized as a JSON +object by default. HTTPie also automatically sets the following headers, +both of which can be overwritten: + +================ ======================================= +``Content-Type`` ``application/json`` +``Accept`` ``application/json, */*`` +================ ======================================= + + +Enforced JSON +------------- + +You can use ``--json, -j`` to explicitly set ``Accept`` +to ``application/json`` regardless of whether you are sending data +(it's a shortcut for setting the header via the usual header notation: +``http url Accept:'application/json, */*'``). Additionally, +HTTPie will try to detect JSON responses even when the +``Content-Type`` is incorrectly ``text/plain`` or unknown. + + + +Non-string JSON fields +---------------------- + Non-string fields use the ``:=`` separator, which allows you to embed raw JSON into the resulting object. Text and raw JSON files can also be embedded into fields using ``=@`` and ``:=@``: @@ -473,27 +493,25 @@ fields using ``=@`` and ``:=@``: } -Send JSON data stored in a file (see `redirected input`_ for more examples): +Please note that with this syntax the command gets unwieldy when sending +complex data. In that case it's always better to use `redirected input`_: .. code-block:: bash $ http POST api.example.com/person/1 < person.json -===== Forms ===== Submitting forms is very similar to sending `JSON`_ requests. Often the only difference is in adding the ``--form, -f`` option, which ensures that data fields are serialized as, and ``Content-Type`` is set to, -``application/x-www-form-urlencoded; charset=utf-8``. - -It is possible to make form data the implicit content type instead of JSON +``application/x-www-form-urlencoded; charset=utf-8``. It is possible to make +form data the implicit content type instead of JSON via the `config`_ file. -------------- Regular forms ------------- @@ -510,7 +528,6 @@ Regular forms name=John+Smith ------------------ File upload forms ----------------- @@ -536,7 +553,6 @@ Note that ``@`` is used to simulate a file upload form field, whereas ``=@`` just embeds the file content as a regular text field value. -============ HTTP headers ============ @@ -560,6 +576,9 @@ To set custom headers you can use the ``Header:Value`` notation: X-Foo: Bar +Default request headers +----------------------- + There are a couple of default headers that HTTPie sets: .. code-block:: http @@ -571,10 +590,16 @@ There are a couple of default headers that HTTPie sets: Host: -Any of the default headers can be overwritten and some of them unset. -To unset a header that has already been specified (such a one of the default -headers), use ``Header:``: +Any of those—except for ``Host``—can be overwritten and some of them unset. + + + +Empty headers and header un-setting +----------------------------------- + +To unset a previously specified header +(such a one of the default headers), use ``Header:``: .. code-block:: bash @@ -590,7 +615,6 @@ To send a header with an empty value, use ``Header;``: $ http httpbin.org/headers 'Header;' -============== Authentication ============== @@ -614,7 +638,8 @@ The currently supported authentication schemes are Basic and Digest -Basic auth: +Basic auth +---------- .. code-block:: bash @@ -622,7 +647,8 @@ Basic auth: $ http -a username:password example.org -Digest auth: +Digest auth +----------- .. code-block:: bash @@ -630,13 +656,17 @@ Digest auth: $ http -A digest -a username:password example.org -With password prompt: +Password prompt +--------------- .. code-block:: bash $ http -a username example.org +``.netrc`` +---------- + Authorization information from your ``~/.netrc`` file is honored as well: .. code-block:: bash @@ -651,10 +681,13 @@ Authorization information from your ``~/.netrc`` file is honored as well: [...] ------------- Auth plugins ------------ +Additional authentication mechanism can be installed as plugins. +They can be found on the `Python Package Index `_. +Here's a few picks: + * `httpie-oauth `_: OAuth * `httpie-hmac-auth `_: HMAC * `httpie-ntlm `_: NTLM (NT LAN Manager) @@ -665,19 +698,50 @@ Auth plugins * `httpie-jwt-auth `_: JWTAuth (JSON Web Tokens) -============== + + HTTP redirects ============== By default, HTTP redirects are not followed and only the first -response is shown. To instruct HTTPie to follow the ``Location`` header of -``30x`` responses and show the final response instead, use the ``--follow, -F`` option. +response is shown: + + +.. code-block:: bash + + $ http httpbin.org/redirect/3 + + +Follow ``Location`` +------------------- + +To instruct HTTPie to follow the ``Location`` header of ``30x`` responses +and show the final response instead, use the ``--follow, -F`` option: + + +.. code-block:: bash + + $ http --follow httpbin.org/redirect/3 + + +Showing intermediary redirect responses +--------------------------------------- If you additionally wish to see the intermediary requests/responses, -then use the ``--all`` option as well. +then use the ``--all`` option as well: + + +.. code-block:: bash + + $ http --follow --all httpbin.org/redirect/3 + + + +Limiting maximum redirects followed +----------------------------------- -To change the default limit of maximum 30 redirects, use the -``--max-redirects=`` option. +To change the default limit of maximum ``30`` redirects, use the +``--max-redirects=`` option: .. code-block:: bash @@ -685,7 +749,6 @@ To change the default limit of maximum 30 redirects, use the $ http --follow --all --max-redirects=5 httpbin.org/redirect/3 -======= Proxies ======= @@ -703,6 +766,10 @@ With Basic authentication: $ http --proxy=http:http://user:pass@10.10.1.10:3128 example.org + +Environment variables +--------------------- + You can also configure proxies by environment variables ``HTTP_PROXY`` and ``HTTPS_PROXY``, and the underlying Requests library will pick them up as well. If you want to disable proxies configured through the environment variables for @@ -717,7 +784,6 @@ In your ``~/.bash_profile``: export NO_PROXY=localhost,example.com ------ SOCKS ----- @@ -735,42 +801,35 @@ Usage is the same as for other types of `proxies`_: $ http --proxy=http:socks5://user:pass@host:port --proxy=https:socks5://user:pass@host:port example.org -===== HTTPS ===== ------------------------------------ + Server SSL certificate verification ----------------------------------- -To skip the **host's SSL certificate verification,** you can pass -``--verify=no`` (default is ``yes``): +To skip the host's SSL certificate verification, you can pass ``--verify=no`` +(default is ``yes``): .. code-block:: bash $ http --verify=no https://example.org -You can also use ``--verify=`` to set a **custom CA bundle** -path: +Custom CA bundle +---------------- + +You can also use ``--verify=`` to set a custom CA bundle path: .. code-block:: bash $ http --verify=/ssl/custom_ca_bundle https://example.org -The path can also be configured via the environment variable -``REQUESTS_CA_BUNDLE`` (picked up by the underlying python-requests library): - -.. code-block:: bash - - $ REQUESTS_CA_BUNDLE=/ssl/custom_ca_bundle http https://example.org - ---------------------------- Client side SSL certificate --------------------------- -To use a **client side certificate** for the SSL communication, you can pass +To use a client side certificate for the SSL communication, you can pass the path of the cert file with ``--cert``: .. code-block:: bash @@ -778,7 +837,7 @@ the path of the cert file with ``--cert``: $ http --cert=client.pem https://example.org -If the **private key** is not contained in the cert file you may pass the +If the private key is not contained in the cert file you may pass the path of the key file with ``--cert-key``: .. code-block:: bash @@ -786,7 +845,6 @@ path of the key file with ``--cert-key``: $ http --cert=client.crt --cert-key=client.key https://example.org ------------ SSL version ----------- @@ -802,18 +860,17 @@ available set of protocols may vary depending on your OpenSSL installation.) $ http --ssl=ssl3 https://vulnerable.example.org ----------------------------- SNI (Server Name Indication) ---------------------------- If you use HTTPie with `Python version`_ lower than 2.7.9 (can be verified with ``http --debug``) and need to talk to servers that -use **SNI (Server Name Indication)** you need to install some additional +use SNI (Server Name Indication) you need to install some additional dependencies: .. code-block:: bash - $ pip install --upgrade pyopenssl pyasn1 ndg-httpsclient + $ pip install --upgrade requests[security] You can use the following command to test SNI support: @@ -823,14 +880,12 @@ You can use the following command to test SNI support: $ http https://sni.velox.ch -============== Output options ============== By default, HTTPie only outputs the final response and the whole response -message is printed (headers as well as the body). - -You can control what should be printed via several options: +message is printed (headers as well as the body). You can control what should +be printed via several options: ================= ===================================================== ``--headers, -h`` Only the response headers are printed. @@ -870,9 +925,12 @@ documentation examples: } -All the other options are just a shortcut for ``--print, -p``. -It accepts a string of characters each of which represents a specific part of -the HTTP exchange: +What parts of the HTTP exchange should be printed +------------------------------------------------- + +All the other `output options`_ are under the hood just shortcuts for +the more powerful ``--print, -p``. It accepts a string of characters each +of which represents a specific part of the HTTP exchange: ========== ================== Character Stands for @@ -890,11 +948,10 @@ Print request and response headers: $ http --print=Hh PUT httpbin.org/put hello=world ---------------------------------------- Viewing intermediary requests/responses --------------------------------------- -To see *all* the HTTP communication, i.e. the final request/response as +To see all the HTTP communication, i.e. the final request/response as well as any possible intermediary requests/responses, use the ``--all`` option. The intermediary HTTP communication include followed redirects (with ``--follow``), the first unauthorized request when HTTP digest @@ -918,7 +975,6 @@ arguments as ``--print, -p`` but applies to the intermediary requests only. $ http -A digest -a foo:bar --all -p Hh -P H httpbin.org/digest-auth/auth/foo/bar -------------------------- Conditional body download ------------------------- @@ -938,19 +994,17 @@ status code after an update: Since we are only printing the HTTP headers here, the connection to the server is closed as soon as all the response headers have been received. Therefore, bandwidth and time isn't wasted downloading the body -which you don't care about. +which you don't care about. The response headers are downloaded always, +even if they are not part of the output -The response headers are downloaded always, even if they are not part of -the output - -================ Redirected Input ================ -**A universal method for passing request data is through redirected** ``stdin`` -(standard input). Such data is buffered and then with no further processing -used as the request body. There are multiple useful ways to use piping: +The universal method for passing request data is through redirected ``stdin`` +(standard input)—piping. Such data is buffered and then with no further +processing used as the request body. There are multiple useful ways to use +piping: Redirect from a file: @@ -1017,15 +1071,14 @@ To prevent HTTPie from reading ``stdin`` data you can use the ``--ignore-stdin`` option. ----------------------------- Request data from a filename ---------------------------- -**An alternative to redirected** ``stdin`` is specifying a filename (as +An alternative to redirected ``stdin`` is specifying a filename (as ``@/path/to/file``) whose content is used as if it came from ``stdin``. -It has the advantage that **the** ``Content-Type`` -**header is automatically set** to the appropriate value based on the +It has the advantage that the ``Content-Type`` +header is automatically set to the appropriate value based on the filename extension. For example, the following request sends the verbatim contents of that XML file with ``Content-Type: application/xml``: @@ -1034,7 +1087,6 @@ verbatim contents of that XML file with ``Content-Type: application/xml``: $ http PUT httpbin.org/put @/data/file.xml -=============== Terminal output =============== @@ -1042,7 +1094,6 @@ HTTPie does several things by default in order to make its terminal output easy to read. ---------------------- Colors and formatting --------------------- @@ -1068,7 +1119,6 @@ One of these options can be used to control output processing: Default for redirected output. ==================== ======================================================== ------------ Binary data ----------- @@ -1097,12 +1147,11 @@ You will nearly instantly see something like this: +-----------------------------------------+ -================= Redirected output ================= -HTTPie uses **different defaults** for redirected output than for -`terminal output`_: +HTTPie uses a different set of defaults for redirected output than for +`terminal output`_. The differences being: * Formatting and colors aren't applied (unless ``--pretty`` is specified). * Only the response body is printed (unless one of the `output options`_ is set). @@ -1148,7 +1197,6 @@ by adding the following to your ``~/.bash_profile``: } -============= Download mode ============= @@ -1173,11 +1221,18 @@ is being saved to a file. Done. 251.30 kB in 2.73862s (91.76 kB/s) +Downloaded file name +-------------------- + If not provided via ``--output, -o``, the output filename will be determined from ``Content-Disposition`` (if available), or from the URL and ``Content-Type``. If the guessed filename already exists, HTTPie adds a unique suffix to it. + +Piping while downloading +------------------------ + You can also redirect the response body to another program while the response headers and progress are still shown in the terminal: @@ -1186,6 +1241,10 @@ headers and progress are still shown in the terminal: $ http -d https://github.com/jkbrzt/httpie/archive/master.tar.gz | tar zxf - + +Resuming downloads +------------------ + If ``--output, -o`` is specified, you can resume a partial download using the ``--continue, -c`` option. This only works with servers that support ``Range`` requests and ``206 Partial Content`` responses. If the server doesn't @@ -1195,7 +1254,8 @@ support that, the whole file will simply be downloaded: $ http -dco file.zip example.org/file -Other notes: +Other notes +----------- * The ``--download`` option only changes how the response body is treated. * You can still set custom headers, use sessions, ``--verbose, -v``, etc. @@ -1205,27 +1265,32 @@ Other notes: * ``Accept-Encoding`` cannot be set with ``--download``. -================== Streamed responses ================== -Responses are downloaded and printed in chunks, which allows for streaming -and large file downloads without using too much RAM. However, when +Responses are downloaded and printed in chunks which allows for streaming +and large file downloads without using too much memory. However, when `colors and formatting`_ is applied, the whole response is buffered and only then processed at once. +Disabling buffering +------------------- + You can use the ``--stream, -S`` flag to make two things happen: -1. The output is flushed in **much smaller chunks** without any buffering, +1. The output is flushed in much smaller chunks without any buffering, which makes HTTPie behave kind of like ``tail -f`` for URLs. 2. Streaming becomes enabled even when the output is prettified: It will be - applied to **each line** of the response and flushed immediately. This makes + applied to each line of the response and flushed immediately. This makes it possible to have a nice output for long-lived requests, such as one to the Twitter streaming API. +Examples use cases +------------------ + Prettified streamed response: .. code-block:: bash @@ -1242,28 +1307,50 @@ Streamed output by small chunks alá ``tail -f``: $ http --stream -f -a YOUR-TWITTER-NAME https://stream.twitter.com/1/statuses/filter.json track=Apple \ | while read tweet; do echo "$tweet" | http POST example.org/tweets ; done -======== Sessions ======== -By default, every request is completely independent of any previous ones. -HTTPie also supports persistent sessions, where custom headers (except for the -ones starting with ``Content-`` or ``If-``), authorization, and cookies +By default, every request HTTPie makes is completely independent of any +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 (manually specified or sent by the server) persist between requests to the same host. --------------- + +.. code-block:: bash + + # Create a new session + $ http --session=/tmp/session.json example.org API-Token:123 + + # Re-use an existing session — API-Token will be set: + $ 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. + Named sessions -------------- -Create a new session named ``user1`` for ``example.org``: + +You can create one or more named session per host. For example, this is how +you can create a new session named ``user1`` for ``example.org``: .. code-block:: bash $ http --session=user1 -a user1:password example.org X-Foo:Bar -Now you can refer to the session by its name, and the previously used -authorization and HTTP headers will automatically be set: +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 +will automatically be set: .. code-block:: bash @@ -1275,15 +1362,11 @@ To create or reuse a different session, simple specify a different name: $ http --session=user2 -a user2:password example.org X-Bar:Foo -To use a session without updating it from the request/response exchange -once it is created, specify the session name via -``--session-read-only=SESSION_NAME`` instead. - Named sessions' data is stored in JSON files in the directory ``~/.httpie/sessions//.json`` (``%APPDATA%\httpie\sessions\\.json`` on Windows). ------------------- + Anonymous sessions ------------------ @@ -1298,16 +1381,14 @@ allows for sessions to be re-used across multiple hosts: $ http --session-read-only=/tmp/session.json example.org -**Warning:** All session data, including credentials, cookie data, -and custom headers are stored in plain text. - -Note that session files can also be created and edited manually in a text -editor; they are plain JSON. +Readonly session +---------------- -See also `Config`_. +To use an existing session file without updating it from the request/response +exchange once it is created, specify the session name via +``--session-read-only=SESSION_NAME_OR_PATH`` instead. -====== Config ====== @@ -1315,7 +1396,6 @@ HTTPie uses a simple JSON config file. --------------------- Config file location -------------------- @@ -1325,7 +1405,6 @@ The default location of the configuration file is ``~/.httpie/config.json`` location can be changed by setting the ``HTTPIE_CONFIG_DIR`` environment variable. To view the exact location run ``http --debug``. --------------------- Configurable options -------------------- @@ -1354,7 +1433,6 @@ HTTPie automatically stores some of its metadata here. Please do not change. ---------------------------------------- Un-setting previously specified options --------------------------------------- @@ -1364,7 +1442,6 @@ on the command line (e.g., ``--no-style`` or ``--no-session``). -========= Scripting ========= @@ -1397,11 +1474,9 @@ Also, the ``--timeout`` option allows to overwrite the default 30s timeout: fi -==== Meta ==== ----------------- Interface design ---------------- @@ -1448,7 +1523,6 @@ HTTPie reaches its final version ``1.0``. All changes are recorded in the ------------- User support ------------ @@ -1465,20 +1539,24 @@ Please use the following support channels: * You can also tweet directly to `@jkbrzt`_. ----------------- Related projects ---------------- Dependencies ~~~~~~~~~~~~ +Under the hood, HTTPie uses these two amazing libraries: + * `Requests `_ — Python HTTP library for humans * `Pygments `_ — Python syntax highlighter -Friends -~~~~~~~ + +HTTPie friends +~~~~~~~~~~~~~~ + +HTTPie plays exceptionally well with the following tools: * `jq `_ — CLI JSON processor that @@ -1488,28 +1566,24 @@ Friends and command syntax highlighting ----------- -Contribute ----------- +Contributing +------------ -See `CONTRIBUTING `_. +See `CONTRIBUTING.rst `_. ----------- Change log ---------- See `CHANGELOG `_. -------- Artwork ------- See `claudiatd/httpie-artwork`_ -------- Licence ------- @@ -1517,7 +1591,6 @@ BSD-3-Clause: `LICENSE `_. -------- Authors ------- From 64d636356581ff36eaa33948b6e04df818b38cf9 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 7 Dec 2016 05:59:27 +0100 Subject: [PATCH 0294/1182] Docs --- README.rst | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 138c9da119..7b386987b1 100644 --- a/README.rst +++ b/README.rst @@ -278,13 +278,6 @@ this command: GET /?search=HTTPie+logo&tbm=isch HTTP/1.1 -You can use the ``--default-scheme `` option to create -shortcuts for other protocols than HTTP: - -.. code-block:: bash - - $ alias https='http --default-scheme=https' - URL shortcuts for ``localhost`` @@ -327,6 +320,16 @@ If the port is omitted, then port 80 is assumed. Host: localhost +Custom default scheme +--------------------- + +You can use the ``--default-scheme `` option to create +shortcuts for other protocols than HTTP: + +.. code-block:: bash + + $ alias https='http --default-scheme=https' + Request items ============= From b9b033ed0ce41bb294e54d00e2de37751d2e574b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 7 Dec 2016 06:00:51 +0100 Subject: [PATCH 0295/1182] Docs --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 7b386987b1..b8eb6db825 100644 --- a/README.rst +++ b/README.rst @@ -446,7 +446,7 @@ both of which can be overwritten: ================ ======================================= -Enforced JSON +Explicit JSON ------------- You can use ``--json, -j`` to explicitly set ``Accept`` From 6de2d6c2cb9c36c4db81f7867e5705caafac0f5e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 7 Dec 2016 06:20:01 +0100 Subject: [PATCH 0296/1182] Docs --- README.rst | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index b8eb6db825..bff1c4712b 100644 --- a/README.rst +++ b/README.rst @@ -1448,17 +1448,12 @@ on the command line (e.g., ``--no-style`` or ``--no-session``). Scripting ========= -When using HTTPie from **shell scripts**, it can be handy to set the +When using HTTPie from shell scripts, it can be handy to set the ``--check-status`` flag. It instructs HTTPie to exit with an error if the HTTP status is one of ``3xx``, ``4xx``, or ``5xx``. The exit status will be ``3`` (unless ``--follow`` is set), ``4``, or ``5``, respectively. -The ``--ignore-stdin`` option prevents HTTPie from reading data from ``stdin``, -which is usually not desirable during non-interactive invocations. - -Also, the ``--timeout`` option allows to overwrite the default 30s timeout: - .. code-block:: bash #!/bin/bash @@ -1477,6 +1472,26 @@ Also, the ``--timeout`` option allows to overwrite the default 30s timeout: fi +Best practices +-------------- + +The default behaviour of automatically reading ``stdin`` is typically not +desirable during non-interactive invocations. You most likely want +use the ``--ignore-stdin`` option to disable it. + +It is a common gotcha that without this option HTTPie seemingly hangs. +What happens is that when HTTPie is invoked for example from a cron job, +``stdin`` is not connected to a terminal. +Therefore, rules for `redirected input`_ apply, i.e., HTTPie starts to read it +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 +something that suits you. + + + Meta ==== From da59381b0b3a918aafea9c3a04c64734604871c0 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 7 Dec 2016 18:54:53 +0100 Subject: [PATCH 0297/1182] Fix PyPi link --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index bff1c4712b..d243493b36 100644 --- a/README.rst +++ b/README.rst @@ -688,7 +688,7 @@ Auth plugins ------------ Additional authentication mechanism can be installed as plugins. -They can be found on the `Python Package Index `_. +They can be found on the `Python Package Index `_. Here's a few picks: * `httpie-oauth `_: OAuth From 3a6fd074a1f873989284b94eb7b402d1c86532be Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 8 Dec 2016 04:42:17 +0100 Subject: [PATCH 0298/1182] Added `ExitStatus.PLUGIN_ERROR` (7) --- CHANGELOG.rst | 7 ++++--- httpie/__init__.py | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c919a4b72a..f80a03fb82 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,8 +6,8 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. -`1.0.0-dev`_ (Unreleased) -------------------------- +`0.9.7`_ (2016-12-08) +--------------------- * Extended auth plugin API. * Added support for ``curses``-less Python installations. @@ -317,4 +317,5 @@ This project adheres to `Semantic Versioning `_. .. _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 -.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.6...master +.. _0.9.7: https://github.com/jkbrzt/httpie/compare/0.9.6...0.9.7 +.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.7...master diff --git a/httpie/__init__.py b/httpie/__init__.py index 05b4cc0e19..bc78c7e798 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '1.0.0-dev' +__version__ = '0.9.7' __licence__ = 'BSD' @@ -11,6 +11,7 @@ class ExitStatus: """Exit status code constants.""" OK = 0 ERROR = 1 + PLUGIN_ERROR = 7 # 128+2 SIGINT ERROR_CTRL_C = 130 From 9ae86f3b4fadb6203b34b8b672e03b58c08437b3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 8 Dec 2016 04:47:32 +0100 Subject: [PATCH 0299/1182] 0.9.7 --- CHANGELOG.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f80a03fb82..ccf27d26f8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,10 +6,14 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. +`1.0.0-dev`_ (unreleased) +------------------------- + `0.9.7`_ (2016-12-08) --------------------- * Extended auth plugin API. +* Added exit status code ``7`` for plugin errors. * Added support for ``curses``-less Python installations. * Fixed ``REQUEST_ITEM`` arg incorrectly being reported as required. * Improved ``CTRL-C`` interrupt handling. From cc9083f541dc1df19294daf3351c5cfb2c67b347 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 8 Dec 2016 04:58:49 +0100 Subject: [PATCH 0300/1182] Keep the latest submitted Homebrew formula in extras/ for testing --- extras/httpie.rb | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 extras/httpie.rb diff --git a/extras/httpie.rb b/extras/httpie.rb new file mode 100644 index 0000000000..820e8d31f0 --- /dev/null +++ b/extras/httpie.rb @@ -0,0 +1,47 @@ +# The latest Homebrew formula as submitted to Homebrew/homebrew-core. +# Only useful for testing until it gets accepted by homebrew maintainers. +# +# https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb +# +class Httpie < Formula + desc "User-friendly cURL replacement (command-line HTTP client)" + homepage "https://httpie.org/" + + url "https://pypi.python.org/packages/10/cf/da63860ef92f9c90a5bd684d5f162067b26ef113b1c4afb9979c2f5c5a7a/httpie-0.9.7.tar.gz" + sha256 "6427c198c80b04e84963890261f29f1e3452b2b4b81e87a403bf22996754e6ec" + + head "https://github.com/jkbrzt/httpie.git" + + depends_on :python3 + + resource "requests" do + url "https://pypi.python.org/packages/d9/03/155b3e67fe35fe5b6f4227a8d9e96a14fda828b18199800d161bcefc1359/requests-2.12.3.tar.gz" + sha256 "de5d266953875e9647e37ef7bfe6ef1a46ff8ddfe61b5b3652edf7ea717ee2b2" + end + + resource "pygments" do + url "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz" + sha256 "88e4c8a91b2af5962bfa5ea2447ec6dd357018e86e94c7d14bd8cacbc5b55d81" + end + + def install + pyver = Language::Python.major_minor_version "python3" + ENV.prepend_create_path "PYTHONPATH", libexec/"vendor/lib/python#{pyver}/site-packages" + %w[pygments requests].each do |r| + resource(r).stage do + system "python3", *Language::Python.setup_install_args(libexec/"vendor") + end + end + + ENV.prepend_create_path "PYTHONPATH", libexec/"lib/python#{pyver}/site-packages" + system "python3", *Language::Python.setup_install_args(libexec) + + bin.install Dir["#{libexec}/bin/*"] + bin.env_script_all_files(libexec/"bin", :PYTHONPATH => ENV["PYTHONPATH"]) + end + + test do + raw_url = "https://raw.githubusercontent.com/Homebrew/homebrew-core/master/Formula/httpie.rb" + assert_match "PYTHONPATH", shell_output("#{bin}/http --ignore-stdin #{raw_url}") + end +end From fb3a26586aeda423c3eac76572a5f0793657155c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 8 Dec 2016 05:16:22 +0100 Subject: [PATCH 0301/1182] Fix --auth-type help --- README.rst | 11 ++++++----- httpie/cli.py | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index d243493b36..d15b7b24e4 100644 --- a/README.rst +++ b/README.rst @@ -691,14 +691,15 @@ Additional authentication mechanism can be installed as plugins. They can be found on the `Python Package Index `_. Here's a few picks: -* `httpie-oauth `_: OAuth -* `httpie-hmac-auth `_: HMAC -* `httpie-ntlm `_: NTLM (NT LAN Manager) -* `httpie-negotiate `_: SPNEGO (GSS Negotiate) -* `requests-hawk `_: Hawk * `httpie-api-auth `_: ApiAuth +* `httpie-aws-auth `_: ApiAuth * `httpie-edgegrid `_: EdgeGrid +* `httpie-hmac-auth `_: HMAC * `httpie-jwt-auth `_: JWTAuth (JSON Web Tokens) +* `httpie-negotiate `_: SPNEGO (GSS Negotiate) +* `httpie-ntlm `_: NTLM (NT LAN Manager) +* `httpie-oauth `_: OAuth +* `requests-hawk `_: Hawk diff --git a/httpie/cli.py b/httpie/cli.py index 2194321baf..94f09a8cad 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -435,7 +435,7 @@ def __contains__(self, item): return item in plugin_manager.get_auth_plugin_mapping() def __iter__(self): - return iter(plugin_manager.get_auth_plugins()) + return iter(sorted(plugin_manager.get_auth_plugin_mapping().keys())) _auth_plugins = plugin_manager.get_auth_plugins() From 3a3aecca45323fbea6cb8595f7732f9f957ec78f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 8 Dec 2016 05:22:20 +0100 Subject: [PATCH 0302/1182] 0.9.8 --- CHANGELOG.rst | 6 +++--- httpie/__init__.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ccf27d26f8..8efb7efd67 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,7 +9,7 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (unreleased) ------------------------- -`0.9.7`_ (2016-12-08) +`0.9.8`_ (2016-12-08) --------------------- * Extended auth plugin API. @@ -321,5 +321,5 @@ This project adheres to `Semantic Versioning `_. .. _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.7: https://github.com/jkbrzt/httpie/compare/0.9.6...0.9.7 -.. _1.0.0-dev: https://github.com/jkbrzt/httpie/compare/0.9.7...master +.. _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 diff --git a/httpie/__init__.py b/httpie/__init__.py index bc78c7e798..da7f1d8568 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '0.9.7' +__version__ = '0.9.8' __licence__ = 'BSD' From 761cdbf8bea4578c75a5be7d31a0c060585f79a2 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 8 Dec 2016 05:25:50 +0100 Subject: [PATCH 0303/1182] Update Homebrew formula --- extras/httpie.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extras/httpie.rb b/extras/httpie.rb index 820e8d31f0..d89defa96e 100644 --- a/extras/httpie.rb +++ b/extras/httpie.rb @@ -7,8 +7,8 @@ class Httpie < Formula desc "User-friendly cURL replacement (command-line HTTP client)" homepage "https://httpie.org/" - url "https://pypi.python.org/packages/10/cf/da63860ef92f9c90a5bd684d5f162067b26ef113b1c4afb9979c2f5c5a7a/httpie-0.9.7.tar.gz" - sha256 "6427c198c80b04e84963890261f29f1e3452b2b4b81e87a403bf22996754e6ec" + url "https://pypi.python.org/packages/85/95/7ccea3ae7fd1185e21629f6d14fa9c896d6250bb15fb492efa91edc741a2/httpie-0.9.8.tar.gz" + sha256 "515870b15231530f56fe2164190581748e8799b66ef0fe36ec9da3396f0df6e1" head "https://github.com/jkbrzt/httpie.git" From 9d93b07a9db2e6e95bc46f7e2f80cfdd86d054d7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 8 Dec 2016 05:38:25 +0100 Subject: [PATCH 0304/1182] Redme --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index d15b7b24e4..5d87533084 100644 --- a/README.rst +++ b/README.rst @@ -692,7 +692,7 @@ They can be found on the `Python Package Index `_: ApiAuth -* `httpie-aws-auth `_: ApiAuth +* `httpie-aws-auth `_: AWS / Amazon S3 * `httpie-edgegrid `_: EdgeGrid * `httpie-hmac-auth `_: HMAC * `httpie-jwt-auth `_: JWTAuth (JSON Web Tokens) From f133dbf22cbe1e8fdbeb37ec977d405c5d96c7f0 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 8 Dec 2016 21:48:11 +0100 Subject: [PATCH 0305/1182] Update README with new plugin repos location --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 5d87533084..30403a90a0 100644 --- a/README.rst +++ b/README.rst @@ -697,8 +697,8 @@ Here's a few picks: * `httpie-hmac-auth `_: HMAC * `httpie-jwt-auth `_: JWTAuth (JSON Web Tokens) * `httpie-negotiate `_: SPNEGO (GSS Negotiate) -* `httpie-ntlm `_: NTLM (NT LAN Manager) -* `httpie-oauth `_: OAuth +* `httpie-ntlm `_: NTLM (NT LAN Manager) +* `httpie-oauth `_: OAuth * `requests-hawk `_: Hawk From fe1d0b0a1e21be4a7c350122e81f6d633ac172ae Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 8 Dec 2016 21:48:18 +0100 Subject: [PATCH 0306/1182] Doc --- extras/httpie.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/extras/httpie.rb b/extras/httpie.rb index d89defa96e..e6366b186d 100644 --- a/extras/httpie.rb +++ b/extras/httpie.rb @@ -1,5 +1,6 @@ # The latest Homebrew formula as submitted to Homebrew/homebrew-core. # Only useful for testing until it gets accepted by homebrew maintainers. +# (It will need to be updated from the repo version before next release.) # # https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb # From d0fc10cf1a1767656a71c8ce75ce3c3b93898c9e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 8 Dec 2016 21:48:38 +0100 Subject: [PATCH 0307/1182] AWS / Amazon S3 auth plugin link --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 30403a90a0..46c85248a7 100644 --- a/README.rst +++ b/README.rst @@ -692,7 +692,7 @@ They can be found on the `Python Package Index `_: ApiAuth -* `httpie-aws-auth `_: AWS / Amazon S3 +* `httpie-aws-auth `_: AWS / Amazon S3 * `httpie-edgegrid `_: EdgeGrid * `httpie-hmac-auth `_: HMAC * `httpie-jwt-auth `_: JWTAuth (JSON Web Tokens) From 0af6ae1be444588bbc4747124e073423151178a0 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 9 Dec 2016 00:26:55 +0100 Subject: [PATCH 0308/1182] Fix PyPi README rendering Close #540 --- README.rst | 3 --- httpie/__init__.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 46c85248a7..df51e1e96d 100644 --- a/README.rst +++ b/README.rst @@ -27,9 +27,6 @@ generally interacting with HTTP servers. .. section-numbering:: -.. raw:: pdf - - PageBreak oneColumn Main features diff --git a/httpie/__init__.py b/httpie/__init__.py index da7f1d8568..18a7fd91ba 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ __author__ = 'Jakub Roztocil' -__version__ = '0.9.8' +__version__ = '1.0.0-dev' __licence__ = 'BSD' From 64a41c26019e566d32ed3739558d0f6dfc026d46 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 10 Dec 2016 17:46:51 +0100 Subject: [PATCH 0309/1182] README --- README.rst | 59 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/README.rst b/README.rst index df51e1e96d..00521ccfa0 100644 --- a/README.rst +++ b/README.rst @@ -74,16 +74,20 @@ 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, CentOS, RHEL, … $ yum install httpie +.. code-block:: bash + # Arch Linux $ pacman -S httpie @@ -107,29 +111,50 @@ and always provides the latest version) is to use `pip`_: ``easy_install httpie`` as a fallback.) -Development version -------------------- +Python version +-------------- + +Although Python 2.6 and 2.7 are supported as well, it is recommended to install +HTTPie against the latest Python 3.x whenever possible. That will ensure that +some of the newer HTTP features, such as `SNI (Server Name Indication)`_, +work out of the box. +Python 3 is the default for Homebrew installations starting with version 0.9.4. +To see which version HTTPie uses, run ``http --debug``. + + +Unstable version +---------------- -The latest development version can be installed directly from GitHub: +You can also instead of the latest 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| |windows_build| + + +On macOS you can install it with Homebrew: .. code-block:: bash - # Mac OS X via Homebrew $ brew install httpie --HEAD - # Universal + +Otherwise with ``pip``: + +.. code-block:: bash + $ pip install --upgrade https://github.com/jkbrzt/httpie/archive/master.tar.gz -Python version --------------- +Verify that now we have the +`current development version identifier `_ +with the ``-dev`` suffix, for example: -Although Python 2.6 and 2.7 are supported as well, it is recommended to install -HTTPie against the latest Python 3.x whenever possible. That will ensure that -some of the newer HTTP features, such as `SNI (Server Name Indication)`_, -work out of the box. -Python 3 is the default for Homebrew installations starting with version 0.9.4. -To see which version HTTPie uses, run ``http --debug``. +.. code-block:: bash + + $ http --version + 1.0.0-dev Usage @@ -258,7 +283,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, From c9296a9a458623aff863c2e045780fe74ea1b590 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 17 Dec 2016 03:06:48 +0100 Subject: [PATCH 0310/1182] Added link to `httpcat` --- README.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.rst b/README.rst index 00521ccfa0..c0a9adddfb 100644 --- a/README.rst +++ b/README.rst @@ -1607,6 +1607,13 @@ HTTPie plays exceptionally well with the following tools: and command syntax highlighting +Related +~~~~~~~ + +* `httpcat `_ — a lower-level sister utility + of HTTPie for constructing raw HTTP requests on the command line. + + Contributing ------------ From 97804802c0b4b79b673da40085c29c3ab074f363 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 17 Dec 2016 03:10:52 +0100 Subject: [PATCH 0311/1182] Alternatives --- README.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index c0a9adddfb..aeccae5cca 100644 --- a/README.rst +++ b/README.rst @@ -1607,11 +1607,13 @@ HTTPie plays exceptionally well with the following tools: and command syntax highlighting -Related -~~~~~~~ +Alternatives +~~~~~~~~~~~~ * `httpcat `_ — a lower-level sister utility of HTTPie for constructing raw HTTP requests on the command line. +* `curl `_ — a "Swiss knife" command line tool and + an exceptional library for transferring data with URLs. Contributing From 66a647506460f8ba50e0e4341f1fbb0a6b0bae1b Mon Sep 17 00:00:00 2001 From: Eugene Duboviy Date: Sun, 8 Jan 2017 16:12:31 +0200 Subject: [PATCH 0312/1182] Update tox.ini --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 57cc5d9dd8..aaa231f6ea 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ [tox] -envlist = py26, py27, py35, pypy, codestyle +envlist = py26, py27, py35, py36, pypy, codestyle [testenv] From 0046ed73c6cda1cbb0b8de5098e3ac0710ba8298 Mon Sep 17 00:00:00 2001 From: Eugene Duboviy Date: Sun, 8 Jan 2017 16:18:19 +0200 Subject: [PATCH 0313/1182] Update .travis.yml --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f0a6ca02ed..c00a50e651 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ os: env: global: - - NEWEST_PYTHON=3.5 + - NEWEST_PYTHON=3.6 python: - 2.6 @@ -15,6 +15,7 @@ python: - pypy - 3.4 - 3.5 + - 3.6 # Currently fails because of a Flask issue # - pypy3 @@ -42,12 +43,12 @@ matrix: - os: osx language: generic env: - - TOXENV=py35 + - TOXENV=py36 - BREW_INSTALL=python3 # Python Codestyle - os: linux - python: 3.5 + python: 3.6 env: CODESTYLE=true install: From 98003f545dbf3f1256aad0e6385a9cdb87d1c80b Mon Sep 17 00:00:00 2001 From: Eugene Duboviy Date: Sun, 8 Jan 2017 16:19:26 +0200 Subject: [PATCH 0314/1182] Update appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index d5be13447e..ca1d6d70a2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,7 +6,7 @@ environment: - PYTHON: "C:/Python27" # Python 3.4 has outdated pip # - PYTHON: "C:/Python34" - - PYTHON: "C:/Python35" + - PYTHON: "C:/Python36" init: - "ECHO %PYTHON%" From ee6cdf4ab3061815faa2d3e80b8da42d5a1569b9 Mon Sep 17 00:00:00 2001 From: Eugene Duboviy Date: Sun, 8 Jan 2017 16:20:53 +0200 Subject: [PATCH 0315/1182] Update setup.py --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 0a15862a55..67caa9a6df 100644 --- a/setup.py +++ b/setup.py @@ -101,6 +101,8 @@ def long_description(): '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', From 519654e21b3008fe0da588eb59e9751edca17d8a Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Sun, 22 Jan 2017 20:58:58 +0000 Subject: [PATCH 0316/1182] Gitter Badge: flat-square style To match the other badges --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index aeccae5cca..556fb50100 100644 --- a/README.rst +++ b/README.rst @@ -1672,7 +1672,7 @@ have contributed. :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 From 9261167a1f86c617e89bd559e3bb83f28cb20869 Mon Sep 17 00:00:00 2001 From: Robert Benjamin Date: Thu, 2 Feb 2017 11:45:58 -0800 Subject: [PATCH 0317/1182] Fix typo in the docs --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index aeccae5cca..7ba562102d 100644 --- a/README.rst +++ b/README.rst @@ -1374,7 +1374,7 @@ 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 +From now on, you can refer to the session by its name. When you choose to use the session again, any the previously used authorization and HTTP headers will automatically be set: From 244ad15c922403b5ed3f8f9d6167c8bc50900e1f Mon Sep 17 00:00:00 2001 From: Roberto Desideri Date: Thu, 9 Feb 2017 15:25:07 +0100 Subject: [PATCH 0318/1182] Update pip official website url --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index b8650a67d2..ea35b36c4a 100644 --- a/README.rst +++ b/README.rst @@ -1648,7 +1648,7 @@ Authors 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 From 64af72eb887cee5217c766c140d189c570ed51a8 Mon Sep 17 00:00:00 2001 From: Michael Floering Date: Thu, 9 Feb 2017 18:51:23 -0600 Subject: [PATCH 0319/1182] Turn --verify=False/True to --verify=no/yes One way to address #559 -- https://github.com/jkbrzt/httpie/issues/559 -- instead of warning or throwing an error, just accept "True" and "False" as synonyms of yes/no (Updated to reflect feedback given at https://github.com/jkbrzt/httpie/pull/560 ) --- httpie/client.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 894a40d70b..6299dcf678 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -159,8 +159,10 @@ 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, From 7321b9fa4eca4bf3db68c78b16b206062aebeabb Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 17 Feb 2017 00:56:07 +0100 Subject: [PATCH 0320/1182] Add --verify true/false tests and CHANGELOG --- CHANGELOG.rst | 2 ++ httpie/__init__.py | 2 +- httpie/cli.py | 8 ++++---- tests/test_ssl.py | 5 +++++ 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8efb7efd67..37f7e5bde9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,8 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (unreleased) ------------------------- +* ``--verify`` now accepts ``true``/``false`` in addition to ``yes``/``no`` + and the boolean value is case-insensitive. `0.9.8`_ (2016-12-08) --------------------- diff --git a/httpie/__init__.py b/httpie/__init__.py index 18a7fd91ba..abed9a91c1 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -2,8 +2,8 @@ HTTPie - a CLI, cURL-like tool for humans. """ -__author__ = 'Jakub Roztocil' __version__ = '1.0.0-dev' +__author__ = 'Jakub Roztocil' __licence__ = 'BSD' diff --git a/httpie/cli.py b/httpie/cli.py index 94f09a8cad..7d13972fea 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -544,10 +544,10 @@ def __iter__(self): '--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( diff --git a/tests/test_ssl.py b/tests/test_ssl.py index b226186e4c..50f34d4ca5 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -73,6 +73,11 @@ def test_verify_no_OK(self, httpbin_secure): 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) From f74670fac1ea2d8051f19b48383991fcbbe21a94 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 1 Mar 2017 12:40:26 +0100 Subject: [PATCH 0321/1182] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ea35b36c4a..8b6bcb7e8c 100644 --- a/README.rst +++ b/README.rst @@ -813,7 +813,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 From b0fde07cfd8676a75292188dd8bedab7de74e6f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davorin=20S=CC=8Cego?= Date: Mon, 6 Mar 2017 01:05:50 +0100 Subject: [PATCH 0322/1182] Follow terminal ANSI color styles Removes the default solarized color scheme and custom http lexer class. --- httpie/cli.py | 6 +- httpie/output/formatters/colors.py | 146 ++--------------------------- 2 files changed, 8 insertions(+), 144 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 7d13972fea..1a8fa762d8 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -20,7 +20,7 @@ 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 from httpie.plugins import plugin_manager from httpie.plugins.builtin import BuiltinAuthPlugin from httpie.sessions import DEFAULT_SESSIONS_DIR @@ -204,10 +204,9 @@ def _split_lines(self, text, width): '--style', '-s', dest='style', metavar='STYLE', - default=DEFAULT_STYLE, choices=AVAILABLE_STYLES, help=""" - Output coloring style (default is "{default}"). One of: + Output coloring style. One of: {available} @@ -216,7 +215,6 @@ def _split_lines(self, text, width): (e.g., via `export TERM=xterm-256color' in your ~/.bashrc). """.format( - default=DEFAULT_STYLE, available='\n'.join( '{0}{1}'.format(8 * ' ', line.strip()) for line in wrap(', '.join(sorted(AVAILABLE_STYLES)), 60) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index b01774330c..b251b5c4be 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -10,20 +10,12 @@ from pygments.formatters.terminal256 import Terminal256Formatter from pygments.lexers.special import TextLexer from pygments.util import ClassNotFound +from pygments.lexers.text import HttpLexer -from httpie.compat import is_windows from httpie.plugins import FormatterPlugin AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys()) -AVAILABLE_STYLES.add('solarized') - -if is_windows: - # Colors on Windows via colorama don't look that - # great and fruity seems to give the best result there - DEFAULT_STYLE = 'fruity' -else: - DEFAULT_STYLE = 'solarized' class ColorFormatter(FormatterPlugin): @@ -37,7 +29,7 @@ class ColorFormatter(FormatterPlugin): group_name = 'colors' def __init__(self, env, explicit_json=False, - color_scheme=DEFAULT_STYLE, **kwargs): + color_scheme=None, **kwargs): super(ColorFormatter, self).__init__(**kwargs) if not env.colors: self.enabled = False @@ -46,19 +38,13 @@ def __init__(self, env, explicit_json=False, # --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 + if color_scheme and env.colors == 256: + self.formatter = Terminal256Formatter(style=color_scheme) else: - fmt_class = TerminalFormatter - self.formatter = fmt_class(style=style_class) + self.formatter = TerminalFormatter() def format_headers(self, headers): - return pygments.highlight(headers, HTTPLexer(), self.formatter).strip() + return pygments.highlight(headers, HttpLexer(), self.formatter).strip() def format_body(self, body, mime): lexer = self.get_lexer(mime, body) @@ -119,123 +105,3 @@ def get_lexer(mime, explicit_json=False, body=''): lexer = pygments.lexers.get_lexer_by_name('json') return lexer - - -class HTTPLexer(pygments.lexer.RegexLexer): - """Simplified HTTP lexer for Pygments. - - It only operates on headers and provides a stronger contrast between - their names and values than the original one bundled with Pygments - (:class:`pygments.lexers.text import HttpLexer`), especially when - Solarized color scheme is used. - - """ - name = 'HTTP' - aliases = ['http'] - filenames = ['*.http'] - tokens = { - 'root': [ - # Request-Line - (r'([A-Z]+)( +)([^ ]+)( +)(HTTP)(/)(\d+\.\d+)', - pygments.lexer.bygroups( - pygments.token.Name.Function, - pygments.token.Text, - pygments.token.Name.Namespace, - pygments.token.Text, - pygments.token.Keyword.Reserved, - pygments.token.Operator, - pygments.token.Number - )), - # Response Status-Line - (r'(HTTP)(/)(\d+\.\d+)( +)(\d{3})( +)(.+)', - pygments.lexer.bygroups( - pygments.token.Keyword.Reserved, # 'HTTP' - pygments.token.Operator, # '/' - pygments.token.Number, # Version - pygments.token.Text, - pygments.token.Number, # Status code - pygments.token.Text, - pygments.token.Name.Exception, # Reason - )), - # Header - (r'(.*?)( *)(:)( *)(.+)', pygments.lexer.bygroups( - pygments.token.Name.Attribute, # Name - pygments.token.Text, - pygments.token.Operator, # Colon - pygments.token.Text, - pygments.token.String # Value - )) - ] - } - - -class Solarized256Style(pygments.style.Style): - """ - solarized256 - ------------ - - A Pygments style inspired by Solarized's 256 color mode. - - :copyright: (c) 2011 by Hank Gay, (c) 2012 by John Mastro. - :license: BSD, see LICENSE for more details. - - """ - BASE03 = "#1c1c1c" - BASE02 = "#262626" - BASE01 = "#4e4e4e" - BASE00 = "#585858" - BASE0 = "#808080" - BASE1 = "#8a8a8a" - BASE2 = "#d7d7af" - BASE3 = "#ffffd7" - YELLOW = "#af8700" - ORANGE = "#d75f00" - RED = "#af0000" - MAGENTA = "#af005f" - VIOLET = "#5f5faf" - BLUE = "#0087ff" - CYAN = "#00afaf" - GREEN = "#5f8700" - - background_color = BASE03 - styles = { - pygments.token.Keyword: GREEN, - pygments.token.Keyword.Constant: ORANGE, - pygments.token.Keyword.Declaration: BLUE, - pygments.token.Keyword.Namespace: ORANGE, - pygments.token.Keyword.Reserved: BLUE, - pygments.token.Keyword.Type: RED, - pygments.token.Name.Attribute: BASE1, - pygments.token.Name.Builtin: BLUE, - pygments.token.Name.Builtin.Pseudo: BLUE, - pygments.token.Name.Class: BLUE, - pygments.token.Name.Constant: ORANGE, - pygments.token.Name.Decorator: BLUE, - pygments.token.Name.Entity: ORANGE, - pygments.token.Name.Exception: YELLOW, - pygments.token.Name.Function: BLUE, - pygments.token.Name.Tag: BLUE, - pygments.token.Name.Variable: BLUE, - pygments.token.String: CYAN, - pygments.token.String.Backtick: BASE01, - pygments.token.String.Char: CYAN, - pygments.token.String.Doc: CYAN, - pygments.token.String.Escape: RED, - pygments.token.String.Heredoc: CYAN, - pygments.token.String.Regex: RED, - pygments.token.Number: CYAN, - pygments.token.Operator: BASE1, - pygments.token.Operator.Word: GREEN, - pygments.token.Comment: BASE01, - pygments.token.Comment.Preproc: GREEN, - pygments.token.Comment.Special: GREEN, - pygments.token.Generic.Deleted: CYAN, - pygments.token.Generic.Emph: 'italic', - pygments.token.Generic.Error: RED, - pygments.token.Generic.Heading: ORANGE, - pygments.token.Generic.Inserted: GREEN, - pygments.token.Generic.Strong: 'bold', - pygments.token.Generic.Subheading: ORANGE, - pygments.token.Token: BASE1, - pygments.token.Token.Other: ORANGE, - } From c948f98b051d8d8b0c508510a09ef60547b5658e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 10 Mar 2017 11:27:38 +0100 Subject: [PATCH 0323/1182] Update links --- .travis.yml | 2 +- AUTHORS.rst | 4 +-- CHANGELOG.rst | 56 +++++++++++++++++++-------------------- CONTRIBUTING.rst | 12 ++++----- README.rst | 46 ++++++++++++++++---------------- extras/httpie.rb | 2 +- httpie/cli.py | 2 +- httpie/client.py | 2 +- httpie/downloads.py | 4 +-- httpie/input.py | 2 +- httpie/plugins/base.py | 2 +- httpie/plugins/builtin.py | 2 +- setup.py | 2 +- tests/README.rst | 2 +- tests/test_auth.py | 2 +- tests/test_defaults.py | 4 +-- tests/test_httpie.py | 2 +- tests/test_output.py | 2 +- tests/test_regressions.py | 4 +-- tests/test_sessions.py | 6 ++--- 20 files changed, 80 insertions(+), 80 deletions(-) diff --git a/.travis.yml b/.travis.yml index c00a50e651..9253b7fcc7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -# https://travis-ci.org/jkbrzt/httpie +# https://travis-ci.org/jakubroztocil/httpie sudo: false language: python diff --git a/AUTHORS.rst b/AUTHORS.rst index 542191ffcf..13577d3aba 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -2,13 +2,13 @@ HTTPie authors ============== -* `Jakub Roztocil `_ +* `Jakub Roztocil `_ Patches and ideas ----------------- -`Complete list of contributors on GitHub `_ +`Complete list of contributors on GitHub `_ * `Cláudia T. Delgado `_ (logo) * `Hank Gay `_ diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 37f7e5bde9..4e3a7d7617 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -94,8 +94,8 @@ This project adheres to `Semantic Versioning `_. --------------------- * Added support for Requests transport adapter plugins - (see `httpie-unixsocket `_ - and `httpie-http2 `_) + (see `httpie-unixsocket `_ + and `httpie-http2 `_) `0.9.0`_ (2015-01-31) @@ -299,29 +299,29 @@ This project adheres to `Semantic Versioning `_. * 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 +.. _1.0.0-dev: https://github.com/jakubroztocil/httpie/compare/0.9.8...master diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index ca57350de4..472bddaf42 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -32,7 +32,7 @@ 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 @@ -107,10 +107,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 diff --git a/README.rst b/README.rst index 8b6bcb7e8c..8b81c834d2 100644 --- a/README.rst +++ b/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 @@ -144,11 +144,11 @@ Otherwise with ``pip``: .. code-block:: bash - $ pip install --upgrade https://github.com/jkbrzt/httpie/archive/master.tar.gz + $ pip install --upgrade https://github.com/jakubroztocil/httpie/archive/master.tar.gz Verify that now we have the -`current development version identifier `_ +`current development version identifier `_ with the ``-dev`` suffix, for example: .. code-block:: bash @@ -204,12 +204,12 @@ See the request that is being sent using one of the `output options`_: Use `Github API`_ to post a comment on an -`issue `_ +`issue `_ 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`_: @@ -1057,7 +1057,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: @@ -1234,7 +1234,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 @@ -1264,7 +1264,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 - @@ -1571,13 +1571,13 @@ Please use the following support channels: * `GitHub issues `_ for bug reports and feature requests. -* `Our Gitter chat room `_ +* `Our Gitter chat room `_ to ask questions, discuss features, and for general discussion. * `StackOverflow `_ to ask questions (please make sure to use the `httpie `_ tag). * Tweet directly to `@clihttp `_. -* You can also tweet directly to `@jkbrzt`_. +* You can also tweet directly to `@jakubroztocil`_. Related projects @@ -1610,7 +1610,7 @@ HTTPie plays exceptionally well with the following tools: Alternatives ~~~~~~~~~~~~ -* `httpcat `_ — a lower-level sister utility +* `httpcat `_ — a lower-level sister utility of HTTPie for constructing raw HTTP requests on the command line. * `curl `_ — a "Swiss knife" command line tool and an exceptional library for transferring data with URLs. @@ -1619,13 +1619,13 @@ Alternatives Contributing ------------ -See `CONTRIBUTING.rst `_. +See `CONTRIBUTING.rst `_. Change log ---------- -See `CHANGELOG `_. +See `CHANGELOG `_. Artwork @@ -1637,22 +1637,22 @@ See `claudiatd/httpie-artwork`_ Licence ------- -BSD-3-Clause: `LICENSE `_. +BSD-3-Clause: `LICENSE `_. Authors ------- -`Jakub Roztocil`_ (`@jkbrzt`_) created HTTPie and `these fine people`_ +`Jakub Roztocil`_ (`@jakubroztocil`_) created HTTPie and `these fine people`_ have contributed. .. _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 +.. _these fine people: https://github.com/jakubroztocil/httpie/contributors .. _Jakub Roztocil: http://roztocil.co -.. _@jkbrzt: https://twitter.com/jkbrzt +.. _@jakubroztocil: https://twitter.com/jakubroztocil .. _claudiatd/httpie-artwork: https://github.com/claudiatd/httpie-artwork @@ -1660,19 +1660,19 @@ 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://img.shields.io/gitter/room/jkbrzt/httpie.svg?style=flat-square - :target: https://gitter.im/jkbrzt/httpie +.. |gitter| image:: https://img.shields.io/gitter/room/jakubroztocil/httpie.svg?style=flat-square + :target: https://gitter.im/jakubroztocil/httpie :alt: Chat on Gitter diff --git a/extras/httpie.rb b/extras/httpie.rb index e6366b186d..bc323fa13e 100644 --- a/extras/httpie.rb +++ b/extras/httpie.rb @@ -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 diff --git a/httpie/cli.py b/httpie/cli.py index 7d13972fea..50a136c43c 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -54,7 +54,7 @@ def _split_lines(self, text, width): Suggestions and bug reports are greatly appreciated: - https://github.com/jkbrzt/httpie/issues + https://github.com/jakubroztocil/httpie/issues """), ) diff --git a/httpie/client.py b/httpie/client.py index 6299dcf678..0c7566aa93 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -97,7 +97,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 diff --git a/httpie/downloads.py b/httpie/downloads.py index 5c19beae49..8b97f4e127 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -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 @@ def start(self, response): assert not self.status.time_started # FIXME: some servers still might sent Content-Encoding: gzip - # + # try: total_size = int(response.headers['Content-Length']) except (KeyError, ValueError, TypeError): diff --git a/httpie/input.py b/httpie/input.py index 97f83edc48..7960cd94cd 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -14,7 +14,7 @@ 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 diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index 30d88595af..bbf53663dc 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -15,7 +15,7 @@ class AuthPlugin(BasePlugin): """ Base auth plugin class. - See for an example auth plugin. + See for an example auth plugin. See also `test_auth_plugins.py` diff --git a/httpie/plugins/builtin.py b/httpie/plugins/builtin.py index 6b9640d1e9..eb7b9fc0ff 100644 --- a/httpie/plugins/builtin.py +++ b/httpie/plugins/builtin.py @@ -17,7 +17,7 @@ def __call__(self, r): """ 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( diff --git a/setup.py b/setup.py index 67caa9a6df..ec071a2d46 100644 --- a/setup.py +++ b/setup.py @@ -76,7 +76,7 @@ def long_description(): 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__, diff --git a/tests/README.rst b/tests/README.rst index 0f7cdc00f8..6fbf97e65f 100644 --- a/tests/README.rst +++ b/tests/README.rst @@ -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 diff --git a/tests/test_auth.py b/tests/test_auth.py index a5fd5da34b..2beb518d7b 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -55,7 +55,7 @@ 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()) diff --git a/tests/test_defaults.py b/tests/test_defaults.py index 49d5749e66..75e8ed1e6d 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -43,7 +43,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 +74,7 @@ def test_POST_explicit_JSON_auto_JSON_accept(self, httpbin): 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): diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 5cef1158c1..36a856f76b 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -18,7 +18,7 @@ def test_debug(): 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 'https://github.com/jakubroztocil/httpie/issues' in r def test_version(): diff --git a/tests/test_output.py b/tests/test_output.py index d4ac560cb4..b9907e72b1 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -33,7 +33,7 @@ def test_verbose(self, httpbin): 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 diff --git a/tests/test_regressions.py b/tests/test_regressions.py index 3ad441307f..b22b140040 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -7,7 +7,7 @@ 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') diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 4b9874e294..893069b714 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -143,7 +143,7 @@ def test_session_by_path(self, httpbin): @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) @@ -164,7 +164,7 @@ def test_session_unicode(self, httpbin): 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 @@ def test_session_default_header_value_overwritten(self, httpbin): 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()) From a4f796fe6913497a7e212ce8d07837037adcc135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davorin=20S=CC=8Cego?= Date: Sat, 11 Mar 2017 16:58:50 +0100 Subject: [PATCH 0324/1182] Revert "Follow terminal ANSI color styles" This reverts commit b0fde07cfd8676a75292188dd8bedab7de74e6f2. --- httpie/cli.py | 6 +- httpie/output/formatters/colors.py | 146 +++++++++++++++++++++++++++-- 2 files changed, 144 insertions(+), 8 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 1a8fa762d8..7d13972fea 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -20,7 +20,7 @@ PRETTY_STDOUT_TTY_ONLY, SessionNameValidator, readable_file_arg, SSL_VERSION_ARG_MAPPING ) -from httpie.output.formatters.colors import AVAILABLE_STYLES +from httpie.output.formatters.colors import AVAILABLE_STYLES, DEFAULT_STYLE from httpie.plugins import plugin_manager from httpie.plugins.builtin import BuiltinAuthPlugin from httpie.sessions import DEFAULT_SESSIONS_DIR @@ -204,9 +204,10 @@ def _split_lines(self, text, width): '--style', '-s', dest='style', metavar='STYLE', + default=DEFAULT_STYLE, choices=AVAILABLE_STYLES, help=""" - Output coloring style. One of: + Output coloring style (default is "{default}"). One of: {available} @@ -215,6 +216,7 @@ def _split_lines(self, text, width): (e.g., via `export TERM=xterm-256color' in your ~/.bashrc). """.format( + default=DEFAULT_STYLE, available='\n'.join( '{0}{1}'.format(8 * ' ', line.strip()) for line in wrap(', '.join(sorted(AVAILABLE_STYLES)), 60) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index b251b5c4be..b01774330c 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -10,12 +10,20 @@ from pygments.formatters.terminal256 import Terminal256Formatter from pygments.lexers.special import TextLexer from pygments.util import ClassNotFound -from pygments.lexers.text import HttpLexer +from httpie.compat import is_windows from httpie.plugins import FormatterPlugin AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys()) +AVAILABLE_STYLES.add('solarized') + +if is_windows: + # Colors on Windows via colorama don't look that + # great and fruity seems to give the best result there + DEFAULT_STYLE = 'fruity' +else: + DEFAULT_STYLE = 'solarized' class ColorFormatter(FormatterPlugin): @@ -29,7 +37,7 @@ class ColorFormatter(FormatterPlugin): group_name = 'colors' def __init__(self, env, explicit_json=False, - color_scheme=None, **kwargs): + color_scheme=DEFAULT_STYLE, **kwargs): super(ColorFormatter, self).__init__(**kwargs) if not env.colors: self.enabled = False @@ -38,13 +46,19 @@ def __init__(self, env, explicit_json=False, # --json, -j self.explicit_json = explicit_json - if color_scheme and env.colors == 256: - self.formatter = Terminal256Formatter(style=color_scheme) + try: + style_class = pygments.styles.get_style_by_name(color_scheme) + except ClassNotFound: + style_class = Solarized256Style + + if env.colors == 256: + fmt_class = Terminal256Formatter else: - self.formatter = TerminalFormatter() + fmt_class = TerminalFormatter + self.formatter = fmt_class(style=style_class) def format_headers(self, headers): - return pygments.highlight(headers, HttpLexer(), self.formatter).strip() + return pygments.highlight(headers, HTTPLexer(), self.formatter).strip() def format_body(self, body, mime): lexer = self.get_lexer(mime, body) @@ -105,3 +119,123 @@ def get_lexer(mime, explicit_json=False, body=''): lexer = pygments.lexers.get_lexer_by_name('json') return lexer + + +class HTTPLexer(pygments.lexer.RegexLexer): + """Simplified HTTP lexer for Pygments. + + It only operates on headers and provides a stronger contrast between + their names and values than the original one bundled with Pygments + (:class:`pygments.lexers.text import HttpLexer`), especially when + Solarized color scheme is used. + + """ + name = 'HTTP' + aliases = ['http'] + filenames = ['*.http'] + tokens = { + 'root': [ + # Request-Line + (r'([A-Z]+)( +)([^ ]+)( +)(HTTP)(/)(\d+\.\d+)', + pygments.lexer.bygroups( + pygments.token.Name.Function, + pygments.token.Text, + pygments.token.Name.Namespace, + pygments.token.Text, + pygments.token.Keyword.Reserved, + pygments.token.Operator, + pygments.token.Number + )), + # Response Status-Line + (r'(HTTP)(/)(\d+\.\d+)( +)(\d{3})( +)(.+)', + pygments.lexer.bygroups( + pygments.token.Keyword.Reserved, # 'HTTP' + pygments.token.Operator, # '/' + pygments.token.Number, # Version + pygments.token.Text, + pygments.token.Number, # Status code + pygments.token.Text, + pygments.token.Name.Exception, # Reason + )), + # Header + (r'(.*?)( *)(:)( *)(.+)', pygments.lexer.bygroups( + pygments.token.Name.Attribute, # Name + pygments.token.Text, + pygments.token.Operator, # Colon + pygments.token.Text, + pygments.token.String # Value + )) + ] + } + + +class Solarized256Style(pygments.style.Style): + """ + solarized256 + ------------ + + A Pygments style inspired by Solarized's 256 color mode. + + :copyright: (c) 2011 by Hank Gay, (c) 2012 by John Mastro. + :license: BSD, see LICENSE for more details. + + """ + BASE03 = "#1c1c1c" + BASE02 = "#262626" + BASE01 = "#4e4e4e" + BASE00 = "#585858" + BASE0 = "#808080" + BASE1 = "#8a8a8a" + BASE2 = "#d7d7af" + BASE3 = "#ffffd7" + YELLOW = "#af8700" + ORANGE = "#d75f00" + RED = "#af0000" + MAGENTA = "#af005f" + VIOLET = "#5f5faf" + BLUE = "#0087ff" + CYAN = "#00afaf" + GREEN = "#5f8700" + + background_color = BASE03 + styles = { + pygments.token.Keyword: GREEN, + pygments.token.Keyword.Constant: ORANGE, + pygments.token.Keyword.Declaration: BLUE, + pygments.token.Keyword.Namespace: ORANGE, + pygments.token.Keyword.Reserved: BLUE, + pygments.token.Keyword.Type: RED, + pygments.token.Name.Attribute: BASE1, + pygments.token.Name.Builtin: BLUE, + pygments.token.Name.Builtin.Pseudo: BLUE, + pygments.token.Name.Class: BLUE, + pygments.token.Name.Constant: ORANGE, + pygments.token.Name.Decorator: BLUE, + pygments.token.Name.Entity: ORANGE, + pygments.token.Name.Exception: YELLOW, + pygments.token.Name.Function: BLUE, + pygments.token.Name.Tag: BLUE, + pygments.token.Name.Variable: BLUE, + pygments.token.String: CYAN, + pygments.token.String.Backtick: BASE01, + pygments.token.String.Char: CYAN, + pygments.token.String.Doc: CYAN, + pygments.token.String.Escape: RED, + pygments.token.String.Heredoc: CYAN, + pygments.token.String.Regex: RED, + pygments.token.Number: CYAN, + pygments.token.Operator: BASE1, + pygments.token.Operator.Word: GREEN, + pygments.token.Comment: BASE01, + pygments.token.Comment.Preproc: GREEN, + pygments.token.Comment.Special: GREEN, + pygments.token.Generic.Deleted: CYAN, + pygments.token.Generic.Emph: 'italic', + pygments.token.Generic.Error: RED, + pygments.token.Generic.Heading: ORANGE, + pygments.token.Generic.Inserted: GREEN, + pygments.token.Generic.Strong: 'bold', + pygments.token.Generic.Subheading: ORANGE, + pygments.token.Token: BASE1, + pygments.token.Token.Other: ORANGE, + } From 9886f01f91b9007e9b21601264b9c42fecc0d9f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davorin=20S=CC=8Cego?= Date: Sat, 11 Mar 2017 18:00:35 +0100 Subject: [PATCH 0325/1182] New style option that applies the terminal ANSI color scheme --- httpie/cli.py | 2 +- httpie/output/formatters/colors.py | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 7d13972fea..a9ec1eff8a 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -20,7 +20,7 @@ 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, PRESET_STYLE from httpie.plugins import plugin_manager from httpie.plugins.builtin import BuiltinAuthPlugin from httpie.sessions import DEFAULT_SESSIONS_DIR diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index b01774330c..b07c6b5a28 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -9,6 +9,7 @@ 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 @@ -18,6 +19,10 @@ AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys()) AVAILABLE_STYLES.add('solarized') +# This is the native style provided by the terminal emulator color scheme +PRESET_STYLE = 'preset'; +AVAILABLE_STYLES.add(PRESET_STYLE); + if is_windows: # Colors on Windows via colorama don't look that # great and fruity seems to give the best result there @@ -51,14 +56,19 @@ def __init__(self, env, explicit_json=False, except ClassNotFound: style_class = Solarized256Style - if env.colors == 256: + if color_scheme != PRESET_STYLE and env.colors == 256: fmt_class = Terminal256Formatter else: fmt_class = TerminalFormatter self.formatter = fmt_class(style=style_class) + if color_scheme == PRESET_STYLE: + self.http_lexer = PygmentsHttpLexer(); + else: + self.http_lexer = HTTPLexer() + def format_headers(self, headers): - return pygments.highlight(headers, HTTPLexer(), self.formatter).strip() + return pygments.highlight(headers, self.http_lexer, self.formatter).strip() def format_body(self, body, mime): lexer = self.get_lexer(mime, body) From 02209c2db1b4399c17f50718cc19fb37461eba39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davorin=20S=CC=8Cego?= Date: Sat, 11 Mar 2017 18:11:22 +0100 Subject: [PATCH 0326/1182] Oops, remove semicolons --- httpie/output/formatters/colors.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index b07c6b5a28..87174bf1af 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -20,8 +20,8 @@ AVAILABLE_STYLES.add('solarized') # This is the native style provided by the terminal emulator color scheme -PRESET_STYLE = 'preset'; -AVAILABLE_STYLES.add(PRESET_STYLE); +PRESET_STYLE = 'preset' +AVAILABLE_STYLES.add(PRESET_STYLE) if is_windows: # Colors on Windows via colorama don't look that @@ -63,7 +63,7 @@ def __init__(self, env, explicit_json=False, self.formatter = fmt_class(style=style_class) if color_scheme == PRESET_STYLE: - self.http_lexer = PygmentsHttpLexer(); + self.http_lexer = PygmentsHttpLexer() else: self.http_lexer = HTTPLexer() From a196d1d4519b16fb2eb6f726a0929307f37934c4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 12 Mar 2017 13:18:39 +0100 Subject: [PATCH 0327/1182] Travis `cache: pip` --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 9253b7fcc7..83f3c5291a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,7 @@ python: - 3.6 # Currently fails because of a Flask issue # - pypy3 +cache: pip matrix: From d99e1ff492bc483006a10fdc4bd5e6530cd230f5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 12 Mar 2017 13:31:03 +0100 Subject: [PATCH 0328/1182] Fix link --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 8b81c834d2..abb701ecc9 100644 --- a/README.rst +++ b/README.rst @@ -1571,7 +1571,7 @@ Please use the following support channels: * `GitHub issues `_ for bug reports and feature requests. -* `Our Gitter chat room `_ +* `Our Gitter chat room `_ to ask questions, discuss features, and for general discussion. * `StackOverflow `_ to ask questions (please make sure to use the From 9776a6dea0308e05c23db05b542920ebd6bea6c4 Mon Sep 17 00:00:00 2001 From: Pablo Santiago Blum de Aguiar Date: Wed, 17 May 2017 13:51:43 -0300 Subject: [PATCH 0329/1182] Support requests>=2.14.0 From that release onwards, `cert_verify` raises `IOError` [1]. 1: https://github.com/kennethreitz/requests/commit/7d8b87c --- tests/test_ssl.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 50f34d4ca5..63bfd11783 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -90,7 +90,8 @@ def test_self_signed_server_cert_by_default_raises_ssl_error( 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): From 31c78c2885bad84967e3ee978a3ce56760c9048e Mon Sep 17 00:00:00 2001 From: Andreas Lappe Date: Mon, 26 Jun 2017 13:00:46 +0200 Subject: [PATCH 0330/1182] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index abb701ecc9..a736899737 100644 --- a/README.rst +++ b/README.rst @@ -917,7 +917,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. ================= ===================================================== From 8d3f09497b0451a991715302726afb9538913464 Mon Sep 17 00:00:00 2001 From: David Oliver Date: Fri, 30 Jun 2017 14:54:49 +0200 Subject: [PATCH 0331/1182] Fix sentence on overriding default timeout in readme --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index abb701ecc9..08d65c955c 100644 --- a/README.rst +++ b/README.rst @@ -1510,7 +1510,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. From 643735ef2365d33ecc3f8e49d0bebec8165d87cc Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 6 Sep 2017 01:14:40 +0200 Subject: [PATCH 0332/1182] Fix Gitter link Close #590 --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index fab2ee5e3e..b56ae1cc2b 100644 --- a/README.rst +++ b/README.rst @@ -1672,7 +1672,7 @@ have contributed. :target: https://ci.appveyor.com/project/jkbrzt/httpie :alt: Build status of the master branch on Windows -.. |gitter| image:: https://img.shields.io/gitter/room/jakubroztocil/httpie.svg?style=flat-square - :target: https://gitter.im/jakubroztocil/httpie +.. |gitter| image:: https://img.shields.io/gitter/room/jkbrzt/httpie.svg?style=flat-square + :target: https://gitter.im/jkbrzt/httpie :alt: Chat on Gitter From 555761f3cb4f1ee5d943b69adee282a8f70bd91a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 6 Sep 2017 01:42:16 +0200 Subject: [PATCH 0333/1182] Update copyright year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index b84d413a10..5b092812ea 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright © 2012-2016 Jakub Roztocil +Copyright © 2012-2017 Jakub Roztocil Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From dfe6245cd603b26216fd147a3647899148b03973 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 7 Sep 2017 13:57:15 +0200 Subject: [PATCH 0334/1182] Update AppVeyor --- README.rst | 4 ++-- appveyor.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index b56ae1cc2b..fa35f3d156 100644 --- a/README.rst +++ b/README.rst @@ -1668,8 +1668,8 @@ have contributed. :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 +.. |windows_build| image:: https://img.shields.io/appveyor/ci/jakubroztocil/httpie.svg?style=flat-square&label=windows%20build + :target: https://ci.appveyor.com/project/jakubroztocil/httpie :alt: Build status of the master branch on Windows .. |gitter| image:: https://img.shields.io/gitter/room/jkbrzt/httpie.svg?style=flat-square diff --git a/appveyor.yml b/appveyor.yml index ca1d6d70a2..c99f4bf2a1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -# https://ci.appveyor.com/project/jkbrzt/httpie +# https://ci.appveyor.com/project/jakubroztocil/httpie build: false environment: From 9af833da309d664fefc532ba4abc8b07b6673ae1 Mon Sep 17 00:00:00 2001 From: Randy Ramos Date: Mon, 2 Oct 2017 16:55:35 -0400 Subject: [PATCH 0335/1182] List DNF as Fedora package manager in README --- README.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index fa35f3d156..d597818526 100644 --- a/README.rst +++ b/README.rst @@ -83,7 +83,12 @@ system package manager, for example: .. code-block:: bash - # Fedora, CentOS, RHEL, … + # Fedora + $ dnf install httpie + +.. code-block:: bash + + # CentOS, RHEL, ... $ yum install httpie .. code-block:: bash From 0aab796960647886522a41c48d247595802c887a Mon Sep 17 00:00:00 2001 From: James Date: Mon, 13 Nov 2017 07:23:52 -0500 Subject: [PATCH 0336/1182] Clarify error message --- httpie/input.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/httpie/input.py b/httpie/input.py index 7960cd94cd..de402b05ab 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -302,7 +302,8 @@ def _body_from_file(self, fd): """ 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): From 37c3307018b6ef0a7fde435231aefc2da514dbd5 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 14 Nov 2017 09:18:10 -0500 Subject: [PATCH 0337/1182] Remove 2.6 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 83f3c5291a..987c38a70b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,6 @@ env: - NEWEST_PYTHON=3.6 python: - - 2.6 - 2.7 - pypy - 3.4 From 6472ca55e16fab898476ce2f08ef71d57efaf3c3 Mon Sep 17 00:00:00 2001 From: darshanime Date: Sat, 18 Nov 2017 19:01:26 +0530 Subject: [PATCH 0338/1182] fix env version attribute --- httpie/config.py | 2 +- tests/test_config.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/httpie/config.py b/httpie/config.py index 9cb6c4af36..7621878fba 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -104,7 +104,7 @@ def _migrate_implicit_content_type(self): 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') diff --git a/tests/test_config.py b/tests/test_config.py index c309117316..9b0a20979e 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,4 +1,6 @@ +from httpie import __version__ from utils import TestEnvironment, http +from httpie.context import Environment def test_default_options(httpbin): @@ -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__ From 8841b8bf4638417038929bf2c7828098bbce40ad Mon Sep 17 00:00:00 2001 From: Greg Back Date: Thu, 7 Dec 2017 04:39:32 +0000 Subject: [PATCH 0339/1182] Update CONTRIBUTING.rst to include correct Makefile targets. --- CONTRIBUTING.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 472bddaf42..bc25810f4d 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -47,7 +47,7 @@ Go to https://github.com/jakubroztocil/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 @@ -71,12 +71,9 @@ 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 From 803127e8c99fd0a8b876f8670483dbea6830cda6 Mon Sep 17 00:00:00 2001 From: Pablo Santiago Blum de Aguiar Date: Wed, 17 May 2017 13:05:44 -0300 Subject: [PATCH 0340/1182] Remove duplicate option from Fish completion list --- extras/httpie-completion.fish | 1 - 1 file changed, 1 deletion(-) diff --git a/extras/httpie-completion.fish b/extras/httpie-completion.fish index 4e4efd30a5..2b9dc5671d 100644 --- a/extras/httpie-completion.fish +++ b/extras/httpie-completion.fish @@ -34,7 +34,6 @@ complete -x -c http -s s -l style -d 'Output coloring style (default is " 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' From 46e24dd6b51d56ea71e4c201a79987a10f0a1660 Mon Sep 17 00:00:00 2001 From: Pablo Santiago Blum de Aguiar Date: Wed, 17 May 2017 13:08:47 -0300 Subject: [PATCH 0341/1182] Use function as source of styles for Fish completion --- extras/httpie-completion.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/httpie-completion.fish b/extras/httpie-completion.fish index 2b9dc5671d..e515eef5e2 100644 --- a/extras/httpie-completion.fish +++ b/extras/httpie-completion.fish @@ -30,7 +30,7 @@ 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 From ca7f41de534dbf1236088acec5da419a97d06991 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 13 Dec 2017 21:29:51 +0100 Subject: [PATCH 0342/1182] appveyor fix attempt --- appveyor.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c99f4bf2a1..579a8a5116 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,8 +13,7 @@ init: - ps: "ls C:/Python*" install: - # FIXME: updating pip fails with PermissionError - # - "%PYTHON%/Scripts/pip.exe install -U pip setuptools" + - "%PYTHON%/python.exe -m pip install -U pip" - "%PYTHON%/Scripts/pip.exe install -e ." test_script: From 91e1fe2d0f0ca30e5d4d7eb2abacfe5602b3dc82 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 13 Dec 2017 21:32:37 +0100 Subject: [PATCH 0343/1182] appveyor fix attempt II. --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 579a8a5116..f362fc4f93 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,9 +14,9 @@ init: install: - "%PYTHON%/python.exe -m pip install -U pip" - - "%PYTHON%/Scripts/pip.exe install -e ." + - "%PYTHON%/python.exe -m pip install -e ." test_script: - - "%PYTHON%/Scripts/pip.exe --version" + - "%PYTHON%/python.exe -m pip --version" - "%PYTHON%/Scripts/http.exe --debug" - "%PYTHON%/python.exe setup.py test" From c5d6a4ad8ec29100cdb4f8f04f9076d35f9bcd33 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 17 Dec 2017 19:42:15 +0100 Subject: [PATCH 0344/1182] OS X => macOS Close #634 --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index d597818526..2e15cfc29d 100644 --- a/README.rst +++ b/README.rst @@ -42,7 +42,7 @@ Main features * Persistent sessions * Wget-like downloads * Python 2.6, 2.7 and 3.x support -* Linux, Mac OS X and Windows support +* Linux, macOS and Windows support * Plugins * Documentation * Test coverage @@ -1656,7 +1656,7 @@ have contributed. .. _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/jakubroztocil/httpie/contributors -.. _Jakub Roztocil: http://roztocil.co +.. _Jakub Roztocil: https://roztocil.co .. _@jakubroztocil: https://twitter.com/jakubroztocil .. _claudiatd/httpie-artwork: https://github.com/claudiatd/httpie-artwork From 1719ebded60090facaa969fa87639cd4f0458af1 Mon Sep 17 00:00:00 2001 From: Ildar Sagdejev Date: Fri, 22 Dec 2017 02:37:04 +0000 Subject: [PATCH 0345/1182] Fix README (#641) --- README.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 2e15cfc29d..70eb312b31 100644 --- a/README.rst +++ b/README.rst @@ -399,8 +399,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 From 8b189725fd743bbe32c1ccc97768d43661d5f875 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 22 Dec 2017 14:34:20 +0100 Subject: [PATCH 0346/1182] Remove AppVeyor @appveyor https://help.appveyor.com/discussions/problems/10507-pip-install-fails-with-access-is-denied-error --- README.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.rst b/README.rst index 70eb312b31..f1856900f9 100644 --- a/README.rst +++ b/README.rst @@ -1672,10 +1672,6 @@ have contributed. :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/jakubroztocil/httpie.svg?style=flat-square&label=windows%20build - :target: https://ci.appveyor.com/project/jakubroztocil/httpie - :alt: Build status of the master branch on Windows - .. |gitter| image:: https://img.shields.io/gitter/room/jkbrzt/httpie.svg?style=flat-square :target: https://gitter.im/jkbrzt/httpie :alt: Chat on Gitter From 4b6110800542a91950863e3cba588bebad1e3558 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 22 Dec 2017 14:35:23 +0100 Subject: [PATCH 0347/1182] Remove AppVeyor II. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f1856900f9..84e21f1e43 100644 --- a/README.rst +++ b/README.rst @@ -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| From 7f24f7d34c5eb2c4c55eb9a4dd15cdc5dbc0615f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 22 Dec 2017 14:36:13 +0100 Subject: [PATCH 0348/1182] Delete appveyor.yml --- appveyor.yml | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index f362fc4f93..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,22 +0,0 @@ -# https://ci.appveyor.com/project/jakubroztocil/httpie -build: false - -environment: - matrix: - - PYTHON: "C:/Python27" - # Python 3.4 has outdated pip - # - PYTHON: "C:/Python34" - - PYTHON: "C:/Python36" - -init: - - "ECHO %PYTHON%" - - ps: "ls C:/Python*" - -install: - - "%PYTHON%/python.exe -m pip install -U pip" - - "%PYTHON%/python.exe -m pip install -e ." - -test_script: - - "%PYTHON%/python.exe -m pip --version" - - "%PYTHON%/Scripts/http.exe --debug" - - "%PYTHON%/python.exe setup.py test" From 27c557e983b71887e79812cb2e05daa0a7f0bfa8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 22 Dec 2017 14:40:48 +0100 Subject: [PATCH 0349/1182] Update README.rst test --- README.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/README.rst b/README.rst index 84e21f1e43..2808cc5bd3 100644 --- a/README.rst +++ b/README.rst @@ -1675,4 +1675,3 @@ have contributed. .. |gitter| image:: https://img.shields.io/gitter/room/jkbrzt/httpie.svg?style=flat-square :target: https://gitter.im/jkbrzt/httpie :alt: Chat on Gitter - From 4d3b4fa0beaed33bda5da61e1d7a6ea395f380c3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 22 Dec 2017 14:48:08 +0100 Subject: [PATCH 0350/1182] Fix rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2808cc5bd3..322d09d8c0 100644 --- a/README.rst +++ b/README.rst @@ -135,7 +135,7 @@ 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| |windows_build| +|unix_build| On macOS you can install it with Homebrew: From ec899d70b725d8f74c971cc21018ec24a8586ad5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 28 Dec 2017 18:03:13 +0100 Subject: [PATCH 0351/1182] Removed Python 2.6 support * Travis CI doesn't support it anymore. * It had EOL more than 4 years ago --- CHANGELOG.rst | 3 + README.rst | 10 +-- httpie/compat.py | 141 +------------------------------------------ httpie/input.py | 4 +- httpie/utils.py | 5 +- setup.py | 2 - tests/test_httpie.py | 5 -- tox.ini | 2 +- 8 files changed, 13 insertions(+), 159 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4e3a7d7617..48d4552e29 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,9 +8,12 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (unreleased) ------------------------- + +* Removed Python 2.6 support. * ``--verify`` now accepts ``true``/``false`` in addition to ``yes``/``no`` and the boolean value is case-insensitive. + `0.9.8`_ (2016-12-08) --------------------- diff --git a/README.rst b/README.rst index 322d09d8c0..245f8ccb67 100644 --- a/README.rst +++ b/README.rst @@ -41,7 +41,7 @@ Main features * Custom headers * Persistent sessions * Wget-like downloads -* Python 2.6, 2.7 and 3.x support +* Python 2.7 and 3.x support * Linux, macOS and Windows support * Plugins * Documentation @@ -119,10 +119,10 @@ and always provides the latest version) is to use `pip`_: 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``. diff --git a/httpie/compat.py b/httpie/compat.py index d626e98480..d81e508b5e 100644 --- a/httpie/compat.py +++ b/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 @@ 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 .### - # - # 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 diff --git a/httpie/input.py b/httpie/input.py index de402b05ab..978b4b44e2 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -9,7 +9,7 @@ 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 @@ -18,7 +18,7 @@ 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 diff --git a/httpie/utils.py b/httpie/utils.py index c3b012581a..e5d9766d14 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -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) diff --git a/setup.py b/setup.py index ec071a2d46..bf66f062ab 100644 --- a/setup.py +++ b/setup.py @@ -93,8 +93,6 @@ def long_description(): 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', diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 36a856f76b..a3717470a4 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -6,7 +6,6 @@ from fixtures import FILE_PATH, FILE_CONTENT import httpie -from httpie.compat import is_py26 def test_debug(): @@ -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"}}') diff --git a/tox.ini b/tox.ini index aaa231f6ea..834e336293 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ [tox] -envlist = py26, py27, py35, py36, pypy, codestyle +envlist = py27, py35, py36, pypy, codestyle [testenv] From 7f5fd130c52f2d58011ddeb520e245cfb3b5fd14 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 28 Dec 2017 18:15:17 +0100 Subject: [PATCH 0352/1182] Start using dict comprehensions --- httpie/__init__.py | 6 +++--- httpie/client.py | 2 +- httpie/input.py | 6 +++--- httpie/plugins/manager.py | 3 +-- httpie/sessions.py | 6 +++--- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/httpie/__init__.py b/httpie/__init__.py index abed9a91c1..0725cc1599 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -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() -) +} diff --git a/httpie/client.py b/httpie/client.py index 0c7566aa93..1ffc6fbd28 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -166,7 +166,7 @@ def get_requests_kwargs(args, base_headers=None): '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, diff --git a/httpie/input.py b/httpie/input.py index 978b4b44e2..affb73fe02 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -112,11 +112,11 @@ 'tls1.1': 'PROTOCOL_TLSv1_1', 'tls1.2': 'PROTOCOL_TLSv1_2', } -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): diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index f7a2a063f4..c6390f2606 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -39,8 +39,7 @@ def get_auth_plugins(self): 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] diff --git a/httpie/sessions.py b/httpie/sessions.py index ff3969be3b..ba162e14c8 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -136,10 +136,10 @@ def cookies(self, jar): 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): From 11be041e066d7165345413fa380d7b7cd3c08737 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 28 Dec 2017 18:17:48 +0100 Subject: [PATCH 0353/1182] Rename `TestEnvironment` to `MockEnvironment` to avoid pytest warnings Close #621 --- tests/test_auth.py | 4 ++-- tests/test_binary.py | 12 ++++++------ tests/test_cli.py | 32 ++++++++++++++++---------------- tests/test_config.py | 8 ++++---- tests/test_defaults.py | 8 ++++---- tests/test_downloads.py | 4 ++-- tests/test_exit_status.py | 4 ++-- tests/test_httpie.py | 4 ++-- tests/test_output.py | 14 +++++++------- tests/test_sessions.py | 4 ++-- tests/test_stream.py | 8 ++++---- tests/test_uploads.py | 6 +++--- tests/test_windows.py | 4 ++-- tests/utils.py | 8 ++++---- 14 files changed, 60 insertions(+), 60 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index 2beb518d7b..62cceb65bf 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -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 @@ -58,7 +58,7 @@ def test_only_username_in_url(url): 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 == '' diff --git a/tests/test_binary.py b/tests/test_binary.py index a76b9cfab8..cb6da2e85d 100644 --- a/tests/test_binary.py +++ b/tests/test_binary.py @@ -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 @@ def test_binary_stdin(self, httpbin): 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 @@ def test_binary_suppresses_when_terminal(self): 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 diff --git a/tests/test_cli.py b/tests/test_cli.py index fa20117cf7..ed78d50f6f 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -10,7 +10,7 @@ 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 @@ -161,44 +161,44 @@ def test_query_string_params_in_url_and_items_with_duplicates(self, 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 @@ def test_guess_when_method_set_and_valid(self): 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 @@ def test_guess_when_method_not_set(self): 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 @@ def test_guess_when_method_set_but_invalid_and_data_field(self): 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 @@ def test_guess_when_method_set_but_invalid_and_header_field(self): 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 @@ def test_guess_when_method_set_but_invalid_and_item_exists(self): ] 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 diff --git a/tests/test_config.py b/tests/test_config.py index 9b0a20979e..d31ae1f38f 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,10 +1,10 @@ from httpie import __version__ -from utils import TestEnvironment, http +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) @@ -12,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) @@ -20,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() diff --git a/tests/test_defaults.py b/tests/test_defaults.py index 75e8ed1e6d..41a896c591 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -3,7 +3,7 @@ """ 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 @@ -29,7 +29,7 @@ def test_implicit_POST_form(self, httpbin): 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 @@ -97,11 +97,11 @@ def test_POST_form_Content_Type_override(self, httpbin): 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 diff --git a/tests/test_downloads.py b/tests/test_downloads.py index e09bdde327..a678d0d807 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -10,7 +10,7 @@ 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 diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index e3f89c14f5..7e37f0732d 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -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): @@ -40,7 +40,7 @@ def test_timeout_exit_status(httpbin): 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) diff --git a/tests/test_httpie.py b/tests/test_httpie.py index a3717470a4..5fb045b940 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -2,7 +2,7 @@ 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 @@ -63,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 diff --git a/tests/test_output.py b/tests/test_output.py index b9907e72b1..d57e891cf0 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -3,7 +3,7 @@ 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() @@ -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 @@ def test_pretty_enabled_by_default_unless_stdout_redirected(self, httpbin): 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 @@ def test_subtype_based_pygments_lexer_match(self, httpbin): 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 @@ def test_colors_option(self, httpbin): 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) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 893069b714..0507b71baa 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -7,7 +7,7 @@ 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 @@ def env(self): for session files being reused. """ - return TestEnvironment(config_dir=self.config_dir) + return MockEnvironment(config_dir=self.config_dir) class TestSessionFlow(SessionTestBase): diff --git a/tests/test_stream.py b/tests/test_stream.py index 48c8dbf693..01ee151d01 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -2,7 +2,7 @@ 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 @@ 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', diff --git a/tests/test_uploads.py b/tests/test_uploads.py index 5cbe2caba2..e65fde0e04 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -3,7 +3,7 @@ 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 @@ def test_request_body_from_file_by_path_with_explicit_content_type( 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 diff --git a/tests/test_windows.py b/tests/test_windows.py index ca5e2bb611..90be4814fe 100644 --- a/tests/test_windows.py +++ b/tests/test_windows.py @@ -4,7 +4,7 @@ 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 @@ def test_windows_colorized_output(self, httpbin): 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__ diff --git a/tests/utils.py b/tests/utils.py index 63a4288ab9..1c18f9235e 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -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 @@ def __init__(self, **kwargs): 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 @@ def config(self): 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: @@ -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 From a803e845a5676c6a09087584051bccb412cf08dc Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 28 Dec 2017 18:32:12 +0100 Subject: [PATCH 0354/1182] More robust urllib3 import --- httpie/client.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 1ffc6fbd28..0c66db4139 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -3,7 +3,6 @@ import requests from requests.adapters import HTTPAdapter -from requests.packages import urllib3 from httpie import sessions from httpie import __version__ @@ -14,8 +13,10 @@ 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. From 6301fee3d24bbff13ed05bfa0d585e23bca0b65e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 28 Dec 2017 18:32:29 +0100 Subject: [PATCH 0355/1182] Upgrade to latest requests --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index bf66f062ab..7c0e8a1f75 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ def run_tests(self): install_requires = [ - 'requests>=2.11.0', + 'requests>=2.18.4', 'Pygments>=2.1.3' ] From 05547224ce03beb3d296f14daee347b46ac2f9ac Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 28 Dec 2017 18:33:31 +0100 Subject: [PATCH 0356/1182] Remove a Python 2.6 mention from `extras_require` --- setup.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 7c0e8a1f75..de1433ef9d 100644 --- a/setup.py +++ b/setup.py @@ -58,9 +58,7 @@ def run_tests(self): # 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'], } From 0f4dce98c70ca4517128990184c47388e58e04dd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 22 Feb 2018 12:52:57 +0100 Subject: [PATCH 0357/1182] Make default HTTP headers case-insensitive Cloase #644 --- CHANGELOG.rst | 6 ++++-- httpie/client.py | 5 +++-- tests/test_defaults.py | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 48d4552e29..d5aa768055 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,9 +9,11 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (unreleased) ------------------------- +* Added ``true``/``false`` as valid values for ``--verify`` + (in addition to ``yes``/``no``) and the boolean value is case-insensitive. +* Fixed default headers being incorrectly case-sensitive. * Removed Python 2.6 support. -* ``--verify`` now accepts ``true``/``false`` in addition to ``yes``/``no`` - and the boolean value is case-insensitive. + `0.9.8`_ (2016-12-08) diff --git a/httpie/client.py b/httpie/client.py index 0c66db4139..21a7f67aff 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -3,6 +3,7 @@ import requests from requests.adapters import HTTPAdapter +from requests.structures import CaseInsensitiveDict from httpie import sessions from httpie import __version__ @@ -106,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: diff --git a/tests/test_defaults.py b/tests/test_defaults.py index 41a896c591..10221fe46c 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -7,6 +7,21 @@ from fixtures import FILE_PATH +def test_default_headers_case_insensitive(httpbin): + """ + + """ + 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') From 8ca333dda099fabf856e7e70eb67c213267db17c Mon Sep 17 00:00:00 2001 From: Theodore Dubois Date: Wed, 11 Apr 2018 18:04:02 -0700 Subject: [PATCH 0358/1182] Use parentheses in describing sessions (#664) It's a little more readable than using em dashes. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 245f8ccb67..7b9b3716af 100644 --- a/README.rst +++ b/README.rst @@ -1346,7 +1346,7 @@ 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-``—, +custom headers (except for the ones starting with ``Content-`` or ``If-``), authorization, and cookies (manually specified or sent by the server) persist between requests to the same host. From 87e661c5f165e710ecd0863c6e3529d0a131da0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20=C5=9Aliwka?= Date: Sat, 14 Apr 2018 22:25:59 +0200 Subject: [PATCH 0359/1182] Support using styles from Pygments plugins (#663) `pygments.styles.STYLE_MAP` contains only styles built directly into Pygments library. To list all available styles (including styles registered by plugins), one should use `get_all_styles` generator. For respective Pygments documentation, see: http://pygments.org/docs/styles/#getting-a-list-of-available-styles --- httpie/output/formatters/colors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 87174bf1af..30970c5d8c 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -16,7 +16,7 @@ from httpie.plugins import FormatterPlugin -AVAILABLE_STYLES = set(pygments.styles.STYLE_MAP.keys()) +AVAILABLE_STYLES = set(pygments.styles.get_all_styles()) AVAILABLE_STYLES.add('solarized') # This is the native style provided by the terminal emulator color scheme From 8f7676a2a929f08705f8ede908dd7264cd582c46 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 30 May 2018 13:55:06 +0200 Subject: [PATCH 0360/1182] Add Cookies section to the docs --- README.rst | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 7b9b3716af..7b9509d1e3 100644 --- a/README.rst +++ b/README.rst @@ -605,6 +605,26 @@ To set custom headers you can use the ``Header:Value`` notation: X-Foo: Bar +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: + + +.. code-block:: bash + + # Send a single cookie: + $ http example.org Cookie:sessionid=foo + + # Send multiple cookies (quoted to prevent the shell from interpreting the ';'): + $ http example.org 'Cookie:sessionid=foo;another-cookie=bar' + +If you often deal with cookies in your requests, then chances are you'd appreciate +the `sessions`_ feature. + + Default request headers ----------------------- @@ -1379,7 +1399,7 @@ you can create a new session named ``user1`` for ``example.org``: $ http --session=user1 -a user1:password example.org X-Foo:Bar From now on, you can refer to the session by its name. When you choose to -use the session again, any the previously used authorization and HTTP headers +use the session again, any previously specified authorization or HTTP headers will automatically be set: .. code-block:: bash From 6fd1ea0e5a9b86e63f9cff3493242a08687b66fb Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 30 May 2018 13:56:35 +0200 Subject: [PATCH 0361/1182] Section ordering --- README.rst | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/README.rst b/README.rst index 7b9509d1e3..50f527cb60 100644 --- a/README.rst +++ b/README.rst @@ -605,26 +605,6 @@ To set custom headers you can use the ``Header:Value`` notation: X-Foo: Bar -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: - - -.. code-block:: bash - - # Send a single cookie: - $ http example.org Cookie:sessionid=foo - - # Send multiple cookies (quoted to prevent the shell from interpreting the ';'): - $ http example.org 'Cookie:sessionid=foo;another-cookie=bar' - -If you often deal with cookies in your requests, then chances are you'd appreciate -the `sessions`_ feature. - - Default request headers ----------------------- @@ -664,6 +644,26 @@ 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: + + +.. code-block:: bash + + # Send a single cookie: + $ http example.org Cookie:sessionid=foo + + # Send multiple cookies (quoted to prevent the shell from interpreting the ';'): + $ http example.org 'Cookie:sessionid=foo;another-cookie=bar' + +If you often deal with cookies in your requests, then chances are you'd appreciate +the `sessions`_ feature. + + Authentication ============== From c9c6f0fae59b284757b3b7fafade32b668abd0c5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 30 May 2018 14:02:46 +0200 Subject: [PATCH 0362/1182] Formatting --- README.rst | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 50f527cb60..546a426b6d 100644 --- a/README.rst +++ b/README.rst @@ -652,14 +652,41 @@ HTTPie does not offer any special syntax for specifying cookies — the usual ``Header:Value`` notation is used: +Send a single cookie: + .. code-block:: bash - # Send a single cookie: $ http example.org Cookie:sessionid=foo - # Send multiple cookies (quoted to prevent the shell from interpreting the ';'): +.. 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. From 137889a2672f55fd1db5fdd346396e8b596b0499 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 30 May 2018 14:07:52 +0200 Subject: [PATCH 0363/1182] Doc improvements --- README.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 546a426b6d..56c40e44e6 100644 --- a/README.rst +++ b/README.rst @@ -743,7 +743,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 @@ -1393,8 +1393,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. @@ -1408,11 +1408,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 -------------- @@ -1426,7 +1427,7 @@ you can create a new session named ``user1`` for ``example.org``: $ http --session=user1 -a user1:password example.org X-Foo:Bar From now on, you can refer to the session by its name. When you choose to -use the session again, any previously specified authorization or HTTP headers +use the session again, any previously specified authentication or HTTP headers will automatically be set: .. code-block:: bash From 749b1e2aca11e1ae3e52c8f3894cf0515c917439 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 9 Jun 2018 11:59:34 +0200 Subject: [PATCH 0364/1182] Fix pytest configuration --- tests/conftest.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 4b4a8bac47..ea0874660e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -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 From a50660cc70701a2a09dda077ff0a87aa6c669c0e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 12 Jul 2018 00:39:31 +0200 Subject: [PATCH 0365/1182] Test --timeout with longer delay test_timeout_exit_status fails on Python 2.7 https://travis-ci.org/jakubroztocil/httpie/jobs/390072675#L325 --- tests/test_exit_status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index 7e37f0732d..119b8d120e 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -33,7 +33,7 @@ def test_error_response_exits_0_without_check_status(httpbin): def test_timeout_exit_status(httpbin): - r = http('--timeout=0.01', 'GET', httpbin.url + '/delay/0.02', + r = http('--timeout=0.01', 'GET', httpbin.url + '/delay/0.5', error_exit_ok=True) assert r.exit_status == ExitStatus.ERROR_TIMEOUT From 7917f1b40c299145b005fcc8b99627a0dd5645f9 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 12 Jul 2018 21:16:16 +0200 Subject: [PATCH 0366/1182] 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. --- .coveragerc | 1 - .gitignore | 4 +- .travis.yml | 88 ++++++++++++----------------- CONTRIBUTING.rst | 8 ++- Makefile | 57 +++++++++++++++---- extras/get-homebrew-formula-vars.py | 42 +++++++------- httpie/core.py | 4 +- httpie/downloads.py | 40 ++++++------- httpie/input.py | 23 ++++---- httpie/output/formatters/json.py | 4 +- httpie/sessions.py | 4 +- pytest.ini | 2 - requirements-dev.txt | 1 + setup.cfg | 17 ++++++ tests/test_cli.py | 6 +- tests/test_sessions.py | 8 +-- tests/utils.py | 4 +- tox.ini | 11 +--- 18 files changed, 177 insertions(+), 147 deletions(-) delete mode 100644 .coveragerc delete mode 100644 pytest.ini diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 99e1cbc0be..0000000000 --- a/.coveragerc +++ /dev/null @@ -1 +0,0 @@ -; needs to exist otherwise `$ coveralls` fails diff --git a/.gitignore b/.gitignore index 0131d9ac8d..7da36e0c97 100644 --- a/.gitignore +++ b/.gitignore @@ -2,12 +2,12 @@ .idea/ __pycache__/ dist/ -httpie.egg-info/ build/ *.egg-info .cache/ -.tox +.tox/ .coverage *.pyc *.egg htmlcov +.pytest_cache/ diff --git a/.travis.yml b/.travis.yml index 987c38a70b..9a844bb8fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,95 +1,77 @@ -# 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 + # - 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 - fi - if [[ $CODESTYLE ]]; then - pip install pycodestyle + sudo pip install tox + if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then + brew install "$BREW_PYTHON_PACKAGE" + fi 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 diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index bc25810f4d..2d1edd5223 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -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. diff --git a/Makefile b/Makefile index ce83fcde54..402017a252 100644 --- a/Makefile +++ b/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 diff --git a/extras/get-homebrew-formula-vars.py b/extras/get-homebrew-formula-vars.py index 158d07008e..af44f156e0 100755 --- a/extras/get-homebrew-formula-vars.py +++ b/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 @@ ] -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 -} - - -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)) +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() + + +if __name__ == '__main__': + main() diff --git a/httpie/core.py b/httpie/core.py index 1e2772ce8f..8442d614bd 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -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() diff --git a/httpie/downloads.py b/httpie/downloads.py index 8b97f4e127..8c714c54e6 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -54,8 +54,8 @@ def parse_content_range(content_range, resumed_from): raise ContentRangeError('Missing Content-Range') pattern = ( - '^bytes (?P\d+)-(?P\d+)' - '/(\*|(?P\d+))$' + r'^bytes (?P\d+)-(?P\d+)' + r'/(\*|(?P\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 @@ def failed(self): @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 @@ def report_speed(self): 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 @@ def report_speed(self): 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 @@ def sum_up(self): 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, )) diff --git a/httpie/input.py b/httpie/input.py index affb73fe02..ebf46df3f5 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -254,8 +254,8 @@ def _process_auth(self): 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 @@ def _guess_method(self): 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 @@ def _process_pretty_options(self): 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 @@ def __init__(self, error_message): 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 Escaped(str): """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') diff --git a/httpie/output/formatters/json.py b/httpie/output/formatters/json.py index 6d8c89ef90..9af5db1ae2 100644 --- a/httpie/output/formatters/json.py +++ b/httpie/output/formatters/json.py @@ -15,8 +15,8 @@ def format_body(self, body, mime): '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: diff --git a/httpie/sessions.py b/httpie/sessions.py index ba162e14c8..69dc25383b 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -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' diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index f132993de7..0000000000 --- a/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -norecursedirs = tests/fixtures diff --git a/requirements-dev.txt b/requirements-dev.txt index 0578ada35b..3384c15230 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,3 +5,4 @@ pytest-cov pytest-httpbin>=0.0.6 docutils wheel +pycodestyle diff --git a/setup.cfg b/setup.cfg index 5e4090017a..3db9ed60e8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,19 @@ [wheel] universal = 1 + + +[tool:pytest] +# +norecursedirs = tests/fixtures + + +[pycodestyle] +# + +exclude = .git,.idea,__pycache__,build,dist,.tox,.pytest_cache,*.egg-info + +# +# E241 - multiple spaces after ‘,’ +# E501 - line too long +# W503 - line break before binary operator +ignore = E241,E501,W503 diff --git a/tests/test_cli.py b/tests/test_cli.py index ed78d50f6f..5daa3bb7af 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -49,9 +49,9 @@ def test_escape_separator(self): 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): diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 0507b71baa..ebaa7a9d73 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -81,8 +81,8 @@ def test_session_update(self, httpbin): 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 @@ def test_session_unicode(self, httpbin): 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 diff --git a/tests/utils.py b/tests/utils.py index 1c18f9235e..0c31c966d8 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -119,8 +119,8 @@ def json(self): 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: diff --git a/tox.ini b/tox.ini index 834e336293..8c888ed40c 100644 --- a/tox.ini +++ b/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 From bf73b5701e7f6799ebaac73bc4443c6c22ad8817 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 12 Jul 2018 21:23:32 +0200 Subject: [PATCH 0367/1182] Fix travis.yml syntax --- .travis.yml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9a844bb8fd..f71e4c64f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,28 +44,28 @@ matrix: env: CODESTYLE_ONLY=true install: - | - if [[ $TRAVIS_OS_NAME == 'osx' ]]; then - sudo pip install tox - if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then - brew install "$BREW_PYTHON_PACKAGE" - fi - fi + if [[ $TRAVIS_OS_NAME == 'osx' ]]; then + sudo pip install tox + if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then + brew install "$BREW_PYTHON_PACKAGE" + fi + fi script: - | - if [[ $TRAVIS_OS_NAME == 'linux' ]]; then - if [[ $CODESTYLE_ONLY ]]; then - make pycodestyle - else - make test - fi - else - PATH="/usr/local/bin:$PATH" tox -e "$TOXENV" - fi + if [[ $TRAVIS_OS_NAME == 'linux' ]]; then + if [[ $CODESTYLE_ONLY ]]; then + make pycodestyle + else + 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 - make coveralls - fi + if [[ $TRAVIS_PYTHON_VERSION == $NEWEST_PYTHON && $TRAVIS_OS_NAME == 'linux' ]]; then + make coveralls + fi notifications: webhooks: # options: [always|never|change] default: always From f93f4fa7c7c2b6496275c26c4305cedb01ca9994 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 12 Jul 2018 21:33:12 +0200 Subject: [PATCH 0368/1182] Travis CI Python versions; install fix --- .travis.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index f71e4c64f9..c6f2536baa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,16 +5,24 @@ os: - linux env: global: - - NEWEST_PYTHON=3.7 + - NEWEST_PYTHON=3.7-dev # Final Python 3.7 no available as of now python: + # + - 2.7 - - 3.4 - 3.5 + + # Python 3.4 fails installing packages + # + # - 3.4 + - 3.6 - - 3.7 + - 3.7-dev # Final Python 3.7 no available as of now - pypy + # pypy3 currently fails because of a Flask issue # - pypy3 + cache: pip matrix: include: @@ -45,10 +53,10 @@ matrix: install: - | if [[ $TRAVIS_OS_NAME == 'osx' ]]; then - sudo pip install tox if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then brew install "$BREW_PYTHON_PACKAGE" fi + sudo pip install tox fi script: - | From 61568f1def1ef4f3d5ffeb709b7fcfd1b1c3b6bc Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 12 Jul 2018 21:46:00 +0200 Subject: [PATCH 0369/1182] Travis --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c6f2536baa..806f9fa6fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ os: - linux env: global: - - NEWEST_PYTHON=3.7-dev # Final Python 3.7 no available as of now + - NEWEST_PYTHON=3.6 # Final Python 3.7 unavailable as of now (and -dev fails) python: # @@ -17,7 +17,8 @@ python: # - 3.4 - 3.6 - - 3.7-dev # Final Python 3.7 no available as of now + # Final Python 3.7 unavailable as of now (and -dev fails) + # - 3.7 - pypy # pypy3 currently fails because of a Flask issue @@ -54,6 +55,7 @@ install: - | if [[ $TRAVIS_OS_NAME == 'osx' ]]; then if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then + brew update brew install "$BREW_PYTHON_PACKAGE" fi sudo pip install tox From 59d51ad513c8a6ee205dbf598a94a5517b210170 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 12 Jul 2018 21:52:01 +0200 Subject: [PATCH 0370/1182] Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 806f9fa6fc..4a4651d7f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,7 +58,7 @@ install: brew update brew install "$BREW_PYTHON_PACKAGE" fi - sudo pip install tox + sudo pip2 install tox fi script: - | From 2038fa02e3aec23752b92bd12fe5aa052e283bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Sun, 22 Jul 2018 17:57:52 +0200 Subject: [PATCH 0371/1182] Mention v0.9.9 in CHANGELOG #620 --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d5aa768055..dbc719da33 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,6 +16,12 @@ This project adheres to `Semantic Versioning `_. +`0.9.9`_ (2016-12-08) +--------------------- + +* Fixed README. + + `0.9.8`_ (2016-12-08) --------------------- From 2490bb25ca2d49873497334ff7b0ecdf40d7f27d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Sun, 22 Jul 2018 17:58:52 +0200 Subject: [PATCH 0372/1182] Add v 0.9.9 CHANGELOG link --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dbc719da33..bce1ea56a1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -335,4 +335,5 @@ This project adheres to `Semantic Versioning `_. .. _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-dev: https://github.com/jakubroztocil/httpie/compare/0.9.8...master From eb929cbc04a365bcdb3c7ff3c53f6a7216cdca85 Mon Sep 17 00:00:00 2001 From: cclauss Date: Wed, 25 Jul 2018 14:02:00 +0200 Subject: [PATCH 0373/1182] Travis CI: Add Python 3.7 on linux to the testing (#690) * Travis CI: Add Python 3.7 on linux to the testing `sudo: true` and `dist: xenial` are currently required https://github.com/travis-ci/travis-ci/issues/9069 * NEWEST_PYTHON=3.7 --- .travis.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4a4651d7f8..4ad14764aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,20 +5,19 @@ os: - linux env: global: - - NEWEST_PYTHON=3.6 # Final Python 3.7 unavailable as of now (and -dev fails) + - NEWEST_PYTHON=3.7 python: # - 2.7 - - 3.5 # Python 3.4 fails installing packages # # - 3.4 + - 3.5 - 3.6 - # Final Python 3.7 unavailable as of now (and -dev fails) - # - 3.7 + # - 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 @@ -47,6 +46,12 @@ matrix: # 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 + # Travis Python 3.7 must run sudo on + - os: linux + 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 From 55530c8c6de4865fa97b0b7bfd29c2985bb19451 Mon Sep 17 00:00:00 2001 From: 0xflotus <0xflotus@gmail.com> Date: Mon, 3 Sep 2018 20:04:18 +0200 Subject: [PATCH 0374/1182] fixed output for escaping rules (#700) --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 56c40e44e6..d6850af183 100644 --- a/README.rst +++ b/README.rst @@ -426,7 +426,7 @@ token ``--`` to prevent confusion with ``--arguments``: Content-Type: application/json { - "-name-starting-with-dash": "value" + "-name-starting-with-dash": "foo" } From e508c631f2fd0d89d23938d794435951d9888876 Mon Sep 17 00:00:00 2001 From: Matthew Leather <39400458+matthew16550@users.noreply.github.com> Date: Sat, 8 Sep 2018 05:08:37 +1200 Subject: [PATCH 0375/1182] Fix Tox using different Python than expected on macOS (#688) (#706) --- .travis.yml | 2 +- tox.ini | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4ad14764aa..618fc4f128 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ matrix: language: generic env: # Stock OSX Python - - TOXENV=py27 + - TOXENV=py27-osx-builtin - BREW_PYTHON_PACKAGE= - os: osx language: generic diff --git a/tox.ini b/tox.ini index 8c888ed40c..c394120e0b 100644 --- a/tox.ini +++ b/tox.ini @@ -21,3 +21,6 @@ commands = --verbose \ --doctest-modules \ {posargs:./httpie ./tests} + +[testenv:py27-osx-builtin] +basepython = /usr/bin/python2.7 From 37dddf5bf7a70c8c07bb383b3f417ce977befb61 Mon Sep 17 00:00:00 2001 From: Matthew Leather <39400458+matthew16550@users.noreply.github.com> Date: Sat, 8 Sep 2018 05:09:30 +1200 Subject: [PATCH 0376/1182] Fix for broken Travis builds on macOS with Python 3.7 (#704) (#705) --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 618fc4f128..90bb9396b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,7 +61,11 @@ install: if [[ $TRAVIS_OS_NAME == 'osx' ]]; then if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then brew update - brew install "$BREW_PYTHON_PACKAGE" + if ! brew list --versions "$BREW_PYTHON_PACKAGE" >/dev/null; then + brew install "$BREW_PYTHON_PACKAGE" + elif ! brew outdated "$BREW_PYTHON_PACKAGE"; then + brew upgrade "$BREW_PYTHON_PACKAGE" + fi fi sudo pip2 install tox fi From 2cd6ea3050b7eaee39b6ef3408bdba3c61a7eb79 Mon Sep 17 00:00:00 2001 From: Matthew Leather <39400458+matthew16550@users.noreply.github.com> Date: Sat, 8 Sep 2018 05:10:04 +1200 Subject: [PATCH 0377/1182] Fix some broken documentation links (#703) --- httpie/config.py | 2 +- httpie/sessions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/httpie/config.py b/httpie/config.py index 7621878fba..06ce586b91 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -80,7 +80,7 @@ def delete(self): class Config(BaseConfigDict): name = 'config' - helpurl = 'https://httpie.org/docs#config' + helpurl = 'https://httpie.org/doc#config' about = 'HTTPie configuration file' DEFAULTS = { diff --git a/httpie/sessions.py b/httpie/sessions.py index 69dc25383b..56614f2000 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -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): From 256ea7d49d5e213fcd05a384ee2d1195abf7b348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=BA=C5=A1=20Ferech?= Date: Tue, 30 Oct 2018 18:41:56 +0100 Subject: [PATCH 0378/1182] Add prog parameter to HTTPieArgumentParser (#715) --- httpie/cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/httpie/cli.py b/httpie/cli.py index f35e35a9be..98347dbbde 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -46,6 +46,7 @@ def _split_lines(self, text, width): parser = HTTPieArgumentParser( + prog='http', formatter_class=HTTPieHelpFormatter, description='%s ' % __doc__.strip(), epilog=dedent(""" From 91961c6b51b8ae091d5f674d70ea6af3e8b44c42 Mon Sep 17 00:00:00 2001 From: "Ankit R. Gadiya" Date: Wed, 31 Oct 2018 23:47:44 +0530 Subject: [PATCH 0379/1182] Fixed some lines (#723) --- CONTRIBUTING.rst | 2 +- README.rst | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 2d1edd5223..9ae0492a1d 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -25,7 +25,7 @@ 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. diff --git a/README.rst b/README.rst index d6850af183..585a0220b5 100644 --- a/README.rst +++ b/README.rst @@ -130,10 +130,9 @@ To see which version HTTPie uses, run ``http --debug``. Unstable version ---------------- -You can also instead of the latest 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. +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| @@ -435,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: @@ -620,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. From ab5a50cee8c2407b9ee8c10e4478db676f90f51d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 2 Nov 2018 14:53:05 +0100 Subject: [PATCH 0380/1182] Finish --style=auto for terminal ANSI colors and make it the default. Previously (only in the development version), this was called 'preset'. --- CHANGELOG.rst | 2 + httpie/cli.py | 15 ++++--- httpie/output/formatters/colors.py | 72 +++++++++++++++++------------- 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bce1ea56a1..1aa4eaf32f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,8 +9,10 @@ This project adheres to `Semantic Versioning `_. `1.0.0-dev`_ (unreleased) ------------------------- +* Added ``--style=auto`` which follows the terminal ANSI color styles. * 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`` (except for Windows). * Fixed default headers being incorrectly case-sensitive. * Removed Python 2.6 support. diff --git a/httpie/cli.py b/httpie/cli.py index 98347dbbde..2a7c2278ff 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -20,7 +20,9 @@ PRETTY_STDOUT_TTY_ONLY, SessionNameValidator, readable_file_arg, SSL_VERSION_ARG_MAPPING ) -from httpie.output.formatters.colors import AVAILABLE_STYLES, DEFAULT_STYLE, PRESET_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 @@ -210,18 +212,21 @@ def _split_lines(self, text, width): help=""" Output coloring style (default is "{default}"). One of: -{available} +{available_styles} + + The "{auto_style}" style follows your terminal’s ANSI color styles. - For this option to work properly, please make sure that the $TERM - environment variable is set to "xterm-256color" or similar + For non-{auto_style} styles to work properly, please make sure that the + $TERM environment variable is set to "xterm-256color" or similar (e.g., via `export TERM=xterm-256color' in your ~/.bashrc). """.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, ) ) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 30970c5d8c..4ea423fd6f 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -16,19 +16,18 @@ from httpie.plugins import FormatterPlugin -AVAILABLE_STYLES = set(pygments.styles.get_all_styles()) -AVAILABLE_STYLES.add('solarized') - -# This is the native style provided by the terminal emulator color scheme -PRESET_STYLE = 'preset' -AVAILABLE_STYLES.add(PRESET_STYLE) - +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): @@ -44,45 +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 color_scheme != PRESET_STYLE and 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: + formatter = TerminalFormatter() + http_lexer = PygmentsHttpLexer() else: - fmt_class = TerminalFormatter - self.formatter = fmt_class(style=style_class) + http_lexer = SimplifiedHTTPLexer() + formatter = Terminal256Formatter( + style=self.get_style_class(color_scheme) + ) - if color_scheme == PRESET_STYLE: - self.http_lexer = PygmentsHttpLexer() - else: - self.http_lexer = HTTPLexer() + self.explicit_json = explicit_json # --json + self.formatter = formatter + self.http_lexer = http_lexer def format_headers(self, headers): - return pygments.highlight(headers, self.http_lexer, 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=''): @@ -131,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 From a7d570916d982103f0e7273e7b37f15a87ab34c3 Mon Sep 17 00:00:00 2001 From: Vladimir Berkutov Date: Fri, 2 Nov 2018 22:57:53 +0900 Subject: [PATCH 0381/1182] #722: Add support for tls1.3 (#724) * #722: Add support for tls1.3 * #722: Document the potential support for tls1.3 --- README.rst | 2 +- httpie/input.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 585a0220b5..bdb99f8b78 100644 --- a/README.rst +++ b/README.rst @@ -927,7 +927,7 @@ SSL version Use the ``--ssl=`` 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 diff --git a/httpie/input.py b/httpie/input.py index ebf46df3f5..c753bcc1be 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -111,6 +111,7 @@ 'tls1': 'PROTOCOL_TLSv1', 'tls1.1': 'PROTOCOL_TLSv1_1', 'tls1.2': 'PROTOCOL_TLSv1_2', + 'tls1.3': 'PROTOCOL_TLSv1_3', } SSL_VERSION_ARG_MAPPING = { cli_arg: getattr(ssl, ssl_constant) From 96444f3345e6e17d7d9bdff82d3822dd4a47c99b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 2 Nov 2018 15:13:53 +0100 Subject: [PATCH 0382/1182] Changelog --- CHANGELOG.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1aa4eaf32f..217efbcdb1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,9 +10,11 @@ This project adheres to `Semantic Versioning `_. ------------------------- * 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`` (except for Windows). +* 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. From b596fedf1394b64a165e75d38558a9cdc75d2f90 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 2 Nov 2018 16:07:39 +0100 Subject: [PATCH 0383/1182] `exit 0` constant: `OK` => `SUCCESS` to avoid confusion w/ `HTTP 200 OK` --- httpie/__init__.py | 4 ++-- httpie/core.py | 16 ++++++++-------- tests/test_exit_status.py | 8 ++++---- tests/test_httpie.py | 6 +++--- tests/test_output.py | 2 +- tests/utils.py | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/httpie/__init__.py b/httpie/__init__.py index 0725cc1599..f4b9b04295 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -8,8 +8,8 @@ class ExitStatus: - """Exit status code constants.""" - OK = 0 + """Program exit code constants.""" + SUCCESS = 0 ERROR = 1 PLUGIN_ERROR = 7 diff --git a/httpie/core.py b/httpie/core.py index 8442d614bd..8ad0e2a67a 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -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): @@ -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( @@ -202,9 +202,9 @@ def log_error(msg, *args, **kwargs): 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 log_error(msg, *args, **kwargs): 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 log_error(msg, *args, **kwargs): 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 diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index 119b8d120e..02e9bd73c9 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -21,13 +21,13 @@ 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 @@ -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): diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 5fb045b940..c6bf00194e 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -10,19 +10,19 @@ 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 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() diff --git a/tests/test_output.py b/tests/test_output.py index d57e891cf0..26cbae96c7 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -161,7 +161,7 @@ def test_CRLF_ugly_response(self, httpbin): 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): diff --git a/tests/utils.py b/tests/utils.py index 0c31c966d8..c9b3575e28 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -219,7 +219,7 @@ def dump_stderr(): 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 dump_stderr(): 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 From 932d3224f4318bc69ab8046a066d65151aaff012 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 2 Nov 2018 16:21:06 +0100 Subject: [PATCH 0384/1182] Cleanup --- httpie/cli.py | 4 ++-- httpie/output/formatters/colors.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 2a7c2278ff..ac2a8dd78d 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -214,9 +214,9 @@ def _split_lines(self, text, width): {available_styles} - The "{auto_style}" style follows your terminal’s ANSI color styles. + The "{auto_style}" style follows your terminal's ANSI color styles. - For non-{auto_style} styles to work properly, please make sure that the + 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). diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 4ea423fd6f..d8ef808c20 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -51,8 +51,8 @@ def __init__(self, env, explicit_json=False, use_auto_style = color_scheme == AUTO_STYLE has_256_colors = env.colors == 256 if use_auto_style or not has_256_colors: - formatter = TerminalFormatter() http_lexer = PygmentsHttpLexer() + formatter = TerminalFormatter() else: http_lexer = SimplifiedHTTPLexer() formatter = Terminal256Formatter( From b5625e3d7562f8e2068bff42addb557f05002524 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 2 Nov 2018 16:24:35 +0100 Subject: [PATCH 0385/1182] v1.0.0 --- CHANGELOG.rst | 4 ++-- httpie/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 217efbcdb1..975d423663 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,7 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. -`1.0.0-dev`_ (unreleased) +`1.0.0`_ (2018-10-02) ------------------------- * Added ``--style=auto`` which follows the terminal ANSI color styles. @@ -340,4 +340,4 @@ This project adheres to `Semantic Versioning `_. .. _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-dev: https://github.com/jakubroztocil/httpie/compare/0.9.8...master +.. _1.0.0: https://github.com/jakubroztocil/httpie/compare/0.9.9...1.0.0 diff --git a/httpie/__init__.py b/httpie/__init__.py index f4b9b04295..36bb65955d 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -2,7 +2,7 @@ HTTPie - a CLI, cURL-like tool for humans. """ -__version__ = '1.0.0-dev' +__version__ = '1.0.0' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 2e96d7ffbbd4c7f19a05bd0d4d2cbd8db4105ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Fri, 2 Nov 2018 16:28:17 +0100 Subject: [PATCH 0386/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 975d423663..2dc482c78c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,7 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. -`1.0.0`_ (2018-10-02) +`1.0.0`_ (2018-11-02) ------------------------- * Added ``--style=auto`` which follows the terminal ANSI color styles. From ae8030c9302ef47744e39bcabdec6a7be44c65bb Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 2 Nov 2018 17:18:04 +0100 Subject: [PATCH 0387/1182] Homebrew formula for v1.0.0 --- extras/get-homebrew-formula-vars.py | 11 ++++-- extras/httpie.rb | 59 ++++++++++++++++++----------- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/extras/get-homebrew-formula-vars.py b/extras/get-homebrew-formula-vars.py index af44f156e0..2e28d3eb92 100755 --- a/extras/get-homebrew-formula-vars.py +++ b/extras/get-homebrew-formula-vars.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ Generate URLs and file hashes to be included in the Homebrew formula after a new release of HTTPie has been published on PyPi. @@ -12,8 +12,13 @@ PACKAGES = [ 'httpie', - 'requests', 'pygments', + 'requests', + 'certifi', + 'urllib3', + 'idna', + 'chardet', + 'PySocks', ] @@ -50,7 +55,7 @@ def main(): print(' url "{url}"'.format(url=dep_meta['url'])) print(' sha256 "{sha256}"'.format(sha256=dep_meta['sha256'])) print(' end') - print() + print('') if __name__ == '__main__': diff --git a/extras/httpie.rb b/extras/httpie.rb index bc323fa13e..1258b37827 100644 --- a/extras/httpie.rb +++ b/extras/httpie.rb @@ -5,40 +5,55 @@ # https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb # class Httpie < Formula + include Language::Python::Virtualenv + desc "User-friendly cURL replacement (command-line HTTP client)" homepage "https://httpie.org/" + head "https://github.com/jakubroztocil/httpie.git" - url "https://pypi.python.org/packages/85/95/7ccea3ae7fd1185e21629f6d14fa9c896d6250bb15fb492efa91edc741a2/httpie-0.9.8.tar.gz" - sha256 "515870b15231530f56fe2164190581748e8799b66ef0fe36ec9da3396f0df6e1" + url "https://files.pythonhosted.org/packages/44/ee/7177b743400d7f82a69bf30cb3c24ea4bb1f4aea68878bc540f732bf4940/httpie-1.0.0.tar.gz" + sha256 "1650342d2eca2622092196bf106ab8f68ea2dbb2ed265d37191185618e159a25" - head "https://github.com/jakubroztocil/httpie.git" + depends_on "python" - depends_on :python3 + resource "pygments" do + url "https://files.pythonhosted.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz" + sha256 "dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc" + end resource "requests" do - url "https://pypi.python.org/packages/d9/03/155b3e67fe35fe5b6f4227a8d9e96a14fda828b18199800d161bcefc1359/requests-2.12.3.tar.gz" - sha256 "de5d266953875e9647e37ef7bfe6ef1a46ff8ddfe61b5b3652edf7ea717ee2b2" + url "https://files.pythonhosted.org/packages/97/10/92d25b93e9c266c94b76a5548f020f3f1dd0eb40649cb1993532c0af8f4c/requests-2.20.0.tar.gz" + sha256 "99dcfdaaeb17caf6e526f32b6a7b780461512ab3f1d992187801694cba42770c" end - resource "pygments" do - url "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz" - sha256 "88e4c8a91b2af5962bfa5ea2447ec6dd357018e86e94c7d14bd8cacbc5b55d81" + resource "certifi" do + url "https://files.pythonhosted.org/packages/41/b6/4f0cefba47656583217acd6cd797bc2db1fede0d53090fdc28ad2c8e0716/certifi-2018.10.15.tar.gz" + sha256 "6d58c986d22b038c8c0df30d639f23a3e6d172a05c3583e766f4c0b785c0986a" + end + + resource "urllib3" do + url "https://files.pythonhosted.org/packages/a5/74/05ffd00b4b5c08306939c485869f5dc40cbc27357195b0a98b18e4c48893/urllib3-1.24.tar.gz" + sha256 "41c3db2fc01e5b907288010dec72f9d0a74e37d6994e6eb56849f59fea2265ae" end + resource "idna" do + url "https://files.pythonhosted.org/packages/65/c4/80f97e9c9628f3cac9b98bfca0402ede54e0563b56482e3e6e45c43c4935/idna-2.7.tar.gz" + sha256 "684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" + end + + resource "chardet" do + url "https://files.pythonhosted.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz" + sha256 "84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae" + end + + resource "PySocks" do + url "https://files.pythonhosted.org/packages/53/12/6bf1d764f128636cef7408e8156b7235b150ea31650d0260969215bb8e7d/PySocks-1.6.8.tar.gz" + sha256 "3fe52c55890a248676fd69dc9e3c4e811718b777834bcaab7a8125cf9deac672" + end + + def install - pyver = Language::Python.major_minor_version "python3" - ENV.prepend_create_path "PYTHONPATH", libexec/"vendor/lib/python#{pyver}/site-packages" - %w[pygments requests].each do |r| - resource(r).stage do - system "python3", *Language::Python.setup_install_args(libexec/"vendor") - end - end - - ENV.prepend_create_path "PYTHONPATH", libexec/"lib/python#{pyver}/site-packages" - system "python3", *Language::Python.setup_install_args(libexec) - - bin.install Dir["#{libexec}/bin/*"] - bin.env_script_all_files(libexec/"bin", :PYTHONPATH => ENV["PYTHONPATH"]) + virtualenv_install_with_resources end test do From 698eb51e60a29e718c100b46f5b26c2843980ad5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 3 Nov 2018 18:08:43 +0100 Subject: [PATCH 0388/1182] Update screenshot --- httpie.png | Bin 186489 -> 697537 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/httpie.png b/httpie.png index 803dc538b2853f7f79537b7b73796478542f5e49..d87eae38850e55acbba2cfb4374127241f8039b3 100644 GIT binary patch literal 697537 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�)*F#7|l1 z=|i;+Q8$|m>%sR}JXdvP3X9t&O^F#eh$0x6*D-`>m?J47{cJw0QXZ3g&#wpde zBHl9g18`xe$(Zl+oK*{930z;fkPO;5jbbozL3LPf6jz~no4lw^+Dj%Sx(IZk*lHp_ zFhY$Rfu1pHH&Y@J*QTL)F}ijW#l&<@VMhOW$pB)+At`P`aAJL?1SlO`_?mev2n64rMlx znh3HeY^)N;fk0}hcZQ-^>F=Z2pS|;^S0<+%`YecFE49!AUxmjy@P*2=x3|w9{B_d8=Bv>vM3srixRuMjL6c&j!N(eJrFA0YQGiar|e?Y z1d_i{fe}JjLxX0~r5p5wO5< zwpdT-Osw?&J;@h)lPIncB8YIXlh)&%dis%A@WFs+WeGafy|5CxWKDwK*<2$ebvG$S z?b{-V7*#zNEq6aiQ&3?ElN+L^%qI0nOcNuaRV$}TOy8Wi7sS$)IusBDWPbyRW@hMN zLq`iGQ%j{(%F+{)suU-eK^ir2y`HA*bYL#{gZ}AgluU}3{+3dQ!u0Zdx z`3cnVRaM5iD?}QxFdKL`X&*o+?ZlW9fsre!LTDH-$5_bOTQV#ZNE?q?zv}f>$`I)z zR1)-Hj-j0xp$V?jlwjb%#Z&T_(r+*uY8A#`L;u$1I(y`qM*49 z8@PT}8FB|0d*NZwGm64Qe+i2fTBJL?!St1k zO+15_syVUC3Beh&M%WOZ&TsN)moFc2a_9Jpzy%10jMeQ>EBj-iv6AOZq$Xb0F;;7dGvgjFM38&8srtnAvc-9kWc^^61n1*nv+kjZF)Hg8~f$$Ee3E;?I)Atj*^q#U1TW1|} z{iSi^=h0!2be`x$X-2fQqjLcWwM8yr*pD?ihuk^GHy6+Z!xHS{=%l<9>T1Z+Kp{{sxH8T3Rs5~FYD zr*18NLzcIAW5|*ZF1tp~=TeI<4n#84-H0cP<;|Vct@a zDbhxo)Rs0W^ac*HO`mksq}^K}^#L2BU&nQ!!CgcslD$!fen?z626t2)TQmRg#{zfE zBqe$n|I!1HDCd*f9fFUrCh_q;n2YxGagsyol*EJLe&#-p1W3ZcOtkykI&Vk%{Bl2< z3m2%jMPVO3cKkh@QjznE@96@3aS(V$&|Djtq9md@V1eg}XWwB5&fae%gK|6eVY@k; z9`?3hIHeW)CBE^JW`A4*^JE@62Uve5V%Z*1Sn`yM&+%3`wvwYLdp9*u<(eHL`gm`n&Fp|AZ^HpBpPi zd9Hm&J8yd}W!f3$`eue}beeR@+3J8W)A@IS%)}W7X&tLdpA-}AUB71&m0-Xxh4&gD zI@vl+<@d3r8`|a~utp5{ChKm8Nw7d_$mN*|k3`cMhfmNabM-w`lwn$*|YXA2;Q^#aCroXU#(bxUBwKmh0q?4 z4x!4@r^eekJ_dK>WY#$r6V*x-82|AB+8wodx_3${d4Bw-B1ByVdWk71+lhyWxX}%U zrK#mJNUx9RM-mAX`Z$CxBiUbTD1vojf~3}#6&BZrSZk@g3+;Vv@Cui5+xO)$2e-N_ z`n%OgsFnOP+w)oF%5zA4yY$hz`Bf_Pnxr;)m%;Q;+3*qVjxDE|-HwasY)6pc5m72U zwC*3Hx)>N@NUX7gSTiIhJAT>(Q7Qr#zRY|IY+R1K*CV~+P z_mC|hpYstDI#Xcf!-gShmuWQO#;iZ>-^o)N(QA{v;+(s4BdQB#3B3DMr70D3aB>AN*%Vgxzn% zyN>BN@QorQ5fh@y+nzc;vsm0UCo~L_>I6#W_3kcCEnU~mDdf&+TRYyS!=C&UHKiIA z6o>$#bdZ9){K%(lE{An+^*A9{wtvSw=0TNS#EM=e7e2Udy9*)_aTQ4vN}9PNf0+M|CF`}Qvutx z&IM{ew>11kzA?&BB{ZDG8f^BktaSE`Nz1OKH#!aM%?>k6`h4yoGsx8GpSUC2y)H8) zYTfV5q4j}_mRF?JA4qBbT}&)SGp{>?x!;5T`SA_YcTnqhx+?EeC_pr650B(~KRl?b z>D2UYC`pw<6=6R79oP&{7=0@)SiVnJ1kA2diwZ-LEN0Kj389|i-No{L^@ieVRK6=# zJ9E>sl7Snw1DXE2$uME;R6%gU*@Xc;t-S=_^=gcuzT+9In0nY#LXuUArNa-UqC+&7 zV+lBZfZ0t%5pU9Fo1U4fDdmiFDU?wO_d|4V_&QH?Ng(RSaq;GP(ZoRb8im65hQeyD zy!x8tM@5J5rQ|>1(!V)c2i#+#I(y$puR5zWb*#L9^f1LtjF0IR7s3@f^(-ol4)!Hl zc|vw8b;NsP`b-0>01Yv!VX4jmI?ss+sL-K1p2378-&@3%F$6@8<||oq8to?4y(=Xn zJZOgEU~heb_qe*P+xhv@rnBVW9)-ln+2m)r%*VQy*^ z4dLgh7CcT=8T*$|I$|a))OfSnt<}I2aA=W)i4(oTV9e_z?m?_W#`*|JflhDityEHnM}ZsagAE zM2uV3&;}%*Iqy=)G&xF=z&r)PKoPcvE>_8hb6Y)*iZa|_Z$T-xdsXsGbx-K}V+`3L zmo-x*B1G}=XNoMR^X)%jt>3{)JWWOmb`nP%0XpU1QdXKWq@j3F(drY<2YsNYMAAs| zV+d~Bzwm%*&4Q8c7ch5>DI=euYAMZP*k;+cNo;^ttCrU*u$ADuff^EzvCHyPN4PA7 zx5P(*;!qLByO2!B_Mw8@^;%iNzg?C$wsUsBfrJl`#gExvxE?!21lsaHyk39-i(Q3x zBH_9Y?K)U(WO9Y=f`;X7N62q3tF zk0D$aw=aA`X!E+}w7pv8_fTdsTlo|`&!KDpy1aIyU3E`-iZU&Fr4~Q?sRZ)@yv?`n zKOdK$$m>8mnPBgBK8MUf;lx|6Q;*=#bQ_@6%1a^1g7D|eJsq9&d=^vdHKZ}eJ90!=Auk~se7wA?hWp2oYqGoYDT z>0S%J#kYCy;B+Xps= z-LJ$64s1iz3{scoXB9!j2s7A{{pqZED*HgXy(bY`MmFz0Xr3G-Emk5K#L3N@xif<+ z$4FmKJMG9cNin&QP(4U#1UCIAAB%`$ML7jXH3hE$;DU``mx-K4VLt2ai~`G|FE^|! zzUKw-E;vS)Et{TeP@b#qrb9F>a&@A2Cj}}%>U!MQ_wLj+hn7pw;s#cSTOTdRyzBd` z2)+{SKBsDn$7rm<{oh&;eRy%G#^>`mZRR7CxL=C9|gi0my-Sg3SZiF{p|=9U`q zC`3gixsub8q^qcos5_^u{#VDk0lLKVMY5L5>JNI)N(Br@w|ckAfIm9yc5aD#DnxZ?aDG%XG1F&Zfq{{)o140lk+ z`3okz$cnq;NNERN*BF`@0n!=fZ_8MpCN+GdAGpyLgiwo|2eqP!AIPQ_?rbr|Zl4B` za|5M>%$919AoD>M@5(7w5Yn4(p=}U^_oj(p81Qksd-=_N3 z+8{!w4lBQj|As%3f`g=Nf$LcqTx<_WoUr?EA}XHvwfng0BDZ(zVN%vTES`K>@VxDQ zD$`leSJ%g1}jdhbvCVh3O$yOp9p#d#(1m_a%W79e$B)IbNi)0#2`Q~;m z)stp9JIqvxXhDCBy|!<}2&R@icZ%-^gHINZ6K@ZGce-{VJyQmJ`&%pH@6QAI#>->Q z&BAD@d>YB^lzVp;2n}StLZ9{bW_VY~f-EQ$I!2H~w_W}Qid+(~=7u%b+tM?bz8OGd zczN*0Sr7bT)o7n736hTaffYOcK9wos>5}Ktdyz}m*$j~KQA-e|_%M>cBy+)b{q5NP zpA`+2#g{&L7m)O#ZX=7(>4NNhBnIm0 z+{*hch1SzNEH?D1^U9vXRb7d34Bi~)SQyH*LO(+ zzCs>=vMBWnjxLBE;J>4Ly)>yRZJN)#_9Nn)MX;oS0B1iNknKVZIp!Sg!E6O`f+g0Y1M`C-g?59|dLy8+$q1ATJ7+bzH8m=<&{?-IR}5;rw4ZdER~9{w zEDis}XA7>H^flw8U*qLuL&`0w%k_baGGY`2&GPU^!g(}8W&l#$+t@aYXr z`5;$hYW*&gBXy*zjv3xvWc!P`S2&fTE^*Ub3qBQ$6oNNOz#<$S*5LuC{u&brTXXQ@~t|^ntk$?{P z2Z&Ut54gd}>~A0A1#pXe=~b0=$6C5Kx!8X82HNG(DNxnEcNCL`@_v+oevRd4nm$!L z%Vn_`{$~Vl88)VZGV}hZMeAT-M?C#uuHbn&9c}2TAu0ISbKc#yWnCqDfKx zw*&E?rwZIg(hZMfkor~R0H$?2g*o)x#@PgIqSBG)|36& zSEKL~S8GOtaVl~MqOgJtP#M#=n41X)9o0`$cM_mZC=gXlR(`Y|s`NKN4O-rZ4`uFB zMva>|+T*RJ94-FqYt?+0jw%tkm_7#8EVp1C-@#cjGkP?8jN)fZ=5B_#{}6_Jj@0H( z9`N$u34m&-$z0@It5@r^X?LHkdOl}K;LKy960&JD02UN=Izqp64q3r*Ang8+`+pU) zmg^-)7;~xKp1y(fy-nimvxL!J_pGLV{;Rv#&0|ucVTUoT(Br}M(EiaJq0^mf$2m@V z1)CWgIZW$W&`zs!R#H{EbR=+}KWsgp6N0*YJmJ3vDIR~tLJ7xFllrG(eeG z8?>B$`c&&=?I$YOu57XdqSMHa>hZ3(^+ke%jT%2ZZ4?b+&unb!K-2<5HIV;dL!d@2 zd~vB-?ZP4LDjd-~YhMWq4LaEwB#`r9n~Vs$4iGQu`aee`@U5B{i~9-eXOk=o7!_g% z3OH78?!o2B{9b^v&uTWY1l`1Z(%;G2^{bW=uHLHJE_7-C7STyCt4_ISo|^JG;b8$$ z1vaEf9Xss}P|V~osU>qr0S!xo7=-LF9D!9f0cW=_N;~=D|DXs^(WfOCN>7$Y{v{FU z7485e0@t`Y_5VMKV3F@=Dh?$zBn&=6)kL~GVPzbZsrFO5AHOAJTy+1(N?@O-s9=0Z zv-?a)-wj!ac%X#;>LWU2H^lL8Y2%j4`?90O;|wf(XLn4P zuhxs=bW$yAwJy0x5o?fMkC<54XZ3Qr>?*F=AvOo^H0bcYmMZCk5o^*#RIx)`2!kRC z3L=U_!AJs`C7EWbKS~77HXAp*$LR+)8IPxxWDj%S>Ovt*kt*T$V(Ur*s5tu##@h_4 z--wPe_$)Ks7&a_*I>hxSMdJTtHK7)1C2t)UbBk-`Qi+j2(b0+tP?bo+LoAYBB&XV0 z-@~0}WZDA9EXuY!ikJ90Q;9Z|7z3hySP2GUTthML&>WjQ*C-8~U2-_8 z@&5_9cm9m{n)?D^|xvPEtr3(3* zO|G&PZ6Y~X>H0{oo`X%@4^$XYuc6z-F$vTJ+yuRW z+pq9%wnUAf(R&gY$VufcBBUr=m7;q1WK*8eBFDpX3{!rff2kECz%Xd@`L#^@ag+(` z7Hg}aI_ z9f7+GWwQqjcn*VgjNru5;PS!tym`Oyz}~B2R@5hmUAkSX<07~5OCtedZymTA7PK>Z z>&1M`wbDV>DPd2TM|Fg7x5qyP9!m~$P=I`@Y6Ei<34IL5v&C&2nNqQwhz=^Kx^G~(`UvCQYq11T8T3zuW zj3!|@IYeV#@os1=SMxBj(!Iom8kj997;#qBaj2PcxZRVIw=i~$wA2}HJVa)QKtLO6 zj346m?X4$tEaj_!ALKN_LgoJ)Xwj@*H$Z__q$U7WR>#{`gkJURg~gsev3Dhr^)|&` z?kvv59$H3Cg*aEejInbm>HH%iH2t;ptNVAj*4LHbuJQD{+@<15RYA9M`F}qGTX26T z>7b)6LykgqRMp^EjJrxrj{MEUfWLz%${NeD-ZJp+V*TRZ{^m!`_;~sfW?>a2lw%%V zCVP+@bP>38JNQgFW@rbMRkJxhL?-Si3TY95U+?{l%eH$3dJ^4$-_q|+R@e)xr~l^wt4-F+vLBU}ElNJ0;!UecO1^KsYD zLC~`c&?A{QxWyj#N`*lJ@H0%lG1BYHCRv^*E6jbw9d%QEZkbQph}cCu$7 z`c%%O+|zD7&kS#&P((bxs#;*o;TMb`^DjF0*HwRB`xO=>pTmi+kSPE*?cVIb3{HlR zW{>&6I*Eo5<9Bv&9|^@NyOG3lMeIN;m?~WI`6t57v1jyOC<-b-0ZxenOpgCsAimIb zr@jT-WJq+?bCI4(?CO-unGz1X`f%=51c*NeVM@LtZU{V(-;;+2Zeo!~Qm4lnGTk%J z&H3pkoZKz4OXAH7eU4bj*DfWEM)J2?uJ}DKOaL&Y{UFr0JAf<7d8dQ-t)Z6@rqYMw zgQwC|M3-*twr+R5#v%77P8{SN*{z=x4+4rq znH$>47P~`~;v5*6*g){2CVb6z#b^1zvf}_oue+2hsr&cN7*WH^qbyb8n#F{XJ7Z;O zwjlFii}=_{0D~9$o~hH7(k>kZ>AOW2VJkRd<(JU6~h(}|EFu0 zS{$XrXrs|HhIiv6CKHZ9-=g^w?M)RBx1^ zE|~&RpRCmod)TkpF@XN}{z-Z|QE-Ok2sN{I6GRU$O1e}>mTVA5zDBCWh07kR&bdk8 zh5*IS5++FxDHZq-UF7q@#H?5vU|+#`DLt9427qZIV0U*_cZ{%q@=2`(=s75WaH;2- zyRNT0I4(%o3fGc_r=E~Igd(jC;mH^61n+~HlPJK|%D27Ug>6K&oP>-dlbrT)kk)+u z(~j~_8zV8aJc{qYw_iV zh)w{_!Ft0_b`Y?OzUo;QU#FaSTys%fff4+;a#a`6a|ci<@~o%(LaIbhsv0JKD1Q6_ zaR{B~0tq1ZgvH22D#q}c>FHjP;VQ+IR2>d60As@wHly)>ekmk4OUU)D%+cS7;k4xI z+v&h(O;yfHxfh}>?PxjumdFgl%5cO!Q=yOB;HYeoGeOgrk(8_^Cs11GrrNfzt&%sY zy5)V=Fj}>h7IB;F$Aoy4>nj|_@)>{GRy2UvgZ)KUsPg&zCrBY%23{n>zBVu<&ageD z+9S*MH5wbMLJw8~pQWGjGnH0D$Zvvt!A1$QevO3|HwwGVS5mvo2YM+_d(N8^tA#3& zET5svG4T8K7o@=F?B+<{*#f1Y=KXc1oO9jAtsvZM#4A6YgegEwWyN@`=1(}N20GG>+6|FKVKd{`Pvov+=3u!k}Kzr z&dS|i@rUanyaGpBd?#*qo}Gr2is91hfwlpcfQkQ~l`1q5DL%L^O_VO{SOeGycjyG^ zdzgy}O#CQ5Gv;B0W0jPV*7ZSuUf(E`j;&LE_u`G^m|AZc`hFpOxwzFz&NSC0xb-XR zuWR|!$Hn$tV)U_4HnpE_=S7WQo&u$K z-op$|_fvLYQv7~({%b;>wt+>(uGDMNk*lMMKVQYq@!vDo8YDxC9LtV(iS+CtG%PWb z8re&_`;w4j&}NZcv)ZDm2~5H2m=*vhXuEC{ruanf^YimxtXI=+?CG9Ge1H2ou--FR z6R=B302vOHod_t!_#y@8uQqGwO!u1@Uals`Ny4+*uvCrzFGj~0;7TPsHzfC$G}wJD z!}_?C{2eCBe`Trj?4=9kIxrd;|C^C3&J)@I0@_k9T^!Y1W8v{O#4Y!eocO6qDp9-9kKNpcUhD1l) zVU6F}>uq-!o+7B!?{};|Jg@eTT@T5EL)7X?@a|b8lHE-amXk_m@<_Ed$;@-bn9zdd zXQ{~oQ%mR3SUg4GY4-I{k43YgjzxU1+vMRJ65tzmEpcK39mad+1w(nxh039J)PH7| zEUNx!_4<|iL?-C*G1i)nkoWZs{G2ktO|39Uu4xlfVz%`9O? z)SrVEL(ziZ^1hPu%7gohjbesGhpdeFmnC_c^Be#kD`^Z$3C}0{;aBCzSmyb>&BjSn{h|(gZ)jy;O0`SB^hH%k#7B8({0) z5?OW2b(pr$P!56si0t=lK-@D{A*cE$9PFd{M+M0e@Vx&Ej>W2rJen=*KA61wlf{3% znZj%sIdB&Eq74H?@MdvE8_+A;1+X33-eI>z!YzFRHeNXCnFd`XfXF2X|G(teyqXYV zOro}gFV@)4kUM;7r~jg3<+t3gc9b_mt|9zNSgDpIf_u=|;;~nJwHBk{x5w}IUYCLF zF{{5y_xcP3>pCE|f<91G$|7Z>l^P@vS@0UV{H|iiVW9SLLcgMk9i@xuPYmAB~C;LhKHXz)5 zIGvF$9EXukX-VmfRWO1VcOOUC$Pg;8P(iVwF2%9Md`L3;Ek^|RZD!Y$WjNu0c97C6 z0ETsKDDIty)}v&WpSMFQvYC%inOzFO>zDoB_X~4j|EuCYE{7rWCY{`^BrRUJP53g)m=OWYp|Qi!PA_9aMNal0%@?Agf$U8FkPQo*#Ep9 znh`aYjV%DFd!=?^Yg8tbI5OUS#;D=FLQnN4_JAP$K3~(7;xdf_oS@MWJ?;Jwqxp(e ztSA}dlZE{hfh%OA%SFJ5j}I?`eG3>;2>TMka|0d~%?NlL)G6cn_ncJCG#cJ{oVez= zUfL`Y=BW1PH#)Z6LT7mzi0;?F9Xp_R8Xre?l_n|4fe~@qz7+0VY>Ka78+Mu?#%2vrXtej_-UCrcO!lTKIc%? z(ercCf8DXY@4RmD+E7u&6pO!Be7}zR`g|U$QsiPjsln)Y79)CnlQCdNeb zKlj)YjkhQqs&&tO9o6kUPCjTX%u?ZQfx3Hmx^|T6LvIK@_c-;5wW5siDcHddFz`b6 z2fDyj4yy=N>~eGO@gL=0GPF8;QBE{km_ z_|vRxK%fm9=`^dOQl?~DLg83TM%~9sxk&24p2JQvcOAoufax?wE;{`eTwANWO--Ap zzWPJ^x;Gox_p5ENFWx)yRoz8YiJuU<(*Rw!I76jb9F=LlP8g0En*v3$fR!?=?G8O` zb+|Rz(OrqOFcD%a>VwQ1@DAJM{jbn0n|jbD$Tv@KI6lhoXx2t@R3yDKT9bmM#)BJL zFu*?BYxqq+br42KX@U^ab;lE#i|2W`ODfhnmmD zin<32=WLd~yXPI<=jX~WpWu7{`|r^cLbz14(=tMmI7G~2^*%ibi6=3AZhHnF<;Od5 zes7M!M<_uVmbd}eQTR&S5Z4$kk9hUI%;byI_k}K!H(3&~lq2RVRwEI*aOig*PNzZJ zOulVWfXD$jF~r*fp&sP|bgwC9_x7a~56t$kAED!(nZBp$p+p|#U*6;<_KC22(Cqpj z{7s3wB+$AWO?1=Gyd{FJZ-=U8s-~I*K;A)^X~0+a>+G7rZGHt)eY&ZRLO%;XEIz% z+7>4T{s~+MgCK=Gs#k3*D=TJmP|rxM!~_-Boh}{qDTsNr8`Y}YMqA6262)V((HSsB z^65D6oj}(WBk=hhX1r)SX_oh12M#eTDes|u((J{mrzk-^rcQ&^kCPbJB8Bf$SU*2Y z+64mKtoUgdtzQw{Gt5kEPc$v3_miammsxkEQQ(ab;JAXRb>F za63XpeRX|T_uEw{)qY04Ril3TLzT^zR^;j0cK}iR#X>(mR307YR&ZjGZ?_9#G-mlJ z>+U^=Hrn~RGi%oEy;jNeSyhjx{VmBvjV$Lk!PDBhQzPe{ZAW5;Xx^Axw{wbnyB#Fs z>Hn7Spq>yM@Kt>3(am(Er%%7UEwU7G0-^B}A=ViiLRqNT5CwFt@_DRvw%QTj2K1lS zisIf!=~-bf5AlGLkNwD;Cj+OjKupXRI`v+ZTFC1nDsiNp;^)K6` z%>1OVj`cDq`yaXh&Ji&Ak*4oqfEEMSzf7$uS#l!=Y|3l5+AO>l=uT$7Bb?LUaL*^> zQb0lKmBTkC=y?_f2xiP*Vyz{oqN>~;8e9E)Y4h6r7*XLBY1?1Plq0)Az zjaYcT=poYnQ;CkS;e`($%%%%9>gY`(fsd=LC-A+HC0p4!3%N=6edkbP?nQ-GHB-5d zKORrV>0*z9RIym`C!;@vj+U+23Y#UaoK88FkG@~G=n^AO7GXb8dJ`eEJ~dzKM7-?p z468crcoT}ga08xK3||pemSWQjc6@sF`8B6OHR1w``Tn3X zhl%DKg4*$8bigzN_pZiJ0LRWG!EyhG^*Tb^6Hb}|3U+%uOQA}|xCPkyO&!O*fKD=p z*k9>lgOG8QVM#v<@q7rx@JT z54dFucJ#d1VRcgZNBWZP-lN&@!Zj+_a_>M^Hr1>^f3dIf=^XTtwy`j>*$=|LcYHfl z5s6Dx$Y*3PRSS)-`vo9i=r`8jDk3oNG87(_AV%(7{o8-RuZCfhOj-W}ze*-5n-4`E zIK=La4I-m*e;Lx`Dy?nvIJ3Lo9YwbIj};KGdx56bQ)kk%@G7C@VI!eu%3+6KsNkQGHKGyX~G=rOXlFt0s0IObpD zJ}ARbm7BW6;p->?lDyaO(59X%s@Uzp7qQAoc(ddl0Nk-Bbik$F$d(%Z{KhNhrBYm5@saOJfX~k?SE`2} z9&zfwG^Fup&X(__R6T(q%7DFybR_dNVJQ&Q8#Q}fu+ZX3S+3P2pxwGKhtYPbF2Ku# zMx*=Qs^Zv<1Nq|&Lt^J6QDy5@1Mvin)Y+Q;nX5)IjQhjKdFw4Z$CulW>mD%XL*lV@ zX`h;W`j!Xr5<82v_@0kbA>$A~7B?jU6cvdQzuTiKd&M>BufFSUtZ=UK^nFyxsJX&7 zP#Wp)3A6v(euSoxbNFf|1GTzW59LJ4U+zCRFS*mCWSCp#c3=amQja#6bXnpPvzY!4 zweWcb4;W&RdmT~J!Fw#ai`4X7vZr@d#wi9-?oSh7mro6a8i=q`5$be*Y${Gld6R5lQJA`y+DOF!|x5up2cc1UgO_YL;4Txmfz6+ZcAKsth@0%?~KyJE{_c zJ}A;-D6i>^-`CQbb&H);up92}&pVN=l@Q$PhChEkB^wGLt8cB3x6gk_^g2_L9Im;Z z{g?()7V0nm#%uro$olH2DA?}XA&2f37*dc<>7gYg1(cHRk_Lepx?82B1pyJHQ>0-i zX<_J8YAAsrhPd;7_j~W}-gTdUX4c{_)-&fh=j^l3-X!6g8N6uw9HS!t>W`D?y+r+5 zvpG`*uAXlz-#31?tj-I3Fm=tm6u+EZ(b0#+bGmSIq>3|a;yetPb=KGaupQ28OgUI+ zAZ&Eoo688iyU;M%VUdOFeY-9mKa=~KRUyy7YlzE>&|Eq+X&6H#%9K+X9{d8iAn5_c ze>0YCzs`;Y%H${wm^Q5#v354QnRN;LevLE7Tf}Yo<5@vU#8Ze)bc`C~q1(gx{_|Sv zDfvGUqW=;iJ>SHv5CIsnc?gl4y0egV@0a9y)Z&3t7G`H34IdR>U{&O`8BV7y=lZ@- zN42g0v;ct2o(AVHmS2FK!L+t)+ZT~YXVU8k82sr{BIONbwsc^iLOXZV zarQFKzph;q&5!QwWxJYSBJBy{8*_ih5Tz2UH9wOeMohugO%XnreaA#yEvSD0y*wg_dBFmwpxIFHeO07F^=*WFWHscQb z{6_YNd$`ytoBa}EW1Cdr`;U|;lGuEL9$Ck^P@!^hT5X4%bBm^}g^Pval8eszK-cQt zUTU)z9^`{j+hJ{AYSeA#omFqnj`2Z4reL(m1iB28B>wjx@W^zl;U>gZTzTopG za+2rsNTQ7L5)qoitF|(*=dmOm5*Fr~Jb$Qz%nX2$ z1Xt>h;2B{{#bZ1&a=t}HZ+n0)t0G!*Dh(@7-q4O8rAEBh{XeDoM^6>n?be1|#!kf(({t)Q;cBwXyC?{~kk{t8O~IJjG=KJ`gx ztvm^e972F1pRF-Gv|Winw}0n_FCJf;BVrYG7zasj;N=Nez{;q-d+DD`nl2{;Yz(2#dMv|sj%i!SbdBz;erOb& z_OLV^pB2wV^K-?ghgO~*-J6Y>tn!!u^`?&ig=%{anIn4YG$xK(Ui`d_x9gwe6b|+G z*{*BcVt+_{=)ttFR$>e6#{Qlopl0$G$8EI{XRc-q+jXug8mCJj0=;Op;BU;*&(Zbw zaeF`=0VdIN*KT#=r<5|%2;O4`3Y2SE-G`pQ-wo}gVg4wc$PWErv+(TtfitTBwtBb}$HVmJ{tgBd;))uwuf?$t6ggEem>##2`pWLR z4eibvEPlJ%sj=$IO+6iZxPQ3J`=R@Zp!=(ThmylmbIMx*dbVG`roCG~ebPai`tgNb z5Qfgv=EwZ^;Nq0c^k`J|I&$7xd|(Em8Y`3;Q45}AO0}M?Qd?dC4Ai`5ru=H^3+nj$ zb)*qe+cV*DZs~(@A{E!)7natu17Ko1Jz?8@f+BD)4Hgr(6S#<0I-k)=ER`n+MTNzj zwM&z`;<> zT@xlc-jU=c=s;Q;%hG-n_j1UF=pBpjw>Tl^u%10OF>JZ_vFFOJ7PqN4z&1ZH6=RS~ z!w*eD5_zV-m-5V*3)S6OnHyIf-oI>&PbYna*qdmrwWap0zG<+YoQn!7YilPL5HR4k z^<9Rgs1-Q#(@xw|5p)Hvyk&oZ9*F}*e2QRgEgFSc0(r!bRs*ScGGY1a)iFs;v0fFp zy`Pshr$SN}PYJ~Bf6t-D=Biy+z(0(5uLC9A{a5@qfX7PqUc!hV1itxIw)OPqtiF$y z(3pfzY>-oDr~jTwHGMukz7U6q0wAiXLMI%L%qsSWdM9zXXobRE0KosaYF`}YN) z%^C}`j{pU4)6D_1^+T~CB>i9qq0=@v>|PCE0?&ELa}|F_L(MlC9`Q%QYrPvFfdBV> zPb3ox;Ekh1M$Cfn>puu1V&fx8a(>%iO2+Zja{%*?l#gthWr$Et3rbbzhV?~DE-kj9v*xwiaOT&AS+uczR z?q=gUz8C}*_^CFkWlmo|ER%`;78m^+BDd*?eFA*i-wAl(876}wp1HY}m^?M9j$hYQ z0xA-Sv=*S+OUgVWr!hv;7MgS$NT{wv>#q_c@Hag|cJSfSJ7@6g>brX$QBg`Aso%z~ zZ-0LDJ3%`|AH)}@r%AY2?n05t>u0b~3*MIk5k?cs70XW>jSk5KEpK?;0`IIXgxOwG zR=a5yeEgJ5bJ_LkFfjTZ|I=iB2a88w5JyA$N?Cr#!{Y$fEu1%9!(V}LS;_rY%Io%| z>|`u~?*yyuH{K8omw)d{2rY|IaX!gwK!Gn$7k2on&jzNSwpWMqo5X*}w*0#%!ZzIw zAqhij)1tCT%;A@;sH>}z(olFO&#)wcPWu^NU8;$ylWOD$*ssEB?NjP`euB#J`9Bwi z1sWRJHq?rAxHE8J0|jkp1%aF?C&T*0WZ<2oc2i`CDAEYVpXX0f!WUE9;k4r+S{LlN zlGS+KNQ^ux^;Q=JRqfLH)V+63!<6o7%6+1A-!?J6;4zI-1C$H^K*CxkRx-x5i67dg z+Ex$Z>a~El63c3Rt2kT^N7+AOY-Tfu6sSiEVw4KI1V!t3Bn2nyfNDuV+ox_8V4Bm& z?5y$=R`Zu*qCLEs0~XIiqu)jQ1ctHvivJ6@C5?URj;K1~DhwK)u9`fdd24$a%dDPN zj~#fQLr<ioIIfu6S8Wp z%DU{Cl{cI;HpD*Re`1t6-FcTaO*$MgzEqIhtAi+yUu7ZK6F3vSn=6dE$UsxnssPh7Q4PD>v zO;exjm0Rw=U&3>eI91;bnm&iqQa#}FTAl){T6fr(cfFJ=TH_K46Cuq|)VHrbg{*Jj zfd`PEnHL2uTht>@hg0ss!H8jAjO9tlIo$!o==3SxE2Cd7?B=hDK`Y+ujHt;i8l0(B z+Siz0cg8iIOcoXY_tY6+arJDfyxxz4VE{gcJW>pO!cSIB(+yTaob`s|jUmG4ZBes5 zsZ4j|(GY+XKEo0W{2T!%jWCxB1Brftfa-KpX%$Fb=soa^OH-jXyPqevl8Ju=5@jVm zC2)C-0mvC$1GJ3*fRs)eB!49PZY{pRFI$9A>6v2IPHv>7N`AH+`8;-}ER1AA#r}gN z2EvDuhxiX2&JniR!$@sERSZIAZd00%xG~{OXE7nZxJO?#IZWpGibz7gV5O{bVPbcf z_Eg;Yx*AtJ5%9&v-%seebLZLKwlf<|mAjW!DQSP#w<0Zc$}B0+zvKIU z)={b$aaH4j&GYKPng5SSu?y{$&yvE+hxEC>%?pJ=Ybk2nrfo{5%tFqgms|L_#cKtW z)xSTlg=Ey{`*qzBoLS^p^OrleL|}bue`)#t-ylt=25nP?AFL$DpHu=CihSCfW>Qm7KT){P8^t_g6}=NWw|0 z;>uO1r}w*PbA-W#cb#QX&QfZb)7tEodY>7`nP&MPA#sXXDYg>%&hh)?(i`kAi?B~a zI%{2Wckquu+2)xRjhcmze>7g(*16ImrL^XCeX9C#n1ixoEdHFKQKDJjKk-y2p70HM8Om zU;4C{j>T~!mRvtLOSDqQp*3#)8{fvil_*@&~$A>?bZq14m}CNoc!-`TIklO zVk_5?TrSxbMF9Ivu8f`NUQyybC90DjuZJz)&URW_%YW>La>PR{DNwachgfyGykfPs z{gzy6V>+0J>uwf8LpTRO$G1cRw7u`KSD1B$j5+#QBFS_acu-Igp;KtOgPSEb?~A6I z;we0#*JXgLYHdC-H{fU;jba{jD2?&&Q5WPx5Z(}20SY^u_-z%zcDBZ%NchReO8szT zR{6?UdrwY^d1iG&%-+kkPvMfK>`A~#ZrqNp#xAoi`}a%Lbs{odT)l2q`T%F&0A z$&EAvmWOW2YFaZ754=AC;rFlPaoXYr9q$fE`#$b?;EFQD&unm8l(DYyc-)<`Wb~99zC#A(<4)y9hZV1bP%$%_|VGX|Ch$M;M;xP@2 zJ$0#y4zixmyj{PDPk8YxB}36)rn%G^-}5E8N#cAEXTU+LBu255$WNLUh&qCA(H5$H zF6{8fpc{(|j;jWr&lmSedLw98i{+lYF^AF^kX;zyq4-U2(FrCrhK zq?neud^cC8iI3Eb*<2{>O@O%thr@GvD9y>VeR~BJdlP!oTq_>7?Jyi2CpybhdBS zGRxxl+ZHCR6Eq-=Wh2AK$H)QUSJX&iJ9*-~Jgc%^DE7i7XI<(gtapI5Ry7sU-&tIHtoEJ)oMk#@+-E@d zOqp@I`8^28Seq^EznELU#!PIq7gxFmctzcMz?7X37ONps>DEo)RDswk!v031XGD$H zW2-=o6OkUrFRJfIdFVRwi?-QsxwDMfg%2(N6;Fl-Z{bJCo=l#L&7tpaYVjPnA9nEuOz=$T=Lk|F1Uf`7Jzj@)==8C=#>(=6 zh1xc64I7wnVAhxiGHbPMc{nY7)x8bGRNNJFlMJ;sq@wO!nh}g7PNbPzS`E;ZC4da- zhIM$zU3u?puv^dDrbHH6Ks9vn{(biOC#eDTGllXAVbzK8knpP>CQ&P^MR$3Z!~}xG zX4Nuzhe`;(B|MdhNa}~m%F%4y1LE^%|t^+<^BOERo+6{W?)}G zc%^y3{?rNRc!v4s2&OMCeX=*88y#HtJ~tu4svwjl5_3tH9oc7RR@e(IqCs^&t3M8? zJ9f2ta8^)OE+J1(Xjtr&h(m4sB7rh+sB=CIr;l)VAr7vWGys_U)wFbfFOuVqoSd(c|z=r!D5vL=BCiDDl?KmRJu z*VE9CJiIvig+(IkWa)bSwI(zynlQ_)C7pUT(>!c}D4K;KeL}6G-6obv7oz{VwYXru z=Io>W^6i1+D$v!k4OA&n;}!4z%Tg)@3|$5q4VnO`UC0^|MQu?!F_45q2N+AtGh zC*NrzlPPFA+v!PaxZhyls90|1|6B5sybXC zJ2G#dmdHRFq%2IghiuH#p#D;#ugX&RwYBF{5sh8X`$wxJx>|v?3F;MiDcB0%K6XE? zDAEWca+8L8k*VgDvpA6+k|PY_#x*y37r+E$q5R1Yi1WYiO5>Wg-!Ubi>7f@{ce00BhKPS$GZ z6=s?P_|y6r4Eo2PK6SHt6TP(5q8v~n_e(P_le#Baz)WwXSoIGmIWWo!UI9ll$TFh|Uc;8e$`IHfV%D9C1|E z*U9uDu10x>h1^icGb7wu<}SZ$-QOq-KVinHX=7GHNP))iX!;8lqt6)mTzjf~kgjC` z^CqG}r};Rk&pPmLJne9pSCU^Kw-Q=&sy)L(N?+!_K-!r>-zAwdAj(srRiR-h)rnZPGq0U! zbWH*-ij>B5QGIjM);h$VpqTvJS!gAd$0g=@GLemZ+9ya!4m@?PuQMhlRu2ao;dew5 z7%8*n^|G_|gS$Hhd-|cSN-*aLo0PhBi!*mj%uFXd#eQq2x_M=W=|T)#xwKu*N0N zh0SXE)pgA%%Sh&u);5^g&0!7c%TRl6|5STSFPk0KsP_EhzKiAOgp@-ARbRw9Od5-= zJ#IA0vsBy&71Ikg5~rn93WL-30Aw|?pA zVh@-O`br&(3}aGBZPD-}c1xlYrt@gMCm0$V+g@T8|82<4&)+v#h1E@&{wpJ@&(aAG zeyg~<4p0{^dcUZCM7Cd^vm1%7@a&Ny-z=^A4+YJd2@0S$oa(yIW34{k51&&w7Q003 z?=uA6jvmN{6frio2a{;v8_5kP>{h7RDF3j8%vcfMxI4@tC>jE_ z7mDXWpwjQcJ`u}%iN(1`vK&yyou!R|k3!LZJ^G68f)++{d?(zzW>fTo`6sY(3^>$} zv2G|Xp(w!Kt8*sAFa#A5zMc#=fA(RlQv(6i$Q?!y!a4$VnUIfjO3@KYh5XVPR$GWG zvZD6^-4Gi{4y0!hF=wzOGc*w*nwRjLSBiS>)~D18WA(U8)w*?(j#j>R4|6eL1#2?` zO>*dEt-2*o@1XJlHVv;lJic=9)7b?kj6r8uJ(Hr7PNhv`;R=co{ia`;W{l`eSoryg z>l+&0g0dyc*=xfq@eQ{_W1OFpB)R}3;vMystp?@pU-*TqnnYnIZYct0rsZq7(>C*y zmP9CeqTpTcrbW1)Ji+2u-IRM-WlW5Pd%iJ0igv+6dvsInz5n#@yH#8~MZrqpExbZn z#!Ne0&$h&5u!~pT>KPH6R-$0Yh27&HvBehx8v4{L+4D5YO(h6GB&Ii z8Yu+5b%M2zB@v+|N9e{ritAe5$*_uuimty)oQN2Hf4S9zfwA$yF~z^R07zi^JMD*2 zJI;73>l_c+=xLY#uW$obKudJ=JFi?1)W9o(Q%eaZZ1X*|&|h9V&gs?%!-Ss|Gk(X0 zCNv}X-)5B?KPeb8DA>r$3{8G=!fzo&%Z`B2N~Go1H9rP>(9uz(8~1+)IIe%n)|fvc z66?HeL_$sUPc%p%skvw2A-jwb4dy*)P2$q8pWn54-6uZ%Vl09benyRCCqRj%!&OjQ z_qI1)%GQMhkJN_W4&G~P-K~CV)bK->=-nKYSTChun2({}in(^v#VOvhfloNei+a?I z2EXvj4@HdPO3Jyy!N0WQ#JW2{c?A0&NH5=64kRSuECve%6?rn9kc4Y}+d4IJK{=Q@ z6&{gK#w7E{r}9fDBv|7hCo=!E5gmdQFRRV5KHLA+)7K~Ix<>+sgcX#fwBc3YW_EBV z-^_82!%8`emV_N#x^G&D5(ArjcO6L$+b3ey3u2#bHZl&2sZ!PD0OFRKaWNW`X%6w= zP*GV44HsMGN^7mlX=-Y2{I~>9aVh;;hK*8V2FbVxL^n*w8_|H3 z264dbP5~U+?VFkGBR+Sdst?pl=O^@a6qBApU0xth7MKIoW zHulj^DBwu2R@ndOGeKnkb9q!d!{FLRIHa3f~62uhy5Uns{&Gen@M4g!L96%@}t z3VpIm)8~@=eU6!yk20*nO2nK|R1-aAU*}sW*12Jk9Ehuf=)qwyokIf;A=CP8E=n7+ zro>C5_|I0F>@FZROD~m-eO^8NKS8#bpO{RWg7`a52T?DJ!r~X|6?#W9Twizy3f53- zf$ik!Xk7z_(lGLR@ocvSe?F1AdbFq$OLDj|_^7N;;5(6ji2sc|)yDhW3w?^{dOqbSQx5Dzt7_vEV~ z2Uu4-oQ{g~-|~Bs*ru%6Ee`*&FYLu4m8EYW&&YgdjI>C)@ojK7qU^?=#JgqNRLx`i^YXdP+5dduxj$ zStyb@#xr}q3KeZiT?$g0G)m|@)~r**;8cW z9EZNM3JSJNEz!$3P?-m;{GMz_@0yL#-%Uog^hoXK#5TFk^R_J5rq+2L@V`=K(L?!W zC}PqlPw6Q4aK{=KDOt@S-g@3$1eoUC>ja2ZZ#M`!)6iu@2d+IQ6;b^yD%4n;az3r3 zATV}8;H?f?1;*7Htz=+zcK=Av=r!?%XVfbbMB9$>J;kiz<9^l99LfUwbrcbZ@om3i z?RgFL$ttQ)9dqdV+WnB79XTM~7x&i+qhSD;syoMJm5W|5ct&AGQz!}pe|2a>O#8I% zO3;R+RNKP(BXFkR{(F0S({G?c{)Yv=(_(ZjsBf~<;IV17PYP++ zPWmQ#GkdGO+oJIKPgnn+D7Qsn$c#om2oTi^lA>T0ksuVl^C0+}0NK6Rl)o4b3R?f; ziqRZ_C5e-KhaQ*C4);o)$#2@M?bv|yf(=Kh4?12{K8}RLc18h?oP9dP|Cw=<%NlrX zVA5wtw5<8k0}N>aO9>J0`-pU@c;o=-@q#JB71m8&LbdCxX7$ zVyyI0Jw#I!;v#7b4e7JAu6wYKt^NIJlIXzwrVinlf5aSeW>7~BKuZ`VzTnS5QD>R4 zg|`zc5}H)c=Bk`O*4jTOpWv?f_APuZ)N;Av(06~9+@tHxGOeH}ZK3`%nMLRp1pRX3 zp_4&OABh|w=<=vX-gbP=^;;+2xZJU(noQEOoy=VOoqM!3AbP7UTCbxTn}>%-ieJb7 z<>LT5L6dr|x3XyZ4GwZG^ph{+<=Q0&0Y$}nnTA!bMrbZ>EThQqG-meYSf4pShc)t*5Gn4i3&UqFaR>#maa}*lBal9rAFg#|s9+L33*weYKEi2hGy| zsZP=LDK{Bu-fZ{;OUNto`X48d=qYK$a(M=(aaDG`!@3rvFcG4O!m=})$^_YIzHtMg z#KPf@c)x7ceCytD)RD5FRKGy-qL}paLiru4rZ^O%B`PX#nX}<-Oq}ll<7KdefeR}h zT#;y z&*RoCw(WirtzyCO8Px6i`wZS(-G6h77HEkud-Ega71POmGTn%CIGwKiU^wsytH7kt%dS&gAKT(ICiicaseK$LPg|6#IGi!Vorth`;=#iLOufps{2|G^z06i~P zQkBFQHb~z7*?l-~s98^WxCPBWvO=XYNF~iE2=lOcExdg7ie0*ZTlRW8@#N;wv7(Vt zll?=Eqhq&i>MGi0W}pdZoS}~PZ7Z(z%vF`|zp1ww;OV@3H}HI;dFk8lrFw<_gPJbV z&!0bgA4f3*ENEq7-gM@38qwFzum2t#TMs5lZ24-Em1liK%?NgQKW5g7S1L4q2)aNJjAqs75J8Le$sPoJ zv;Uvhq=dZtRu92yel^oOB+L?G=Mmq{wpH-MF(sQUXqF`MeR7lw3Er9~F z(}L}@RA2Y4yoLt>smsD(kH?Imw+pw&pHxFXZ!cd~GSOUFEnnS^#y#6Wi!r~Cz$VJb zF!DV9k^0`ZHk=R5#g`o`PbJo8w z`MP_@9mN>Bv<8q`sEu#mK^yc}Ui%=dGMya0*EdN)Y9SUD`WO$8J>rVWN({z8$MJjG z2b6R<0mbfeo58JtTJsNUcNo}KO!*lxFj2bN5}6yS=u$(1^DXXYS#xI&|~Z$uqCha<^O!(#D+wde?^F>;YV zqUN~&2mC>QbHcU~fN1?1q4{{CC=nuGm&)aAG%Fm@OjzQ+PxNP&QNlyQmEN&U zw0IruJEvGGQz04)t zaWcd2QN05~zC#L~%MEH0u%~0`<0>EMvy0C7Tg>~IHXl88tDF&j`%7o7^T&FJkFK_} z*)w%7zDIaLKYT|tq^e*V^ zF!*whb&XYM^&b0zd`8xDF}0-$tsLPhb z!c33SMlJ-bO@v>{--4vYu$;DR))XUeOb#LEQx7Z@DcmXDQL2eqJtOcY_!l3Ht6S*q z>}M9%Z*G4RFoU0oGj0z4KV=yMGr#~Z9%iTY@DsGwqw#|sF5vl0)_$UUDRCk?1%p~< z5cve6i=D?dfRXl<2#rl0=5AjVr63_12wPA|dVi-PVk!YMD371VQ4d|0(Q*g8oc$ev z41bRqNAgs<`(z#4GZVwQK;VX+8j~E|ySKg~_Fqg%?}ygXpbW1hi5D)vpId(RI5NoV ztFYPBU#OwYK5K@^m|tv`pshg%j%E8FS5iUvne$=MW8-*ohzGjd*IiM-FO!00n=X&FM(BRJ0Ru)jO%C$Tl*t zPpx}-FgR}HMG5frvGr8R+=#Jeyi#uO`+aS*$01t;W4CW|pT4a-%VTN*Ersq)XN)gl zQN6f3yi}Fd>z6R`Vtn1&4ghkUSoQY~2G(v3V>(1=X(-8 z)H4&2DNLIm)cGboZ%@^F8l7W%)Iexe8>g4mrn!yoHH%*evm+k?@#%PYd8IDpDfjHH z+KF^p<7t=ra;IqVd01mE9z7l5rxS6X8ca58wJrQn-yqt?{-eUl>~>QJ`w^U%nVUip z^IFn4)Hv;*K4;PI;H@kk3*+G_fb8#dA`{Lb)kiu609eT#2hYHVDwj!89Pcd(yp}dW znq(-j5@P3Uo~hV}Iivq0S7CX+mwstE=@?Sg^~H^)V_vI%a^e32AfYj0_HM%t7=Bgb zM*tUDqMF%;VL1c#>;soV+m(@0Pj(agf8bre_AL$vw?bU%5IcwnDy<)U)TM|nn4=4c zJw=Kd|8rd!b6jyn7~#~N+9C>deKOeocI2cq!cza(vFQBrL7i=H$rPu)cM1kz=JT~_J_iY*@b ze2c6|n~$V(a}^&IIvm46%@C@oD?AlS5$WB`rG7~cQ<{PT`g@A^bq3O%PNS4jKMQdV% zMYUH{=-}y4A03G(u!XfjEi77b<^--j4VPwiy&*zN!ymGv|nY!Zl?9vG!Mr! zG!QT@C{W0kQ8KQpCS}Do=)gvo6SyjzPxICJ?w zne!*ZrnSLt*k(VR?5{@rWp)rARp%2^PL?_RW^#Rvu=mc<5c#1_iLsmT!x2@xzCh|Pms|XNB2k2=j)_0ue9QMzur)l z87m%Lv<|uIu$9(!YuO;n&rTm zm8I(Z8>^MYi@D&J;a-2}xq4PEWi^jT4f~b{KQ^5LWs9-?!C0BO)0*(zxPld7A@{Fq z53~3!0K63^! zyY{N<>TcnSqh}{`yi=NJ@UlV1KO$xD8* zjRv$KcRy4AkvcIQH7M7K30S?OyT5U5Te4-EROmt5zm*ns_W*S_d*_Y2jfu#cJ$j?2 zmYv6uCe6O+7q#!koKW#Fx(ZQ4{aB-yT7=j9<)h1g83gGtL`x zf8i?B;k?6CvIo1`z_;JuS+ePAokIiv-s`=7G0oTYPF((Hw1nUf$+;|FJO_K_Acx0| zhrb^AOL@D@v|88fbZi)PeZ0Az+In5`)y1(FC!b2!WUyXkR=4D#v1_2&}&^GL+FRW|HeDR1%u2PRIVG@?EYQCf#sY9 zro~~XmSh@BEvq56_@Gl|c$ik2#Q;g1C?h1AP{Fw_!k%%5S0}ir!A_|}Hv2(SU-jX% zf1B&B;;ghMKg(9lWYp(R`&qOIP=u0(X8A!2Ko2B9`<@Nw-=ZZ+Hb&W>5k(WC7rvO^ zp0`O#1SgzS=3CO-VgQ-x1Y2~TKaT_+bb`crM@0tZDIpJ#%N&5N>^)}H z>y{pA=teh4-a~>;tfEWx(K*^d^m(7aM^E@!WrU|nv0T_=e9>a+^@d}t+JdmF@77xm zUp2$;R)RONuMS&OfW7Qrh|1A|^gShgj+%%8dkuV#r=rAq=h{M9 zqTO;NbW>_jv{n$TXsYwgJ9n(3KM+Mo4;{!|efk=qTd#~DG0jnpK zmfCl>yQkl#KK!XW*OJlGYhsEl56UYeK_;(3X*>gCW& z3-XUhl-Av#8BW3;q^>cWDyEt<$&ruXof894_yE|Q^zyYm$Uxj$+i*D);Ae#O_HRJm z1dXcP_Ka=q0t=@1HW8@~!YvhTGVmmro1eTOiW^^&+0#00Kz13ig+Rli(lU$CM)JdX zeC1e@sO9CCbAOlH&R)0Jr%W&SASPf*^iNKkM4=B$9>EHqJgw;u-u$>`L@Q%xOn&xJ ztTsQjXg*s-t9zL$)%ZL>BnB2cX&!4Y&P-!F;bj+e52g2^m7Tt=?5?-zbv&-Ji$_cqI7IzS^v$Hc<;!Fo4nd&t0XgI9a@F|lzCHzyO`^-Xg z+0}@mUB9)($skOM)^p!D4t)Du$iEYO`!&Th2&h#B7s{KB$!uWWl*UO4QiqdKJ)=wd z6T3jAG#AU%EN>oo?<_0X>l{acfid&JW6O?#9x46MQvq?C9x>}e zBW-ivDf-De+fMPa>^igweRn(;Gxc#O2SFFV`54YurgXL$Y{Ab-!6~`x#4a zN@D+<7a0C}TO5{1GCs!jE1Y#-yTq^vP@YDgu?ij6#k30CiLfCRiwPid7KiU0_DNOY z6v&>K|68 z7Q(jPPxx(VxKs)qYxh*Rx$9n5C9gAlh3-&qRM<&!30q>pvP^-XGvWQzV3v z=6@$1B4a_F`7+(t@#oi8n-*JFiQ(=O_2VWn5|s1R6%|paOC_gHW1Y&F>#zb2WTFYGw*OcbKQPn?%Oyng+X=tDax^>pcCWL{5LBzeS2 zwSE2i_4*oLjqPMTQn#02@MN)aFtemhc%EZHXO;n3^;#`{d%ywF z_rs@*5q0-<6FHOT=<%4d{b6EQn)3~xDH~XiNSZ&}UnorKz{C@i=xckoSbpzl(#PFo zxS#K=er!KixiRWJ=?aJ>rvpSwu=>IndtfP{SQhz19)%dKb+~B1iuz63-865GU99q8 zQX6j68kZ2;Q|IIJD}&ZsRG;QHZoy$~$7iAwbAXfcMOWvYKMkYz5ELy7$$Vvllo=eK z`Sr@O-?xZBN&IV3dliw=@87jYmuu%5 zGm~dA%*PBr>3ke-Uln5iL$FM4$CT;%qW%Wkj$bdGjQ2Le7$Hd@BG(ME+h;{M!Nk_Y zhrl|2lOwd^sT2+kw6Q^ps|xO0TQH;-rU&tm5h2_Q#Cey>jo9L_$y3mNlJDdfrV)|| z_C7idm|`o!!ubjG?ba72_Bur`ijH9|t^#$!ZU4UoDmIjL+VjX|gxYHap(8j2Hv!`a zSgzMlOS)dFATo(v`swkD1(>f!<92+r0audp4K^VS-?q-BUD2#c5)=5! zV4{Wn9C`QLSyWV{D4>RUTKbQIk(XD{)Hr%1yT1KiFzjqxj+z8)_l|Rsuegj?65&%JC=#nX)i)>>*@Q~4EOk})T8H=Rj3H+6kb+r-O=DE1{5QVmm&j+Tc#B`D| zIiM@VofK&Ea!K&3Zjun1w6^tLSIH*I(GQNOhGW-4$YbM$TfX(~xrX~&RJ#o0od|_J zPLg+QBH^Qb0t|g4GVM6J85hj=cIyql9Sib@Ycj~$V@;`4+#u+=)b{VDP1pn`9=eOJ z+|CAxyU-pmp6ug17C|H?GBgwsl=N>(6R3Y*Zvr_-t-CvFJ+p2_6gr-{ zepr}@%by@;k2$$hE+(^txz%>}_)Pqa>g}zzdKVlvo-h3ufFol;ljp>}h}=bM?YA3` zCW3DOxXe_f73cI4%$*&V--23xjyvWu%dv9FgS;1;Ba@ol+t~NBT2|p6hmA*z#L}co zIMSr_1oTpEdad44w-<-=wbv7zezyZ>ic20V#jhs{&`mUdsl9!qJU?FgN3y8OuU1oB zAVnkRJ)~=Sr-VtJ)LF&DGR|SpWz$^7n^ipdE+o(G>7JTi^IM<%B|G||d|cA#h@ME+ zLMe9Jc~s`_=hmk?g-TN+8Q)O$u+Gtr@qE@2BW6P?k8tAWG+x%v{h`vN%$Q6-5==|C z&V}}%|1dYvl-Ss>?2X!49=8x^*Zs8P>)6z|*Sr}ikX~^k5@w{1aBdHg_zG+gUT2h* zp*jDn`;H_m;vTC=yT;;V+N8YAJ8u5+R?J@PPe)ye{@U@^nMrFhtwh4XZyzPf=e*!= zPlR0G{+{q@+v-)nc+!7c_Ld68rFs2)w>7U08F&sB4f5TZG*d z{%UuhhQ7?8>MQGVk%yI}fNAP&?!JEE-f73BHcKpW`pLkZ@`=7k+1I3=~tkg&ICLlsr~uG1!mN|NhvS7jP8vkUhS{q2ry`SXFo(B0jgL&Fe5JU9Qn z-{;-?J>L1m!3RDJ*S+p_t#zKi)7eLGh2$a-(Kh?sYyCg|Jri;o%6TH#V(Xj zjsOC46La$5-_PDE;;^3aH@2Wd;a||O!-d~TwGy6=N5Z~rdPMk6j{s?dYX#{i!M)UhSz35U)OLkV zt43pGh7`SZ3JQx2^fT)+Z-5XELp{CzP{QY(&+6rjM<*1pH@YMI>!FJR6EdI zhO9Ivl~qvNnE#nd@VAMoxoZO2PVUDPR4UzVB{dJBF#0oa)0mvIqthvR$-d5VSNBG| z#0Ge8zM2AmCW;1wVJ}|DamoB@Fjg_AriRkh&CSbMHj1q}pu&vg2foCc_Kf>V2VGwU z=u#9GW`+9865Yn_I{5mHSwdKDCz>1&K@GIpV@|Lh3_0Q1+^)~5%A25ug&?txgG^R; zuZ3^KPr~=)qjk!|Zk^gpMDJb2J-6{7|3vut&(Fbqkfhw}ge=h@kfIg1VD#eP(f9c6SMQgQNIN93jkSj%%uj~)g-psqAp zihZzOKA7{YH%o}rWX|YXeY)BvsaVSt22cE+Y-}jrWM%Yt7!5phzsV5I`I7Tc#5!5( z!GhPejkkRV40G1{&Emh+x7>R4*=Cn7Jsy>Cg<7lzAU`l2<2F$W68prG4`&9?WMuvL z`#DNz3wY$cB%K6^r>@}#Qnos&KC7KG=g5_-qt4&LVmy|8y6OVQ^jobq8WaiX&rO?! zdm2t{11#e=zE++|KgL!!CN;EL_nisUdfRW@lE_|Ioz_N);801#0##8Ik7f6U*UJMhEMMn<^`Tz6-9nw&ft-;^>Qct@I}I*P zkY!IpCru2ExPoDw>BT0oUmmgq-M;U9!45CzR?*I{2WwomE*^rrQ zX#S&Hh#!!O6Wh4bWk)bziZh2HZ{7bk1zr5QZU1vxR+Y_{iu`#ZVDi8ZF(aVocSe1d zMN_IWwR0N(^_8&H8aG-2Vf$Wa>ctOHeLW_@d^^l(x}OKy;zN4y^FgOG5@fs3WrJ!D zU2R!KAM#S8{D8gNUYnFtDRiWOEKMVAz3zS6)CM=hHEr=YR7Hg@qYYP6Jrxdkq{SHj zKzi{3Th{Kt>4rn>5kD_wDcd{T~?)kFpn)l9f*J-Gaf zQeGYFk3|1vHK|Ldcp=r7?Rvok+2nKXca!SaH!~*J!ZndL4)Wk*- zU+m2$W{cJC!ofc zH|t6v+^IYN3>A$I6`cxu_maA8N+x(;RR9+P_1t-BEocSo{ZuK-_i-C>G81jrJ&z;r_M&#z5~E*iqL>+h4;=*Z5WMBak>&eEbG zSmrY6H0W}v4+0wO$>P+-m0DXlHAW? zMzz%rpD+V|Bb7UX(`Vx(scWLhE)==8C#SMm?cXuhM;ib*=lIWOIwsNxkX<>@7 z%7R+DSTv`oFAX+<)X$JIPP0C7yCK)P?VN@#BU}y@mq;2{dd}K$-g_T z3}vRuGl9^6Zt{!t-i~Jwa(VMBqsBGL-O#Hs6X(6SdXfOzb7#@67 z6?y29OCiiJ9krBv!g*a>Lg_&ohnD$Ps^QVtPxaUC)+uz$BobsJs(jtL_kPYwwIuj0HeSqyqJxXc9(_O<_CsHj?Rzo0`q6bSI_U95yx5T_||LLH>1PV z0U%wA&bw}GT7V01Wa_3^ui12dkZgXs;q`MuqUZEh(o@bdy^dh0Z!OqUQTj(#8mj;G zPYeg&t3Q+1Ps5$~x~u+bO@4j*AKL$9B9RHg&sTt}sHv|K*cLSDZP|O5nVHm`c~k0| zJdVL@;Mza0vdA$W!-!hxyRLZKD&`)x==7ALtuSmYn0CChGpsOHtSv<8v4_|kk`}Ce zW8`+F;C$?@V~ZaXp*V>IJ2W|dvGOj@I;saN9!ALPr8A>{vDEVvr!bq zgR4;lHS2j{3#!i?l47VVf5G>Ww-ESMq%Ut&zvROqvRt}Q(b#X;X~~;6 z<3T)q2)_?jQVWzcZf}60Nq0LD;J}nS59RlIz®b~++&gc$PaZjUE_IfkLdcuxUt!{p@GK8 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 V0TR2_$ESIg6zkU5)W*x{^NiJlZJ*| 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 tQi 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

      s%4EkUY6>^u6>}vaK*lswR(Pcj`;o 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̈́<@Ban(O?qEGIA+cTDk3VGX& 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%0Ay8*O9yVvawyo6JYwIH~{`?FYl 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�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

      jfAJ=gty zU(4&dUa!lMX=lQiY%&ONRV8eV&z;sed{XL3p7QO4?OO-yJJ}p50&N)S+Yd%JbGy|0 z&IXhYdvQ_?{m>uZ#V>q&2LrhjCy4)Ue(nN!EtLpAe$ageW%_>tT$Z9rg-Yble8BzT zyK4SSyi!kLHQu$6hK9#+pC&up2wx(2I@C*3T$H`FR*o{Bz2IkHMDMhQ zW3P^3-hde62;iPX0ICmB!NOEWp6IRm?_8bjB7+@q^j?_aJ)sPV5#2=v3FsVuc0 zxLZ$sRjYVHWCJ-F0j^Ks1L|Ne7oM57W;Xg~wIIh;evNGE`xRJw86uBy6!`h#;%;BpthT6Yd?=t+10-AoudX(WXLN2 z@GQb*_bzU_D@!Gy#ln>Xter@JJE#EF#-VPZ=87V^wLH1nyPLy3!5vxv`8C)G#wb2T zxTXIIvu@}gP6$UIxOn`$&BDEM%nWZCW|tA5FF8}#2C~ZbLfC%MzZypHiv<5ca_*=# zuox0i9nzgZ_`txYe3jdNH@AF1^YPU(nX&REtq)sW{cS!keP_kq#v`J7Tv?XZR@BY!n6fxsE0FZd$j-*&i!`lS;Am&2l+5@Ek0fk zbC#-0*W&}Br7Rr2j?Y?xE~dgP3&3GAnW|^-J5lHp$Bzx7j^cLbiup3d!QEyv6MBD+ zif9j?VF!&JUy8|+{{+M=2U7<;1ghWs?l2no5z5|1d@WS#PTv(37{SW2o;vVS8-04IP)(YAUPt)|%8_&>k=2`FeN+&0e(CN3{LFLhl7dUi+%(9CJc>Kavl@KvIGtc zsTOUP+jrcn!IuQjfh)+YQ>3jL>$3m6@=?ADL~NJ9SKLIRenOF(RRu=xAZ$glE&0Zx zL4&-Yy-yxBey3Jug!u{GXZiU(1^Fxb?krL}m>s@IP}*UT0IDwcF?~wG1ark+P1ZchnQO-k5z1dT9~=BjD)b*b%-%hlrYfJ8!y? zCWg>%CAgr|V9SR=mvcqTFMs4|wP*a?Hm@NL3CwOGfr?vc-Xd#3f2davVbg+Sh2d*t z3#_thB-O1Sg{8T_0|7f!KSzt-FP@P^oSoWp@cf+vl7+NH>n|IK3Uw(6<>+6FJb%>l z-9cX3pj+z)y?*B9GngN3J7p0&1G^XYSFg1_&w8ZuspVCd7s>g8orCf45s9|Cv9E*7 z!XbQqo?+AH-3%(D-oLteL6J09F{6(n*Rl!7-|1GyUshWCQa-2Yh&=oDc2M}$8o_Ua zCI~Z{cMpBY;lEB#@3pMUjZM7mNTqYb@ccw#NqvDt<)QE5G7()?DZd8F2bMA^Cx;tr zSzRF}N2({mi84aaSTxJ_xCtckLui8UMaLDOa0wAT zQ|WldO>5MFbl8z0Tpw4?6X3g&n;Mf1Wz~^*sBqR zQ##7urW$F}iRuQQ8V}#fh>V~&>03%x@yjf+#|a*1u_>pk`cwl+w8U&Gy%v@k|S7KTxu0kr0K=zT)KN@SY|y>n1vmx$q0H_JhI zHdO4kJX{YwGg;X6-azx3*8%ydZC-I(u8!;yc2if&yJf3ud+)Z>Jo{+}@9 zBIE+_>`&kG4^8jtg2V^o{v}`6nwe8N1^h?EvQnXUvQG1IZ;EE+UHI(#L7r*~Qqpo{ zWkB$~!%UOYGffH1DU^uClF9VuXRcK)Q z?#}?es^A`E<>qMF$DGJqYj$C^Dxeum25%g^wd1C56RT105Vn( z95L|U#LItBQDuzqjbSStK5Qdf-(4YuwJ==hq>N7O;ZH;CqE=syA3d8FflgPGCN-IH z(Z7YQ?1jdt@oM+&v)T=p-rsDIu{_!IlVESy`eT9jqtvByb6tDbc0`2eQ$dXlF-Bs&EE{TJ-H`q5~A@~WRe@~Xa7!c zRt~-6J(5gCIs!p=2_9{I@Vu2Za~e|xhUprN482e~^_V@k5O^!~r+LIZ=r5`oV#ymPQ@jha8#q4>D!}m6m6gTJxPfUBOy2^B)FeJQ(oAm`A zs6<<+LwZuRahsZ1w8KQb^&HEYJ%O+93$j6~e|&+%M)x0vU78Sr~E^1{^3f(~%fm2-8zbDaukE_%J9dXOwRCFC5o_8(Y+D=oE&))B>V!3SD z>-`E;(^b{cTHn16(*l!#sKhKyBQV?8e?8V4ZnrsLqmEaItaKSFutv<_kx8f7pveJ$ z6R8S_JXzuP=W{fh?^bqoDPSTIOOF;NLyMbe?stKRpR>{I_PrR`+2%MW(3tk!lxjC9{XuXWUUC23iG zeZDJLKLuqfRyDrqGVG();DU<4O3>}sg|2dce&5$XF%37iG z|KhR%ZJv~ASQ7}{hBDXyS|Ip1K(nhADb@(vfx1WRw*nj=X4u74m3rra^?|aZnYiEA z{rqqGElp-7r@?pfbrm}kckVtcPIlf)$BKoX-M3Z(quX0nml8MTTP#n_d5Vtv<`UXJ z0+O;F)DgrPy8Xhe019iCPVeBL6ofkbYO~)0E@koAbtM#f);*;0(8Bk(Ymdr78b_i5 zs4Vk4zo=kJXrbLm-0e`>@i1(lv4d{GNuthg6j!)*Zv(1LPhr=GQXvV-@B)3XCjOJ8 zmo2|8^^w)3saRFBvBuGnm5#l|2TD5OsKu;nE9owGVAYA`@?6!r{rsgNlhN>ZJUd? z{n2Lgq<^t79Iw3DZUEP&Eqyg1)E@Ve>`{@`5>DHQlr*cgOp&oT3mSE%|F1V8tL5e! z(?vh%2l&YX_(M7Lxcm_>u`6ZLcXmL~E>>~}-35fb5B%Y73)!uJuHn9}#=xz>D^H$WC-Sl=6I8Hx6889+0dy zFSk8N+PtIXzTM?-FBj%H7}oeP7uB;N?A52!9~{8|E}~D2hZByZDR`V*ga3`8P|w=} zqnPk~iIMxB2P8V~f21q7J%DGJT&8ma?9#2Qt}9k7x@akn0_G5jiKS6Q<+hPA_IRlf zW(S(1rcBw`i}?j;y%RnK!gHc2gj)v)z3V{r`K2_5VYBo#(gz=@rd`z~AIjLa)!Vhz zT==j7^@0}2Y0(0;pceM5+PiNR`cr~CnfnWfw0a-MR7vYEnE@()&SEbuzy}Nn-_g(= zRFWM+%WoKnn`Jt0{sXXa7PxbT29~y=!hhO0udGcA74Om0uMD)tb@Fh19c0SQKfQ(C z&t9t5y}Ny_y$5fi3w3%7&+m>MVwY<3KzsBnJjt?qTM#3&auMA1zDy0?oTZ;FHwnFJ znQC?E?`=3cO1r)wKZ>FAcV+qPDn-8Xy$lgEjPr_vgWvan#UwqIwg*)q*5`oNVN4wb z${bYiDjxsV!G8QVnf&$hHs45L-^|?-IJ!u^n_;fkQU?2LqD~+D@3!(d)zt?{& zhhD7LM-V(RsCeE|fIfyQw6MsuUVmyIWLa4@0Y=RL$K4-Vh^IPwv%lwq{&_As`U64p z2iQ(o?lFtiv-B7X`ME9;^a_@u>un50mfi*rho^T>T%U7U(z?6tb|}WSx2Hq%SvehD z3_R0^qNtd_--bfzG%+z3nV?>Qn&|=csCbpl3u*`daj+bH)*zTtNp;B_&;4XyNwtu6 z0@b>#&gVX(#@2!}b)d@b@?O?|Gz6ZT_QkCpS60hhDoN$FU5Jig?%XQq-(y%-l|6h$ zCrAg0+UYqKoW;OC+S+(M8)PrOeR2bpulxYUddCyiMV?w+QHg=y(S(Uw;Y0#aO>c0? z4Yg}z@9F3^BHFqv2~}EGSqqbWJxZTyI)Y2s zWWJuL=Q#UVPwFOa4`K+V3oQr(H1KuKI1nwp8Uz1DMrSzsr{HhvJBzpX$Q~6I+6m7; z4V2~guiE$uonEsaWX9&LnQ!MQ|N1IB{pe);=RyAyBIvm11-O|Im-t9BdEZ#GcHh?o3dPn{Whe7siuZi zDP84=1MlWQ;qZh{jj?MY48a0!OT)J3?M8*l6LVA0`mo6EkQKzUWY__sR|?vzGc_4? zEg3j{`9(WLEz2?q}m6c+lY9+^^K;G6$)Lqb*hO7op74i*NLcA1l6ixj%I zc`lIQ?L*3b7Trx33WUlr=D142wZrDw_BLU^GytOZ9bQhF#o-K}_H0yrH2m}^&h=;j z>->?6zKa~-V#K7mOdo3znUJZaOa6q#frUA55rqlg49a9H@}^+hzi)?C+f{eO-r`Nt zPsJ&Eoh#*K-=yCSHd=z~)J{lzDJ$rx!?+ZME{3UEGLo;*k)faVm`~YjUAc)f*}*i> z@T2sPEJuO+6!z@VDh>*xJP;+b^y1*JX-uxl4%PO5YLQ%iK^w<+jx4Xcg;M$7*j>4o zbw+tPmRk^{a=w9Fm55bh`tc)9mm1Q`*Ir`UtIK{`2P@ip{`jfm`Fl5Es8hX4OdFOp z&S9JlHt$83%$XDwqisr)7G=())`{1;YvsnI6^m3;cPt)&+Y-}y5_1};>?)EtQgaox*U9;7V`SuYCd<28;i~j}Pij%6J z=U!*Sfb%0}d#0%kAlvMdS*6~}8L~j=LFMxYKPTDrk*6Oh*`?ZnJVY1L)EqCWoB>4c9W@bftlpMrfPu zLLQoiE(l?*P8Ye;2J$9<$SZb6-2&ST+Xf?EDuWko+oFZu7AUJoibMvIDtsVEi8hXL zl?Qy=Kw52vuj**cS`oG3YE#fzi1e;ct`N)($**ZUHQgxgm$r;r66@ZjZP*ZteqVC;wAWX`Zp`mo%7lqeM!8NsbW zlTw8mNL$pdr+Eij7%o1(aWR77?*}<2`uRb;o>JXHk5&*|UT0M4;|jjnK`Nr&nP69c zs=)!U<7iMM7L5SCf9{uy~%&&<%Uz3m%AZ8U@n8FvuTq^ zlwOSa5xjDoPlu1~oW=IVSVO7MVtYef$WhklKK55=HF$Y^HQ|%de%a{inh_7xZ)JI| zBZl$lpVT4p2{dlRGine!@B*GD%Z>xHIS^FR? zz%@A_ijAfDH;(yFHu~(Yqq}mAX=sVh`V>ysH$;pWn4_$0@-Y3&lXu(-oB{Pm8dB(g zEat$qj)m6G_ExxT(;pvSyn7%)nJHmz@1jt`h`eD0x1@LElZ+Q=H1CbIY$*$Q9NM!n z(=kabPY15^v-YnQT}9>XY_CWMxp#jNw%9Dmt`dH!CZRZrd;PslvFw_CM4n#E!zWin z1sF<40Mkh57ehY192W+ZW=Y{tv1< z*|wOMcgqZ4cJD5H*s;}(5-i$r9m~BYG$t#1SmkXLJsb9tdIQgOMOk%^c>NHTGtJKG z_6`D%Qo_TEc38*0uBdkSUnCSTU(Nin<@0^GY{vRxQ0Jo)%B}+`w;yVo9PiMMp1%Jj z?@zZTpVcc%zbCzj-Ps1htE52J-FxDC@uacgwNoRnRzC;P zRr710j&KYLznjy*&@mqJgnGUM+lEK0VNO0XwEM~;+ZKz=fs0KIcFf)(M;7!%e`@+nt0y^LDyyn+t>Ee94|Y6*?LmoF zpbE@ziIfOOQMV=JG$Xy`Fk=i?R3aPWv;3ocV|1)^QFy}%s9leR)X%tp^ZhYBUC zvcqR;e(YZpRgGvgq386WToV;I(>Sv`_%ULEnf~nOEo6X@U9Zghm2I2ORD$;{%da0| zT<@PNG|bWs1zx>E7iu{Fq{c7EeHsT6=4hyQkkxRwcIdJ(sHk3`MtpA&x?B~8#xU*Q zXQlSOi7y(s=0|xW*yTWWA2!fZN*A){yYXF3uI-q%JgdQh9U0jK=_+jCebsL}HQ9>0cWecOMGJpS=xk{O(FJZ&()?p20iX~;eoF#^y zHl<+;E%OxVa5d#hRX?>#wdIGQS@eBI3vDI`*;sfcH}F1uMWNX9S1kPu7V$HMKEh4t z>J+zamRRji5A)V(4R*0oyQM{|m|<^VWEIdp!In^Kaw-Pxb}u?9540uP@LxlMHkHcx zW#7y^i23%`?cp1|3zEXuL`LpZjj|1u6Z|HWwLXEZ$Q9${{u?5V==yfkhr8@RfovF&-KX|#S z#2`lquY7^?8V6mBS{}Dhyb%QDp``XvM(JSmn>JJr;><`bN49;~s_EmSi9V?2lu*uN zu3&>Nb)~nl5n}}15w1HL3&Ar=wMVZEliJx1jLKEfAbhR@t)F=_{wZ zzBF^`j=>=oOS#?`&DnXS<_&oa^e13$E{sBAI(%na-?Zj>|HRLLvNa`|&@(x(Pm1q} z@aQA?iyB<-7Q80w%ps1IzJ*&63o50HGm|%au1Aa2jb0rf9`mDy?pd<;(fLuEGQ)FM zXr3n@*FuRDvB&|6%r;I?2KK<^7i$khL_~E8^&B`)28rVNt$BGAY`tZEiQneBlT|C0=)0V58fs7={xvh~ z4ddHd!%wG2_z!;GXQ*`#*RJ(f&)ibDv3*hDZT82tGoe{KO#Oi3ch0zSUf*;POJ<|n z;m57G8(vZ9+QDD9(1i5FAI0Y9GhVF~GO^-QX+ztKtiE@NY&+xZ`7FXH!F69$m3(!e z;U*3d_rN4+__FP>ZRTY74>GQtWqRA0ZtT*EN~j}9J^HU7G{zj-Zc^=ycU~Op`>L4O zwG{t3tmyIS?7pf&n`bTAwb~1H@lyJ*vEoPdwYkM{1_hsgoDJ>`6aon>49fLH+@q3P zy#*GZlInUjvQquE3oiHV=N<_ecGx9*QavkglL#*EK)r(Q$-*NB!zN zgUb5PO-b^id5CbyuteAW?|II&)WWQg1?k_%Fld9WeLkO0?n0R+kEiFPDI@c!m&{#3 zjCCCRwX99-k;OK-ZM(S_*nLixW)c`w$FSA3>P}} z3mCJV)a*2w#E;yIrrSgYS*scK0VUpc-g~^dV28K8CdEZ6(Q2b)#Um5}%7^tCfZ0+5 zAVS@S@(>X`ppd{;LFc%z{ z^oI6KKN!+Irb-O83Nb;6_da~7(mr&tREc`g03%)MnlXs#KX8J|MX<<6%iP4>^BlQn zb9@&gx^$NnltYeC_&kFxx)Gw&vmW1K?Q#%>8ENC#(L7>}uoBdhc{ND7YC{);vd_^r1Q73*z$yKfTuTq9YrC}GuSE1cB5b9?n}r?Lu}!eBy8P{)_RTBnMDJS$ zOLgBhRtv+!Wk%k#Drd2wqco%4l!$)&BG~EPwzQK%-vd7y3+AfLdo`!AC1~QR6bAul zut(0gVu{bhxPDF}$fWgLyw2-v(!c;lTD$3*6fB)I!4}HRju5XFkRveM;eR zRMtqsV)r!9tN@GB%MuB`O}FrKl%Q}VxcW6oc@p2A=Db(*LRa8L)(%Ur-?2+TzYVSK z1(u&|d?IP&&f@+eeH1)}Sist8=@DC9N^2?x9EN}sm`2bnf9wOq?DcEHp_6solR-hy zt!sP0YsUw{63lT6Ih&_~QJRGQ)@Ji}zB7ExFQUpMrqO~)y647kHK<8Qr%wUUq}QGl z>GtqbJCKcx^)0m>2y;IEujFdSI__GM^vx`>J zn{`usfo|xbr4l6vCYMVTf}mug=(m}Gqll0G(Hn9dyt_nc$E4(TB0#)sM56$&l~kv9 zX9ee7-i;)f_buFk(?~TSM0LndA~E0K|L2!EAIAUvhpxt;cm%>QPtaRYg4T8eE? z8E8>_`_I|=Z6pjGl#HwC)Vp}lXU+vfH+KaXdsWjO%DQ>*!U}$fZ3kN8Xm)}CEr~rIs6@0ZJyeq*b~T7(cI&p8%@5X7G$iRp%|LKaF_XY-DG`sb&nmHbNB7jZQtu? zjh7_lY*KlT#7=-6q8Y7}v?KKmfo;97Ii!^k*dsqjR7mT2@8WXFXXt_3T`&3aErn_P zQi69W&4NHancNs$S#b3P1z`W*%~GQvyI}^DwQ-zHGpuR%yeIYB_Pr1^=MPau)LWaB zYK%|bR-c<5Fn(v?LyCoG8w+)B+;VIk#k!pmrf$j;gSA0cNreicph;r$k(aed=98G z3(XrQ-7*C=fUT{q=*qen9@lw|dzZuR%Jv+Y@pTdk^1CXrrI{WvO~TAIkXQp(_{rx# z-_L9dF@K}Y0p}7Jfa|@S?Wt}>$E!zToQv#p)gDkPS20B!?^VUTjh7UsTcA zsksm`tQRbfDcDshzi$c2cIP@fablXdgw79HYtbMF`9qX3f|4ykn4qs zc^P#E$4^7_riCY(IldO3jYWJRNgeKjeBx8AL^HB{Et?YRXPB1PS|goMocLHKfO(`-95D75T(-s(P+lR<>e zp5|VlAh7~yMcNB{U$T833NY2*pCqu`VY)3=NrsG#fo}RjWtjUH(t#fzQ_d=7-_877 zPULfVk*>oLI|MlI5yN0In*#r_4CWd5gRz4c0kp8n_qWmeVJL}C>@Y<7`_62G2ik3t zO?WO+Q!R4#rrg{`D=~H41J|3j_oiIF-cLYEiSMDRr0z}moe*%_%Ovwu_tksZB4l?A z$}n@i58OAa=eX+AOKUCxfd;`9v{4%>>XU(A)uH7NjKyYa+QIMia}RR%k)_P$;7EV|bp^_}r2;Y^(C*3jihS`<{QaA^ zp`TPokDt4u9Aqyq!Mc2i#)Ymh&Njd*7I#oQBz7E0S=QLhma{_^oT@wZC(H?Cm04mc z84{x1=McL=bn;uSU>>s_LdIc+AbvU-(raFnQ#(<^&~(I~2=?p30hbY+@MapX--&fB zJz(J>e!0BhTh+;A*b~&w84UYz)g3>Y-2Gg;+u)tLDr_JGz%S5h*UpLG2luo%ZLZb6 zh?sGaw2>p1*tP~GP;VzR-xS92lUqC80TlTLAL6w=^&#bCCq=(ZrpZ^1HaQLXUg!Ws zUmpI)E9D}RQ4?o83lzrXG+6WTI$iMaxAc~al9#fR${Z7Wz;IWvAdAad?$LP}zpl#u{UGLf-pHs1MOfpdK#oI4*IHuq7gmE)`N3ufWud(7Ha&)ierS))^dE6+boTKDzU_~(9m@%8q z>CPGwOpN(WLF{vqWgd}l+QwP-oD~qn|1Hb^IX67yG3Q&ziGFX0X9l@}1vG~2@IUb9M4fS!1J?j+z?y%mBVaALwEUXi37s8&aw zC!GNi%I)vbk8LyaE;Mfc_!zztBMaNjw8J5DAPl})^yYf%Rvm-0U_ukS!MQ7OV_76O zCpNr@p}>WJ@*S#15iwNBD*^!Du7ty;RD|;3;wa{Bti~i-o9ikGLJyB6BRgLa@zd zRI=r&6aRYCa78*p*lOSea{#tFP=}I1aJ+GlI7q3_c%WZ0h0*}DDfSK6+v;&RrjYun zoVnaf2t7)>=kv0v!+Gp|X^HM_tssY2 zIs1ZWGo$EG6kR=YPCb(?$1Tv?rrk0`@Mg%RCD6|+uWp6GSb%Rd_j#X70x{=i?l8?j zF3~1LUzv~IsU|_q5lLRNwK_*;uis4SK`O{e?YvF;pjhZmMQ)5qkc9q|!0=6`8f@Y< z;j$FDowxdS9JhLyqAw{h%~_qcXYF$&Z{N^>P-G--*D}mm-Of#8c)WAu*)XyhE2=Ia z>YZ{B%JzDd@#~p`ThFLT!>AePIb9wHA-@wyO4_}0+C3fVC((!s8FN7Ni1x4e8?VPx zov6l7>FTn>4&$T?+oz6@-ek1|b`3A0++l87|q?2yYo%s1)lfO!%e+&U=QkG6Z+4efZP^|7T z>)2$G-Uw*X{rRv*Y9bZUq;coe^4XR*d| z_vy$*3_ayr7tO`7>rsski#P`W>CQr)}q9 z87Je1z(F;OL+L7K8)NBy2bw1CL;RM~^BwiAXxCe8`Z8Xy8wG8&(RnR`fa_AKs~p=s zPKnOJ)gFo&p^vdCsjM=660Uven(lBjM&6CWo^;`x{*8I9z0Dg*UZv2cp04C%R2AK+ z9kJwEQK!oys2L=;{KN~uiAKD4&EGtJ2OF^2o%6o&vIujd|NNVqap_!%uG?5_{#R(}9xM&!2bi&Zytp+RZF|Rt?pIW?a{nL&P711tyi9wnb#*vhCI6 z8_QCpDU@J9ZH^SsTodvmcg}v1#f&i$CR#V4H3sagn$$S(jn<5eg)-RNY)w8aBHb6ci0mTo1b!s z3;oze$n4@G_}K@a3VAOWY8@XMoyqQ1e3KB&S}41DpRQl&M@|7iG4`Z zeg=x4i6PZE%!nf2vv4uGQ;HNfM$Tq*@t^w&%|J+9dCMAGRE!bcjV;THNJSNvY`!2h z-2d{4MsD1fDO)3MuwedmFi`*>iJC<5{_61*$4)?f!u&Yk^EzMio8!>ahL-hfgaFn= zpI$2$stZZLL|zN|p7oUv*GZhODGM|b)wqM2T;S3vpGs{;My`Fo_psk(0>8YsyFFgC z1+%A3?4$Uwh`3kP!iWF$vIF79d}YudQ0D`9{vY$Z_Ku=V?h|*v+M-`JsTjMgXpJjS z{a}-v-cOOrtKYKk}Ir3TX%i5;dtF>(7TXYYaB!IW?@BW#crZjVJgwZ-&}ZObPF^?w7mg59HPHoTGnn=r>%&oc z@j{rJwqjdYCep<{)aJFlbXT($czuiTrTC&Wzu3XbvX5u&_{~Qp z^gLSL98D$5rm7o7RmDV@ih82h%#XvRqmnb?mmITgVf~j8t%yE+I`gK&)-53*WgeF` zpg77g-dF7scy<>$=cpARA6Me;UvW0o0&t`p`%m7XFu!o1Y_lT_nZdh2ZG5m}-L(hQ z2;SBW=Bxs~S*lLa;wkm%*Kfs8r6SGfR;w=4R(q|5MEz6NE6H+BI7Z5scx;6I{lqJQ zKz%DBHYp}BG!iv~5_`9~hldAW3dW{S^TiCSvT})0MQFYDG_4JGE51>RQtHgru?EjP zF!)+8Lgw0TvezU5()V-NZtBL}VC%$hSs@QlzxH(7M`EHUxfse7`J_A6zEdAaXc@HB zC90M%7#YN^3ZkdH;>n5HN$Wm_p()r~)2{O(dpkdYx(3wO0G~HsC`#WO_Yk5Bx7%PI zJTC;T6%{^;XVL=4$N zeBy=22^HfuDC0pmHBkTZ?Cfn>yyk8?X#{D8P&zsJUDzn-+4Y0qAz8ex@hoCWpEbD} z<7e2pR(bHA|LlA<>X_M!yn@(R%fyosr*G~#82jw)@5${*9CDu4A_SkPj{GXPTYs=t zF*oUj3*5lr;hSsRjDrlM)T5M<7qIyrTckX9QR49*E-A(Y6hEGVXMTNlHN$ObKh2&R zD}N%WPfJLx{@e#2^f$_^lBzjy8m=_CD>KXYpW+r427!U~3#IxStcxbQrsRF0t|R*r z(+fX-hGm@zSXQw`$aw`n9eTyWe0?GDMu|>|aspVbt2k3>loz0Fh%uu4&f}?f zKX}1Vvhn?rjYPt&TZs?SnqY3@*}M0-xKzEiYiFK8#B~fKA(zc#4@+Il>98zpbTeh1|gWsVN#R(yjJ_MiNNZv)KOF%95ix)CNC z;+vZMmWKl_VYkSI5L}=cPyNQA{CL&d0EZ-%$hQr!Ss^H1J&DK9fY+gjl6!*&+rF@vO^w5oV9q z_?=41);bJ3eH7a6>Q3-5$2rn?bFe`#iWmqn%;16Q(Cm7;mPpq>S)M$MJJ6fo^uX1nK^s*ZLQSJ@a>3 z2Gey((|U9pc{gfW80N1f@{bM=*Xyqga8s09V}{>I0DNWka_ui)J_y^a6FqF(zILV@PnMWoVYoy7GP^EBAaVMm~i^Y$T#~DVos7JTUZ;78U z7Cn${AnBxZif=K1%6$Ww#}7YFCOW7K4RcSC&62~fsil!*#A|pWNNY?25kGX^6yZ?? z#DdOpB6JycVH$;NUi(kFg*b@`<%SBE;$oZl(Pr+n@|0LVWZCP<0Ej5vCc-Bz%U#Wd z`-Vjo~i_-hN$Y-M{ph$daGLbPzwlOs2f}O%L zQ||*k)lW3@y=>l|V!$}zZvp#^TpMl=OG&X@TrX9h)T^IH|qC7Z$6#>jwLoN~M_e{Dhg*2dGWxG@2)2Q=$wi zA-{>+qAYA01hQuYk9>5X*ojDd8T#%h9wGLp#PfdBkTq_obrygR zXe&H0Ogfx5MoVFd>1OV*g3a|Iy`!X zw>CSCkdb*wRP(3WNTV4v_VG+S0jqZCqV}8Quxj%ZhiK~A0|C0~C{Nxb-)|c3A6?QiCg*R|>JnUd z=WRSz$l$nZ0wMqn%{tuQw}ueLXS*p(h#3b-HA2+KGxiipRAWY4iNT zdwx|Rhe@}6E6-NRIAgW74VHF!O0h2aq}n&ST#_5G6T(!kY&#ez&GtG*QMg>kX%_!! zR3-3I+`ANY^Cn~=wogkb4BD<3lHZdGyVBlM_hQAhwXO|4;@M1<>(UV{ijUdByRqus zsop?=&Vs!Y;6dxW5`54r4#!;ON((25>kn)cr$nOsMe;FWK6?B*frn5`Kv~-tg!- zS-dg*S?{|py+rYoGlc!?f+NtFte6*=?8%-P49h&GBb%~JX|wrNoJ3Fy@O1^ul3a&G z!A`?soA{COv*Zw}^lZoN47R~xSbs;sSf$aOi?G!+q``NWcj#91yD8D`TbyY5?}Gx2 zA9UzeMmRG&U+b007$+yu#V~AE&c6Kl`SsV-%gQq@eIgQvw(nrdVII#rTRDfuc+B5v z3y8X~_S+5_MPk@gSTp6UeEMyuA3xDPm~ENg!#hzyU%DOPv<%Iwh4^sIOvaT4Dp(6^`rv_ksN`P9WIY=R{znO$} zMb3e?aGd9{MUwoxP5ebZFcA4>_U0yQ;P2-#>Q6seFy8#zqn)R9VZib*O-*zI;HsgZ=Jgkt9~E9pSa z$>jy$=e<8xyz%1u(K!zKeVIS?E@jT8`1Y>>5?ARs$=cJ`v=Ez(i&Ud4~=IljoCbz zdUNA>(|xs2phqr$Lv`!p$PC#%XmpdM#MRWRU%oEGnfk%Z^~?YFc`VABZtCcK5N+7$ zW5gP%1I=Y4b)SgA{)GG>UJP^hs=pqtXlC8AU_0AvJ1RKW-bqHb@dyRjm6;3v#0dXu zm|wS154;+RF1qfBWr+ywTraIwNJ(OywPKT;m=CKuGiRx)5@Un7!-L`zcOpEV1j{eV z3J0+*_zOO@D^pz;_B68uGyS^WoJ_EaDb!~l{xF?r(psHShoo~erycq;l9ESetI?D+3_d9ARc~p!0K?QB?&Nh zUq)w)Y^qJkz7IsUS##ev6S}j{o`}_CDN($jwP^3itjo+MYHtfkE8^7pi~(h~#r;{4 z2fIW$JI`BsY0($?|v6BD}0mZ`)Ky`C5MT$=pNj+osc(sXHG5(Wr3 zU+Y73@}N={+#Xtx4b`|=%`DwcX?JL8!v%tIXx6{}V3M)mNA6nu1xT#aOtXC^%(9#h`%UbM)j% z7tMfO&3_nKWUDWGpT0ZzWSnABBek?}-wF-My)7B^K3~rnBXIZ* zdrhmnLin`H?d$AJ(JDqr=+kd^#;Z}k^s@8XX;N4hw?*goBcd-%Ct8@+v*_mq9COI{ z7uqk3%iM^!BZbV?45DB+jFi2f;jbw(7lu?7LiVF2CE(JD4xR zPr31#C@hbkmXQ%jo0zpPosO2?B1q|mVpO8z!rSF>KE>(vPGmI>Hjc<>!PdY#bM+=4 zzrzRcVU(L$=#VQ=!H+>D+^)!a1S+ZZ_9RDIz-IowSu`Hfu0E=#UT zvwhSd6DeW$=v(&6;6!4UC+B0kIj?N(Kxg|ZE@w#Ncu>4?tcaS-G;y3pn zA-dnfX_sTPt0)iDmr%vz(g;D!Ain#%FzW3XhD@L9rLDLijKWidM+2I{V5anj3;Aa< z&f_0^YDsc{-tfdlkxc%rci4>=;N${$l<%3qB{)pquAFvT=-tXAXxkvUVP zG+_0}RgveoybfT|4%RXI-F`bSrkkyuG>dGQe%u*fQm4&lnZJ=0c9t{LybNtwrr3;1^P)gJWXKFQnYPyhhvv*6I) z;R7L{2X_H_u;YtQ>9jh+R)OyRZ)P%i4_0DmM-nXTpC$7jv2nF!UWOOb8di>=*YxzH z2CSaDZcS6GTcMZ%5=l<-euA&`A-cR!fdF3TO7^H+Q{}3TPTH#*?BX=Z-JO~m(XYO2 zBmTWw-^FD^LVV(N>#tWw3MS~DoDfB(L4*vAy*H_y+PkB z{&=>5@@-4&o#M3LYmMoREiKe<0(x7>mNN?T>WXzryv))6~EX13G+ z0j){5vJ~AZk|S2#sIBfrstbd&UqormyT3!{T;8064A~ji>g{$KpnmUB+`um(BN8V* z6EBEL4msx4Q~g7PJVRFG<_r0U_&528X3I#OxiCB}K}mzn)rQknPZ`=&XCypffl~D; z(!fKNZS|$73r8O{WIz05dpN*8+Pcdzz7jnA>-_l`mbWT;LaYP3Vsh#4oK)|`I<*62 zQ3sQ|?G|@CHmnQpq|P^pJ%}SF4zD@az`H6|my(ixrIZ}q-zvX4dG@JjqPE@_)k2c% z_puq{?5&=a{8M#7{uZcT)yanSTM6d-uCc8gLuZ`6^oVzHU&~B_1F!at{k5SH@`@g1 zh_>hTTIn=ue6Scyu^hY;v2bp#Y{Au$AJzelYKk+|mn0zrw3RvJnF#?{l;acQXV~w0 z_i5cX$49(92Hgkrgui+wK2<79wcV)V2>dnRjU!G#zfNO$Et_?U?Qcp*VCO>fFd18E8797TM}y)BKELi|$q z+CvL=lBRY;G6NHJLHky{@itR?>kg&9Ppmxlff+=Kk?8(wn?1DrvhM|ANpXFWyj9m3RJG^7dl=nA`lF@6iQ-q|%O9pDWfa1nw+=zzlf4oC`A9Ev8YsuM5xq zyFPFzX*3hd@=fr1N1Awm1I`Y?CcTU9_u&n|7B+-HlMuBLwXS*oeB%(2>A9pmaq+DULZFjo=Sw64SsUT(edRLvSzpRs5sNgA8V=%GKTLnnq z33BMJy2r#_+4^Yu%DAz5)yp1xRF1!cag7jIx4_OI{uYiBoaQjih^7CPAs+%O;)FVP z@*Yi`bBeAxV8x!86tIqSx>>vl&Tg3Y{H|#6Xx!paJ3T&Ggl)>P0eaECyg4h1UO(XG zUc}G6ONl$Tfpxf*OEv71oDU->GfZc3!m~7-E!0-G;3_kO`-mQ4O2KDe&H>NQQyD91 z=XYmQw;75)&5)WgdtkJR@=^1Qs9mwsVY*e|aX|{G4DByqZ|)?%6!5TEHh$%v{*5OS z8!tYoTb3%jla>Bqe*^W4iO-Ch&RqKnW5;prZ{O|E_DyL*&Fs%e@u50rw5MN-a30E* zYgeAYwk_qup-V*QE>7LA0DJp@Ty~i%Pp+g407YmYU!T*s!H@cfkxx&06$LWUIGneN z%32k~D8S9-C)vIt_3Px0g)wwap4LKL;0YXXS6wAfkad!v0`w!$nnRcot7yg3(Tj33 z*gk`o$LqEVJ9qT1%q{4j+q3FRc+!B^?1*jX&~K7+UL%fq0v_7P_BsjwYpWnjh$M+A zPgxyzZuS5A)mna2Y}tNkvxDQ`6C14!CW84ElA7s3Wr%VF!l{UQ7?$~M+eGc4 z#&9&8vons3c9J|=7vdAaY1db#qC;n49II6pg!dhn*H8OVjb`!ahIcAsHYsmoO6<%NLHU# zADGyBv#$mOpRHXfg2Nj9WJ8hDA|B)c^UdFVXL&lrD5l$PirI}=oFgv226BMeMQw&- z`m&fR`|_PzNKZfCdW@C@j|6jS+BTm69k9mL)mDcu{5B3{iY$NVx7$i>%l`Z1^#t*| zbv8#bl1uY9P*UGd2R<)%(3RkQ(es&s9=Ypnvi`QEGMwIfn(KcwdNWL}pRnDmT4|iB zx^*CWTQllX&AN)1pxHwNVY8Li+rMPtEe;fV9B~gIrT$TXhIe4;h}zOaW`vdi6XHb>OUNtI+Zk;odO>DQ-kgPs87z!i@? zs0`t<>`t;-STAq-D$*AgzUK_o_ZDWAFKEhiz&#PsTQ)AH+Q33zC#s&tDDoHGrLs! zhoWe3B0-}YCycZ+GDV!dFUA@(_6xC15${JJ$_l-%LA`E<_)85VfT2dXy@h@DP^6{c zT=%*&ff)ZDAv$#fqr?Sski^-1*(NkZs3a<4es=D8=#TrX`K$kE**?iYerSsoWSs0J zh2O}~|Jrp!y{zC4XS2X{(W_2lJMWP*c*^|qu981Q?%AFrxQ>C#=!_Ts5^cWe!^dbt zA7#5eW!PH@T52;Mc!YF}z1Xhym(~-#*pJ+6ACs;9W8nnqk>2?C+Z_2tJ*u~D=bi_< zmK%z5_{(8`f&W2iJQ)ViFMRBv2zROBNv;ItGda#~GJ2Ir1;L_KUuUFU&^_eSzDD28 zZ1qmSjZy1{Bpt1$I67LVZ{sp%hd8&bUa}`F#QF#ZykfcBPgE+C)W~r~p4!?%+56ki zB12dH=1`@iR(7AUCNDp-I-IO#m#P>O#Or=2K{*lI@vSAJC)s_~hqmwLy;Qcf`Va)6 z_zJ2}Ng}Si#ai~<``5^Xvwy-Je=k2Hd+3Lu!;Z(KR5`<_9Bqqlbo?Nxi_pY*sM}^i zpSH)Y8WBd_MC0-acf;Yh9be=nr#@8gobui7z{@YYsmS1oz=pL;dE^S*Oiv)OrWd|#t+qbVcV(qvQ<|I7@I7Nu!r)O?yXMhbhts6oY0J*Isvn`t3yz%=su#~8 z5M*-Pn(3S_k)*1kOh?4DK=&qv_2Y7pE^3i-(%KUAa`l;U=4VBpX=P;$wKwjM3uI9> z-@-u5fCHDZg77jtx(+6QE}@KDv_Z=#odNG$+W89VD{32Zp6%K#tAmwParPYv;g@AZ zGFt-Zw@L~2w0mc{O)AH2=;m5_#Q5QZYdJQ9TQ$OAU(z`!GZ9h*d(q9bhCrtHG4aJA ze_C)%`VhzQaFwn*H$TQq);Vkb)barv9bg{nA{$vLzRfz+e3hd&o+2-M4bNLwlb(FY zX5Z|BGEo+l=0#hmBHHbZ)4Q{^_08X> z%TbJSm2};G4*TpAb5z2<-vKZJm=2ceMq%8M7=%~~bTt<`No;wC%>^~LH_4y8b|VVE zpC-ys)^xgho)=}i20sad(-^m`UVfMm&~b`j8{IIJ$fK6A^;mI~X8#brv6c==A8XrK zcH;vYi#acy+o$dhEI4JcNP%q&RUgFw{gU>wUM45a*_x=0==Zm%{Y4W^PdXHwnNJRw zy_$g<83cxt)vwearo`>;rjv&K(;ZCY8Oli5BgfHZy}_8XI>7Ik;Lr%9umb6uS)m;S zgZ`RQG@XT=|K-kBa+qNV`h?HF1Fz*|GD31_sh_;ruGbKxJ4Nj&5Q=Zqt;l?evR0HCEWzpLhwaeXQHmxjpzb-aejsWZu_P6K8C*x4S zJ`IoHdy$$~v#b(QANer6tw&V{(R&Ajr1Z>g*y7v9S-V%UoyKZeD!*skv?RIvekith zS|^|gBV!UYLpMovWHn9otnIU>3Z1xW)WxVE91^9S(HE1Hm=GZFF5Mddbg3dB7XTt$ z>NNT}Vm{^5!hVLTN)Kp@(9q{yrrE9%&_TSg$J$jdZSp~>OPWp<<*TKVP7M_%j5zUl z0sML@b-oOF*i|qlzpCkzC6#~&^h)`{v?Je868lSk8ETm``?pPCL($tJp}hRA7X4K( zC+codr8YtXZcVpY_qYxm?uxR_0%APWK8)fNHwY zKv|jiAvb|ZL;Ygz1$0j@9Cg;(eoZ<~vAJ%)`fN)zEP|JGjk+}_!Sgtt-SsERv)H#b zX5feH-m}o{z;!upF4}``Yy;xIAXpr0;@&Eyv7t5*f*@}(b-EgnN4?1|PM+DsOZ*hE zU@9pTLnnOf61+@|T2_)amt3wh*k{QgzbB;#m2viaPuOAFiF``2$gV+etqZr;+UoUw ziXb(ic$`<8Khqi2mh10;T`O&Ip^)F3r_7!ev4x9!uI60C%$T`&nB|4>c=Cine_Fc0 zm7Q{)UNfpf0y7cAwk}?95;*s<`H>JcmP}onIna`W-x`zHuDi)c+gq}EPK2VLbyz{U zhWtQEc!(C0{=FKOC8lAKyX8`mt%0HkwUB-NuJ%XB$0z&WM82lZhLD0__#TJJrfX*no<9`yrS`ykFL_zO57^d8avS^wK3AWb<&{;^(!0z77V zkL8z5$mFU??{g|$naeX?=NC6GGvv%>g!!I7Kxp8+YD@4{azM8s8+bys%EVZQ1H0M9 zC#84#k2=xa%1LYSJ@_jBK=RexAy>gXpUB5&8ab~k;=#x*A|sW{M~3G6kmdhU%Af{q zNSrzJj6WfQ?E}tUS`&Ii+~i8Xq0X`?$Ck(3BB=E0@=<-trZP^iNhwpiGmU$mNRnUY zIy9`^1R~54#KR5?B8W#T6o6@c7Sb@=^$34lhKhlWMd@#8Axm=QCc?WaT>-s~Q%UEv z-6er^zhEpc@lba|(NxLM*aWf7INIb|Ynx1c3w2}u%~pr#Wl;(x3Z$3uk1q2VGIa89w40%}dheBW?ohch>FSMJyt&7PY4>Ua#<#Mq?PWw{ zAL>e+;+(qMD?#acZ@#%P2UbhA+IYO0yCu*L2Al)IO))h4>Kns$-E*g^-zTpqAJ?C9 z;OISlA`)-UsbZK8!AhafQ4i(DltNZUoyZ6&3zmTLP*nPtOih4@TqHuJs7Gmp0KO48 z9(l89foNJXucWA@sG2f2Sv@V;D>j?>NW>%a{OwN)v_9#&;K(X^Uq{(r;T$LSc3SMA zAK=cukuIEtF29q}keraM!c$bnEq)5=Zbzl1W7fSACd8dz-e|G>hhAaH(OpIcLVYSL z@`y08xseolY2Dy5J#;VUtv|!tLiXN(tJcd#%|SbhYGRG|hxh>gDFsrB?W$ScF0s=I zTupV6mw;SH42bxnN55--PG=QdI0M~!hh{Sb|3&eB9IM#|DTEk66GlF#dEQ*7LH&qh z`qHiP43dBAs&KXvjE{5%>Sp|%4{Ewc{H_`8-&XcqB+<*xH(?p1<9p0o>)D3lV+!*T zvdq4PHM!VM@oY@K;vav;Yfgh%-;yUSZ+ zC4CS#ZtVV(TltO~A(xzpgs-xO0~;1x@dDn<&(q{b8;X(+-8Z=X6w#Yd>0;&Vb=xt-Pia&slks6AbLpy-^~sZmHz4s#rZMLP%zjS$c!+$Et`)fdiVy?9j(^T7-A}?~K>7a%5uuc3$PP?u{m)=&%jV)qnL#}!o zvs!R!MeEcNq{#D923LeAb`z>b_as2K*hlyhNBnfKE+RNhij|RX35sqAXP}n z#FA1sLE>6)rmm*ii6V+;mZrQW@7w&x*kQ$HqzaXo7fpN& zNm2A)7g-D#uIJZ^kJB<4^CoA?8-S`|Hco zT*E1!YolaA^jazA)c@R(VuS^e@ucX~^BsNOomfH5zgq!N7t1x@t3MhpfT}V4AZ`+G zZwL8)W=_91Jw@q(z+C@yHd$XL7oIHF81?Q!4QBJDzeHDCURwDPa}%dy1*E3x@NGzn z^R{SdXYop0tJL5TK!TKf!PgTAK1Z!)BeK7LXPL&vmAX^W(N3LXZwAbzt|TTjolUqz zdsWLc;Uqo{3&{U`>I3`|%f|FAvrmxYHhNG`jIHsrRvWKH?MF|<;7o_`Rg~+)3Ov`3 zRhAMrM|lfjBLab?VTDm zQ5iFJGjbr>uDUVSw%Uc1rj}UA)q9V}XNXI#=mPZ-zPpA;&sK$6jgEaes!Wt`gd%uH zPKV>lr|YH;cMyK&hPX~#&a`n3)6E@P{jz?6D%5bDAHj**C$q#*0ZU?5T$;NbCWjZ| z;i-bg+==^qE3JS_`EXLnY%S^&FzthBchz`ZB24w{+O}SL530w>=2a;C30D>Recr;| zz3o&x*idklxV_A$!qZ2X!qh;^v3FvFxS!UAX26*?4A34aEg4ca9;ZVF$ZEIO<&c}?1bM8F4rp)tiuwG3 z*l^4uT4E==0O#?gOj}M&4pW^XH|;Zf4nhtu^L>x+btZujs6~`PH#ZOa0Hguea-4`M z3~Tq+C9a8wm;#)5$72=97BRhnc`05WI>Z)b$Cshx)le*dYy-~*>q!{tSsSBbdSrxn zkR5WHki~1?#U5S;eS@fFXmLHNGe5c}=j1%bJ&+o=`$sv+!EhqWZ>Qm(LQLUQx49=j z6&&(hga^0d51*uUtw!2hmy76GqbPjvY*eZeb;s-a_<0PS-`#J@iCG@w9=-?CA8^fm zrN>ssKPFTLc(SeR;o=wWl`Y}fxwIzhl3H9BO^iM*$m1EACOaa_xHbLa@+DuocxxDadcY001(X_6zvwrk9(ItyJHkAc9U2*q z&6FZFbqFCCKNrKIHeNVIr4@WnwIBOw^eB;Bsn_$Z!l`GhP;-s6JM_j-c&uG7vrg`h z3=M-F+{%v~J+vQtfq8QCbPEt5NXHq5J@`Ra`*P+vy6bKiZn{e~zVc~L^+kD56p}1# zbK!MR+u2Ky;n(w~r-%}0Q)j;sfQ1<`T$0c%wgdJPgvGy}s)GoV_;wd}|5;hat6#am@-8P^bH(TXStHW+hPT&ZS$p)rh8KKVJj&7{nr$Pt&Tz&5rGr z;#@CxQ|D=l+KlbC{el+A0gy&zss2uk;5{g9r?>pLLu;a(x%P#hA&=P}bk-jLwj9hy z5*m-*4~kqZtbSJ8+*5j-_Jn%GW~$yfz8_`xJ+-*|NcUh@S>0ui$Aq;6!66@gyM4{a zgZXuc>Xa3y_(55HL?>-k>qJ8LI&-T-d20||IjpXecAp^B(kR;e^~&TPp>T3=lt&cV zGe0ODKS;J>w7+f&A6eLlWzxNW!6md|z=%tHyF@FXTXoWKa~Nn?kxYL|vB%uM23d1& zW3iJ!`r8BmHg@Di$fHhp12Lv$!*|bEL84`2As-qY(`y*Ha|m_oOZuA!x`KDGzukFQj^k5{jLcaCIP>QEKvy) zPsG4vF+~)d*$7dNt@V7g=Gp9I?2Rv{aPAhPZqYicr*f?&it$W5>RSvPtglSbGzi ztBShZ{XP-E*DIwQWBBQJV)xC`Y)9PiZT$JoJlbazbH*l)m49SWPac1gveq;k3@_YG87<9j=L4+RViW zi659(=QbP$R;6h+T-8Yvh3{)tJXZ}rm|%(!?J*a++kkm{8Yp6}h7}qypIwV#Y=RVu zFXWFE{P-t48%nK|;Qe9Pr>pM2u9vFmoE1;b*qzs5FURm?;0+=rc#d$=+ghZK!TJy| z5fDjIR4a=lVXFvk@_$}}f@bvwy<;{8carjM43SwI`#4tB0TD4P?(5$&orUhxNWV@T zcn3bMzaRvZKj9`JQyr-keiI|P6IU*-g=R-h%h6WW-a=$9Ve3(qx^=0T*B+D~z>*&<3iWnqr%vgY%*<@}j;NToIx4+e zc8+5Vjl?*>H#~iw%?U!tDxwM z28M8Z-gJ)DA=lj3DblqitMWAO3_V=Ia&n(}OwgE7zXTPPVxTokR8PVyKDPu|HP{8R z@ek@PUM;59WYFSa2-=HrwVKtD!cqdTFbY7RWMK8bSR2qTypV2qe;q+{k@FX$gA788 zt@(ha84l0L%%YBTO-Cd?gsmw&3xhdFNWew{_;B$xMk1#IC-vgtVs8lZX9wWO7RqDK zjlMU}d)(Z)2hM&#j>WkX?j8-C+3?jGeRUm9J9A^??m>lIy(zNIg#iOzMdx(A-1jWy>ePtqC8iA`_%7B3iDYhWzBqwc!DJX%V2@kWxnjt4HXpo~)>JV})ozK#@(T}Z_|fZ-$zkDT~hSJ4Q*>-XYoJJe`=&G6!Y zWsi(|y+>AU;|?aRZe_^>y)}?gzmw?>bzCgI^_+#yuxh#I-9M%EIfB&@-clt|~g ziND2PyYaSUrP6r_QVp`ux&$mlZiyK|ywRgE+-R{`)zoC=5xd()+V3j;>(Ug?kiWBf zd{4XUc8kDABmFIHYuskejuqlXa~@T^MuK>maX!g*mLDqN@V?Cm{YlddQl%T*GghK% z85Af3(h2nl2t;yZYgRzh(@gu!p)sj#_1?2kwKWeE=z88NcE&Gpl`(K*E!7yd1Ioib zzQ<&{;7Lq@Fi+|tioTQ)@vwSteT#?d!yeF~O!_VJB=Z7H!x1Zf+45A?v$zY}1{ng5 z0xb~ZIPowuBP<=P#Z==>KRdy!;in_>Zqm+yFC=-}A9tC3Q8Dq_7P4R6-Y<#BgTVyDKz{VoX5eip{Z-IOldAhwleG(OD8u|b z2#QZ#zUibgSSlfx!Z$3V3KA{E{us5cpuWdf?NTHpi{V{h1GCvJ*a==k0N-gAd&LLN zk0ohj1(Za?*5T9M;laugf&9Oq5)df6FuDjSgo0E9wpGAbWvqgxex>BbFt8&H)bg@DF<4q6Sta`iP>R=sa~xU@&2Wxv|(xh*lr5uTZGx( zvp&`h%&SNQC!(8xOTlDAF$tKsX=$CVICh!KUjuBOuHK3{)Y>~N7KaF_=!N^o(U12Cs@$EUtH$NbdiA<0WVDRrJIXqsTsRF zVCg(~^FC?}ljLySl-F_<^C?5G+bo&4<4Gt7bO%uh8j6?Vg{r-7qrRPSZh^& z&dhO(o=7P@8XWFXPJTdUM{q9p-@8l*}fYFage!Na!mTH>V_TdN#YSv~clZdu8O1bEye zTEM2`Wdr2dSElVrK{}cXSwucT2(Zp zWeqiB<8ek$dq1^J?0m{&Tkkyvj~Bj8CMNCG9jXz)W4Axnl43k>R!+;%TbetR*-oaD zT0^uZ4po@LlIN^kDpkN~1WEt_j1RtaT4oXyak+m+*`=I$^)Z+qz{ku(7Ky>h}Ne#m=v)}tKW1EvBO`bt~^j%le_JCG81 zPY^9OTj*GK9S5I_g@hocY?up!B^}$sSL8u+2me;HU>-$2|uy91rLg4OzloYV-$W_dgK5=3jl#HV)T#cH4Tm2f;U*TPTK@adZ3^xfYZ3PHTd05PIDJ=Uhb4uB-2{|ucY&HBI_;az`8BMG$z}=sdy&(Y0vyNcnwsK1`Ld4J_#qYoiaXxZW2tIS%{ziX>-(p*CPV$w)EHW zq>AD-LKl~l64>D?De8A~;RcSYVDA3uh^1VT5#ouaqmXScHjWNS@NfeWbof1X0!`bpN{ zEV-F}9rRWQ)GO(koax?K1!#|$Er_#Pc!SOuhKa(Nk+FqX4d#ve({#dR&nIHzn;~nW zUo_N?x=8A?*3kc@@IX}-mElRs-NhsI+~?OgP2!li9Kt-lr4zb^c*YE74v~jgb*<>KnGqLw<-zBL0NrR_nYQ3Mn+91Wz zQK$L1*D8RHc5Y&9fmeeKcZ^XYi$35Js+MLYpw&wZG9nKO^#KCl@-@3@;IW4I>pffO zN3oiJl4*cNthX6x9!_}_#JjM<5DC7kr?=lGCI^%j#FD`9wAX1^M$HuKI-d*7IA?!| zZgu%Msoy&Xvzi4Lux&a5->A7X0%7^c%tP*E2%Uf~$5WgUTo?3nT(HkSQ{hc>DIO=& z{oZUM?OJ6f+2~G?Iw8OLT6m50e7*z~QcT*0OjaI>@CO|;yX}3Os>#75#f&DV2a=4? zS3?F}Iqk^^XF2i16`xY{uRDacPjgbJ5= z9tNDN$y!bBkm2kJv}2d3%UW9FY8tuCzM2ZwG)kPX+Kr%YIVD0JJ<9>#Bw z0=5|iM!U#`P<~(NwY21Oy*dI7By!rXE1Xn=?}7He$H3Wn3SHP)N;gJF&8=qeu8_vz zxjx=>iUMc7p~z3vbC9N9^1icj6PMNk61rPaWZRDqj%^Y<<&`$~yxJ>P3zXe?Rkw(F z#7{R%5K>=fi32|ohDr#}h2jR^8BmJZi4zYTd2Zs}(0!m~Eg2&~9g0z=pf_}w@`x#l6wdUl;4@p|Xp!7-=d3(G+VDq~f>OlvNv%{_895f94X)xA-*r80mxHp$^1rjsba zuu&1Ve`t*FX4nr=QJ(dZrAyG#VQ1h!x?4VSzy8%&#Qo2icJq?eiHcjO@2*IW9gmUk z({=vwry>)qRgZE_T4RLUD1eUMOK(q{I~m^t{IWQj0|dXr_}TpVbG;k?%IMVliD&sc zi`v#@-)`&3b1`7{Cuy=esU0`1H{}NER#9?hq|rl1N2vg@nWZno*l!nBfXtGTv9CZs z7t2MocmO#LQJAs%UrpIMTBy&;4|N+l&-7^9F8%uvT*4%Vh4E{m_=F}Z6U*k0#q!&0*@BHOLE4*h?`TD=0q=#4rn^1JMWm0n*>(I=@&;Rk416EA@jLP%v ze`c{4fcQVZ%}{!<_K?T%&3^ofUfr#vueIb`)7wY&>O&YK{x*Y_b$Wh}X_c?HKLBbY z#5fO{eN01%zfdjMK7{qKlSYYzK43^Te>$Bv%~A|pKeyP802I-1FfaOG&y~ms;YrK|MFcs_QTEc#OzV+YCVpfd zt|VX#6j+mKrx*3BRZ&|wzF*oTy6^o}{N}Z_YO$^%_v}fJ$~>h@I+l+?!#uRwCT4b= z)1>P#a);!4pD2tcNp2;{F6~$frhPEN7Urh&3Ady8I(JChjkFt25)#rpF*c@pIC4$UtvT4U}QoOxF~jal_Etl^BhL zSLzpDN|Ox0x)A>vpXyD=E?mPx{>foHzHEQYtuztq1#p4u)U<-b+G}cQc~#wP&vYnA z`?-%YhQ{OtBW8Gk$bu*`c^hi@W!1tuFg%XBR)UBzYcLP5cx1L%RRMCNg^FB%s~SjM zIi(`be5IcHF@iyG#Y-}E1~mO529U_FnuQVVDfu(kS`tLzko0*)WG4Ps;7_QDAY6rb zqx>=JNl1Q^@PCtftCNblr#6X&qk06|&9GN<{>@!3qeV`LM=4F=_mQ#fIm(m^hW^#R zTxZ2Y>=uH?&yymiAd$5(|Clt07Ugzd@6?qT8JI?;?4DoPFE&C5YL< zuUpy{9xvT_!FKP7kltaR%1s4Jfa^hok1tF)`y z`{IWm8~uuO2QW3_?HoSMdginG&xW-J$H$IM9K25R1_g!NJv_G?=DgQ?zA4<+T+Gp{ za;|&KdbWUim8GRsAj;_>sdLx%xLQ}Vs9*i<64tSd{)qp}Q^8gvSu)1vSX++(IS=FQ zz#o;|__OS;^;=QBrL$MuoW2X{>9uDzza>fG(=M^j#|i~p@tO9sy_U_xhsrlMU(rUk z>M?s*?Y5&=qMgRiIPvh6=-~@%{^hAbzSF`0R37qyPYbdVUp|-jj}X4+#Y4(D?p`ya z_7j7YoRbo!*KaE3SE9$99Y;v(Z+|mjHV8oLO>bAWSl=o*x4yn5BkBmt{1?sM5NSro z$jr|=|7gW9fZbK;Tg^wmO9|w_(aap~ilbiauUpqH4ap$FK&9fhe>+If_$M)J47(ej z96ijq7Jfck=5@He*OZ51qo4Mlq!ZDBMQWCTOQb_^4Q_SncD&6$rGriPzRERP+sSC+-G#Z}o`KpXU_oC*kD4H!Sr6scoty*FBB;SbtuQ?IZ;Er4at-z4^#zRQxGU z_3z0Ys_|TlFRyxGm5kgJlFgl-(ubOMTx)t67wpsX*r8DiP7m* z{J;L$b1okfe<~bj-b=E3?M^reV(LdVgG!$>PioMc7Q~W{!Fx*|GD50XFOAUnXIhNM zq9@c&+(9X$7zTll_*!Ru-Phy2IbEKZU+9Lkms6K3YELdH?FEZj+2|m2{O5iF7{LD= zX1rpf4-yD4|9PJqXp!;nPvE;&`JcsI|NRA!+Wg z-?RDewD`Yy^UuQj|Mi-h!}6VkmoEeV?jl*jMSGXaO08V{Y1uBd)jwbDj!XZ1Elt?+ z^YzZ|6F*;hDdnchv3X&g?2$9~rdGkS9N=)U=8<@g3Z{B@CfP+4hkF(4JeR%7l zA}R8wVw8CQ%^Tr2(qdoKJl-C)BYNxgBrrdnHgFC7tk*7O9BO4?zMwgU<4dk$_J2bI zhna}SM&)2$BiDa>VcsEUen-PR@bnWUg&@Hh0Eo^Nl7+SYx<4YtL9n&~Do z$Xb^^^6k21YFtmZH#*2NHk)Za1J%`c!Mv^qeupc(`i=JbXh0UqHC8O30c94(ID#cC z6A~;8p7>{1N=_KWsLr0PANq23@@MviBM|6|95By>Z;$`n96|~s6@jo!Vj;&OwyHU| zly;dC!v8GrX2EK@U6>Lb9+nAK@?Z0mlp>z~X@43`=7sqIbe3*`HML&ZP;yZGFZ>W{qV*YkHc`ZFr9FT ztRxJc%qWev0|gF&cJIMD&;OR(GlSjO#->TlFbI|}okjQq@9zO{tJcDb=Jm?Sr8P6L zDvYzGm|HW=+_8fCo6uiOl-wZ7KyhIji^x+&!!{}ebt2y+QusH;_^g78;$e8bciDvo zEj=l3*_Czbf2RO8gxy#_>M5br0I`b*FgnaYx9R^~G^>)hGGhwMW_~5{G&~O9hUnop zjef{KpV^a##hlm=n=V*M)I5)_XR0q#uz|%S^zU#CXwj8q*j^fJNnp>cJ4s|eoB;i2 zi4+QK%i&Tp3#1C-|@ygb1H4@%(3@M(!t~jXh<=)<)?xyXDtk6<0XuIxFX-u5{ z=cMr{Vb0yAmJVDf@t6rpFApRd)dBJl1S$rY_I)u|$;LD`1vUkK0HVEV3*~1sVA+4+ z^9=8=1?J&^~3v*W0*oq`Pf%=>Heh zqi8V8PHQ;{P8)pZ`2HCeBcCK77KyWlLC(!q(w2H6 zt*ssnb;G|=b&I|i8n;tWmL5Tpu4~j+n=3n%doHf9p|zb4j)EpjkZ@aivDTG%T>a)P zm%hLkH`ije>b%Wz=ERozvVVNsgpU5B@!gI@X1bgMWZQdwn$nvyN?e1n5CXN}3%S9l zN|`5k>)1mB*vJ95Br_9QkwMj3QzEAb@llpkw42)I{3izt$)S;(n8tf#YMiY*pfiE5 z$>+(DF%58c~Ru&~QZ@BkrTHVJd|N%Vn4_KbX9c7ra&GVQ*s6}xOV zw8epO#^hWE*%eWl^Y76?q3T)7lT8r`WhJumeH5jM5Uc-X9WzWdkC|JI29TEU@+mtI z;w&{ZY?iy-4Azzaif_6~Dlq0keFoj5A~AiVSvqu&=BcTg5ESCwc>?(Y%7mzRCC@iK z!?izYoq3Y)hpTd=-_mCE^YjQXp62OZ{&Sw4J>R~?b?+2BD{PlTKdqi&MFPCrvnTRsZecr#d@}J6(Rf&F<$>&~?@!KmQAptEz!0U!XeOQ5>uZUO;URgd3qygef z#YzWRv&K%Et%gzzH{uTcP;~Jnj8opj z+E!g-`>;-e+z4HXM5s}snbCwAFVcLc6y%ahwv4t=YcbY6KR++Kuy6-og8E-^%fjIK zg^*WJurXDv>PO1wb|e%-ZLzl|`BLIynPlFb?qMzn{Q|Q9?88_4?J`-L5{ay6bg8gv z(&;ZidTZ$V1sA#bDGvOTW5dIGV!ss9Z72BuJL_?TD*_mPn)5j^oQqa;i+z?c@F0HQ zXijQDSu7syPtZ?uQuxNYEZ~-3X-zC9Zy|=%8(3pkh2>-hyi|Id0>HLgJ6Ih4e-#QF*29)U_s&e8wA2)ZoiA4oZx=!*Z)^lmD6IkSeicV{zVeF{ z7J`37pIR^1x-Otp zjlV1qLM&#%g7@Sgu6hr4qcma4h32TBxG)nEcY;J*{f1<2vA4ABFqiZK{f=EO5-KTw z6ML%5!F)Z|OHzj9%F7swvXr)czI9rl_-h~{^bD=rBomy4<^GW&xQ*) z?+HguFlx3?O*j>Ua`HmYV)~<;-W+yxGGc#)mX!lU^3x^Ul3ICJh2pdmh(crGy0%}> z)5iU+v&k>OBI`23!cLbYgXfAvkhFPC=Mn{lO{oYp+9U}&ntv$^;&e#BO-)NS+j3mu9lRW% zM*%3=Im?Nnntg+_S9~KKSc{UfNk!DO<5@k+TcPW}6onQG#&edtpG+J|W2CU)1UYg! z9}0?zE(2kMSMAGb#e5$BczMjW0*;d5p7P`-cF#Ry#BbUc8weoMZdMcJQ4budlxydx z!kwAl-_~V{laKqmkWBRfAe(EP74>(A$JItU{u1QM7%@&^CWW2uK8e*~&ET_Pt5SXl z5Sqz0(6$4tqYs2u<3<_e5&2=Z_3p}HJ)QK>w?y28(HD_68O&ZLXllhYKr(Xp1hQK) zTJ2Z$S)F1;NLyWRJlQr8dx0MKS#Mr5!NL)g6J~3i0{8P8t(8%4hQ7;2jvWpSDOED6 zcpV%@epuLvN-uO`F~5l1flqbtO8Axt_KC#z?j7yfI$z~lZsSTH;O7tt*N58`7v!*- z09lEVX>3Tr2Cv#>_iK!8 zkAu3wD>Y$5PN$j`omqKzBjXDkvT>X+&lvt^TKV{7gdPke%888|E>7zy5NH`Egt(3) zQ1Qb|fK@y2JqguFG_0}#JsSK4pqz5<9{;g5x@>KQ?gAc^lYE z1eq$jdm`UF|6zR?@N%f=N&0mj{Yl2IM^)&N)Aykp?&&hRBPvgo?;IkT@!Qr}iaC=L zv%Yn9<6MZb`-c-H3teG~#}Mm&jqZ8m`|Y{b8+iu515Ny^a=)%m%!k+OBfosYDt!(Y zrEJRCiI=#ANJE&1$v{ql6}pueRTAG$H=NIw!4PY7Xmk!affBc~3IgNjUi(BPkLnMg zZQ~~dF&Bkg>{I9L>Nd}FaarV5It|bc5V*^sgDm${G+HbzsKYgJEnaJQ`A7z{w0o!Z zaJ%|vtHw6>t>5dfUs0z*SD%jroe5QuLpDlp1;0&JQ^srvg)}_Dhzg=-5oiv&%$tN9 zjvthE=E+v{1>z)82yl~-&<1$Eo;>z4kIF8{4_}mx4SrGIXXxt+!`<5Zn|Kmgg`>sIR^A`QkSR84G|YIGsmYG3eY0#i zVB~2#nT5_#ik;*o+k|@#6+&ek7HVzPde*EoA&Vy8$*9?ol2*>d=($o1hd!z@WYkpwF1#E_ma`^Wp^OI>jt zB#}Ds9^969RgyiPBE&T5O=hWhKl)d$H4D8W3i(z=uL~vAQbEETw zxaEBK%1iQ3!=aCku-p}x8x&f)a!h?p!&MyGKllmr%M?MRu%Bq>0AO3;1lxE$yew@_ zCfJHz|3aj;9wO9?X|du--J}pdlL$B6FH8uOOX<~>x!+~1nWjYX8@1)g)UjwwP^5Hr zjHDA9+$Gllwf82fFc2{g6X*p+>$(x#oG++QR;3VsvKjxh!@IYX-N{SK{?1Tm-e7i^UR!)U{gqAinPhi?=XipvCLqD z=Q-F2DcvXZHxTU{1#FKJ+f;p~1cr`y1~IW-0vJKky4wO1=C+tVB9%b+T?OtOw>^X^Tk=7a7@=L2smul8MR6bNwgd;BB4Ywwg?DYIS9DV*Ox{#B zXDRkrxaOmM5519E?kx)*pI03vwz;sZL6r0E(vM;c49S%iMYfJpTMDoN%uM&^e-!2aH^ZsBQ-_ zRS#~~kt{P5?zE~(FjhhvKY$i5xhlzeGd%rf0|iKd)$$~`_LC}3PVLC zZ|Hl0zN9SWa5XC!h_=umZvR^``U2D&PokP=H1APqRBxSAaP0tVIU!(_atq355w4J6+7jh@KNIx*Igdx` zdCPgJ-V%?I8o$k^!JnPBO;rgUl|?AY@dD?i_*(i??yXno897R|@>3w-#+>u_V}?KI zmuk$0JXr_nZa6r|LESo3c8f@8$6kZ}v&k80JajxJsge%EeV96jvEI(qKM7}lL)v;i z4cN$ynT?=~CKvSF0H#`QJlj^UFlIO$I(KUMKKLZO>od{l1)d#Qf040$Ft!RyYWJTtE%w6JIuN4J2*NgaA4eoWqs+ES#lb!#1SO6`kz4!uY$VT~of zUTh7p7pXClJOzC+K<|#qBaTNYEVraLoK&bDWG^hgkW+oPm=!2N{t+F$Z_E}tnQoVP z(92I^$`TCd_QBbhNFL*+rHw)l z0?B_9GIS7$#$buo-8q>5XiC8OBkmJ07Nez~Z8g-qC#gom2?|s2a>!GnyC%#2Y{N#%9+-|-TP`51rfG)an3*Vx2|P$l2f zFM|`EceJ*sa69x3_At}7gDRj$oJsMO6WTPr%W<_{mmR)#)ESXo7KtW2Oi}fh>-%qr ziTR3<+{Z$DS!Vu4+hDIO9D>O{MlZIhn=ruvjggP&io0rry?DWd!=N2j`FvTynK}N; z(wS1o|C@m_5t1$BO{&FRWtzcT;_%T)^dn$A0Mz~m66nBMxO9FTfTNf%ooXUo%QVo3 zDXDh^v416VRFAn3L}QZHusB?7@7O?~P~Q#HyM| zyAW{N&2;et#AcY7p=G+||6`V_2J2$sWch`L-5MKa9{(=1w)M~T*l!;V+O$Yy&7wQ< zxma5Wm!+p|Z+}hy$qUQv-^sf)cBk8AS*2KKgdtL|ce-2dZeVf(c54{(gb%#~fkbCIoPJ%**l@U;I{-5& z>xv$Bn_I+b)(j3SHhPyyVX|eEAdRV`l}Pn^yKHY#`zBL{p9&{^m%7oR=rr=+s6iOA zhPKA{1nLl_)SdBT-RRA3*GESxdeoGr(~f+6#U_F4L(R=7-8qlhP_5(r<;#X@j{$P5XC7MF0_-Ujfw2iE|wyUS9tp4rl6aqkahC|Z)F%0 z+uU?5E{t{pt6%ubgm9i`O$?!8PtIp|Z1WLP#9`v7-b}$j_3Xv1^2Via_oAxf z8np}cE;_7sZ_Pg>FcFn}eWB0;edQ#5hVT-Tu%U+UKxSbMVK7FmdagifQS>VY(d*%O zSyHyO5r@@D>8i3BGIC$s+>n08V&ZTs&H$el-(ALv*gdbX9abK<#46jIrn)(xB^_U1 zu1t3d=6g)ipZApFk}s=MnCi^(}X=4g>K?K~JcW3lU0jgHuTmM9g}y=4qzYU&u5k-V%58-wMxG#x0$jM zz-*Un{nOmJ;E3AHTTzLKJ}`kvj5-%yqugSsp@#dn9k72?)Q^o_-ekfog4tY;`;=Mb zKl&R>02ESAyd;gC^}8svD&tv#yvu3FiUCg4V8GNnB1-GS)bqLkJuTF9mkx6}Znhn^ zoi<&sCOwBt_gXuj^j{YTR%;Nw)|1>bv>cBG^yo{R>5Lo8XFy4CRcFNeMmQ2xKgyZ5 z2X2Pdg#gf%*!rZbWR^B43xjFATP$-8tEQUP_1qPG%q!r%Et|r?T@M9#hn#g4M9olmMEOWpBQ1C`c6D_edf z_cHJUpn$Gux%$Jv_NJrtHLWFGxtNvAk^GL~?CmlLFeqDVRS>a6X^3nsq#IpmxF8kn zr|Pt;@Ba07XW-qYi9-nK=_KWhmwlJz=|}$a*2eB=Y&=8I=Za6a#?K}1@C6*`ksxvF zw~g!lg$^4+s|#fIeKAy?1*?btc5R5cRi`3oXR{O z9gCQ_@mrb_;ahnMG0MY53%XwXh^>IQ!VeL*w5A7h4>)q4d<{N#B#(b?U_ z>L$Ej1TlVsNTRf27WV3Mp)N}(38X=SSOADE{{qC;jF1dfrg#_hJ}@RDC7XXGU$U&3 zKx%AMBr%7Rn;EZo|9!Iiy_~b0Rg9gjSO_;x_aG8ZafkfFfL;F}HQ)YTLf^v_SoqNG z>Da{JU22rk9((=$_AjzAPvuld6O)-U=EZ$=^<5QmQdoR#0OrExVX$zK0@vl zR?fV8V!%uJSv}EZb8mz_(KF^*{loYQ6KV)i3ig(ns^1{J1OcExzFu--Zbw{W0DI|m zdp?$jYBwu_STzwKE$hTCL$f|~I~*OK4Sog{wgfBrjgke?H5?!0jQ*^;3vRXa*;LB& zTpXWs#AJLiZLw$S5;Y_y`$%@&(qy%dsa9=rVADH6*%zy=6>M}*FlFIFS;4H_vUWhf zrLwbiGwmV7Z`#^5K2m?Q;~h$U9@-ulymlaM;&feyq$gMm^WJL0elhmivxc4}qA=E{ zugbU3XMS&YNPg8ZWNfLYakD{udn?&(?GEFhw9bvI6o_=v9PP*C{KHWHi_gi+;xbmr zE$5p7U}XkBNt~G&MFO&UJZ0csxuo?meT*e=~UKIt)owo7xjgxq% z$wFwEX(C5Invcc|MpaYYb+d6_8 zh|5@i)9vXl_V}zop-*%*HTrG+;d!@N0hy$|X%R_R#-`**D&BeKXH-b)g!0`EH1s>n2(855_Qp$DUa4vT1yXL_)N zvtPZIQPgly`i?HJZRh9hhsQNh&=dl^Yc!hQP$~w1P)sVusqAn{H3^1fzqV|Ru>G{? z=r3kHL?mRPz=J*!|E`%L%!3W|65ee{{~&yc-B^jvpqyu zuK7ekP8sQ5;iPlOW{jMLN@^>i*auI?=_~vgl9y%h9g9M2WBhUGlQL%3@>_h9(>ISp zBatY#-GP}iu!k2%JyDbv%4}>T?}IpYNl1wnu~S5g1buP4g9~$Q8Ahlp5Rqe}EO!Mw zTctwn&hRF~e_RFj`8ivRvziS&aLzf~!kI&IR>5+F?DEW)S_XKcL$MO#i%~}`#Ht#q z?bj@$F)o9e1pv9%C1Pyl_7Shy@9C>j1l;%%iB*Hme1;m-fgIekqrWIRIp4l>5k&c={Y_AB^|-orcA80SEZgs- zwzCvcjHna+NWXibR;TV9f@Jm(IG)T^4>i!XfP2^N8Cwq^;*m?2^5LcR<97F4ajtmX3M(3`@GHrBWU-xg*vCImxRq+ORSF1A*`9$s+1FoN$ zcV!6AFBA=+v``b#CQ`{+{Xpi%MDk2JTzc{`b9>Y-qq+XOs~RHNyq$!v3?E3>+ZiJp zZ*zeObE%|p9DMM^PpAsDLiAB12mN?tznz%-%PIAZ)`2&ejCP^J+`YX`&TN?gQj8#v&R=cjU-r>e{7k}NA z{``HSY+S`)g4OecVG~|Sccfq(6K?%eHDxgA>}*Zl*glxP-c7ot*^OVjHo|#_;Ff9= zui%bCU(NlahmB&_-bXr7mY*3~w$*KJ0X@b5Lw$M`1cf`>WlhCh;HM`}vWXe%bcIG0 z@XuIX1Mv$A7X{bmE`Um!57Qdpd!(1bX32&3ut6KTHVC-tuoB{K?eVGRgZHM<+v~4J z1DB!kb>l(3pvzEmZO-KT-zI*340xx_^GBPE z>JW<%wu;mKaM;=JYgA`#ehdFi3;EoXAAEmyBa*aLSdG@V5Q>dAorL029phK|&v)R` zVRAfb29?kOG?MX=iLCZ3RPlT@9I2MXciD7Ip4iKT@OJv@c^jpT!z_A*ItHV{9_?p0 z7F0XpJ-d}CnYk6)M|9FpQgamj!*nY9W+^N}(FPP7oUjT)EWdxZ|NPpDzddy{-tsP7 zXQ_Xjh@hYGXG0-{(5%N=q{-vdeHF(R%HffBb6@})eB``m{YFOSt@LKW*WM`^xonfs zIyQ9xzkInwS{!ok#>Ke$;Gt>X2NT8g2c4paA0oH}ilVs_%&N$e5L*b zKhw3rSoI&$Rty(|7Ns43k3ZKRoj@-{PeE1RQ~M)8Z-pP6xjr}D?|9bSkO?$Ei$%}A zcc?S1H}9Ag05|ny&D)TXbwaFA|41!KKjmc7(6Bbm6JJR~9nnD92gr9iw^04ee2B$k!1MO+GcLus#=kt#}D41D?#9<9qc^uBS zKk0ZQTBD^4GnG3Ld*7xf%O9?JIIZls+MCM<(i{5PQ0_#fL`NuRc8eM^_3j81#;|+y z(+@6GMQ|nTwtpETL_H!OZhJP*JK^_VhkT9{z}-)s1M`8ROt@(+RlZ0DtL{yUKn7^|lB69_yV~0&og6Oqz99LYiQh+$A#GIjt z>ke~j-kKk8VP<#lX12-+_16;%47UL%jIO~VSyBs3a8)*?r@eu_?;_WWE3r*Ab3r?Oz|F{i=j)BZvsx6lj+{ z$U3;bH)IhCyvKQRCa6DzjGH`tUEaDf^uimkg$tG!c|UdnrcO~>%+0)=S)*L5GVA)T z-paqriwAcn=QRYU!)=OymZo^9 zChNGk>W3JI2JR{fW7|{~GBm^tqh&y_4|ns{-6hmClK3-<-_oAAoL>1OY|LgS8c3Gr zshQwJ_89FoShcCd9vmMfLSRQ!^Ah^no1x>rJ5)lZH32?bcWGH)V_+aQ_?FfIqV08< z7Z=hVpkpMGZe^h|i9A>SHm(ATWnDdEM!#}-wEm&U9*ogeI1!gMLMBNfYYJxTJDNn2 zU()3qvqGi78+J{X#^D_bC(WMksqSCcAO8!AP>e69s5VLryzi~fo35dkPf&(1FoR09 zrY-V7CfoI7_L6oc@E5Y-k^T&&Ebtw@gk?|N>|D$;KxM3{>87{8yp8lNbxCz>>Ksw& zCCuY0u+|%|S3T}ch;yaqx5|u?Sz9qdb=&epXy5`olYrW)nd>68jD3%j>*KoXC_Dgl zot=UefduZE0n0fuh&or9)t;Y5o|F`r)lPuV38J8<@6B-*anhsT;4Z`)Bb90Kp1YFR z^{p&>8sO$4JQe+r!rwS_6za2mgyPC8roX*#wkXsQnJX{2sVA2`A8FKFeAYN+)KgpO zF1W*u1Dv$PRIfSC5}0g-?Uqyp7i0-zt@yel+r4fT9%l}+xGjB(kLDc9X^B10&1Zav zb6Jcwso6d*ar_`^(YgQvAsQ_&B?gDhQ?YXd*7Q|xD5kSbjI}WwA_bEU%4#Q-)PY-^*rtPnm>G8li6LLzUyHJlI1?C zd9HubSx}RXvVwcE>vL)gef)s_?A?4yG;szpy3afx=uo{n6oAK3cVQ{DrT`S|TiTR~ zryD6g9XJO?OZTIIXj?z%qQYjX-5t0!6UdhJGGvG9a8?$ijDcK~%*yV}LFrJ+h7Wd1 z!QQNG;kQtL zmTw!b+IsmHPHgBTJZ?5Mg_Iz?9vBkJPP&W-nW0)&{syf zX}gE@t5NyjUs@GYXBRkmY z#{4U_eL_1eT>H+n^$lm{;9Vz}-n1pUrJD$$EL2BzWF&lAuT3R9qu)FU9#EfM9|Z+g zSq#||3#LTmyA%=)nMa+LbE(1USXY@ZTTLB5O!cy=Te}6V2l+5c9uf%%7$Pl9#1$%h z#UTkLvvfF=EighE;nj>W3A=gLy0^matE*MkFiA?GQOFvf<}XYc{j%4k=lxQ9vNBFY zc377fj`@~vSB(kwv(hj>G*-$77bd2h!HM0{f~j&vw(kslZ{B-EN$3-qY9W&R zJhf#h3fg$Rq**t7TQTG4DC4r?@`?QX$9Cx#+^;y!Va~&Kh;4(4O@7jCyKK)Iz&TR0)26c$S~$30Cy}LyzJ@vw z0^pfY%g`~H{H=Kj-pT%wFTFxX&XDwGpFGaZS{><>BJAus?`q z+MMM(P*!9wp-p|51E2=VPBDp{fI|EM;%lD-9{4@G8b-ytN4bpj(Pm2xuJBvFX@}2I zj*q;UkXBB$sTEA}j6~(?mnByJWWNM3w|p=Bt0<=Itc`2OxeHh$cVe-~_Lmtl5XV|chgJ&p9VtcC-C){zGb@3m9dA%OkznUV zIjvXGc^eLQw61kVq{=0jOUSt~r`aw-Uz@K*w_Qhpa=a9w$w{FZtB+D^A4+HMcn$-h zykU)bNAuJBq)d)oiKSLc9$xP{qmSin0vGFeDOLb995T5L2gzF|`p z=27NSA&bgf?1zkPHjp_uLNu4_Sx!{gBnFzOLB&5VHQdd!Wf?Arbtlw17J+S7P34M1 zRSPBi0sr#?QMX&SqUrr~9i;MY-Q2`#^l{jtd8lq{| zH!d5+Yg5-lS#>wh5#ay$7M0r6j)eBnVbtBn!3@Ws__I9qjc`py;g&+&$9aHyvaO;4 z>4$IcJn_i#2L%;Thvjmjm5MT5TpfOQQXTL;8EgozsLb)gA_aeC3B5buT5J8K$~~+2 z#XxX9btxDnH@twHkMCV^@j$U(ov1U z5!ZEz-UgVU^#c7ckLaIJD~Uu~LyTs9@nu`xra16Ni-{gF)g(x2O>MDM0hPSzKk+&U zOZhp=2OSqeEfS}pvUL#(^ir3>biqXQ(zbN_8I$~>Fo~S2xgTU73plf1)6I}WzJ}0bxpiB|fJzKg+z=*~du-ZIZ^GPBPC)I8senLQN zZ({#FN}wL@)HA%^KO!f|c6@hwTc7>1M#F!*M4R2RG`A^HP`mIk%FAGKbJEKm$=3#) z@zU*%P~RFQUKh# zde_Twp%ypc=8P!+WMcBM)|wEjR%{G zo~1D3JX+ON@~%XhhlQyj=Jk8gkI@lfy^H4E9rmw7fAnQLzFA#?mcRN5VJ^j#FFq_` z^IIH6i;^iEV*XaVYju=^^`pl%@cVq?&QoY#p*nNmtq*$`Nwev#Q2y)Q-a0lm(rvYh z9;zNTmU_PPTjfK`2s~ZS{w1~&r!}@=W8bH~Ev?o5WW{fI7&@sL$jRJsp`oXI((|AW z&*HhFhFw70ed^F1tGN2ducKb*lh|uIYs3l~$s$e#buxbcVbX&`6=CjCZ|zClPuCP* zH@=ck^%dn5b8A>n2;{K`@#ipHEIzzAiQA!?7k@Xf#=D|;@7e)7EC=-=4R#ySW4j|XaY)+d%r z9(_|Wa;9~EIR(u9e>jDW8 zOtqx7qlZc|H0~#nf+lNbE|U0je$l zo`_{LT8a<gZebLbp25mn|$=KXSsam3G#+St<6F_*E% z&qKWswYDw!8qgT|XiSP56?Ny@my_6~FBCD!6t@%HBGG~wlH;-C+SJ!b8j_k?<)bVA zN8(PwXF87wqeg?p|9dOr21gI`b^>un)KhTWO_ZY zKt^=OA{(gn zhMi`(FCS7fk?f91)~5Tz_TZJ#HKe+=bL1Llz9RQ<6%kNitMqQ=)N`@6fx|^<>2ZBx z`E)H|q}$QQ47Grvjaap4C*UEZ8k|Uf71$|J5|X@xwb@+uVDkl7%uy`)FB;C_K(P|} zGrT|2AT}X+sAzwW*ZaeqEITr0z!1k@LZIu<$DVb`<`kgIDT=Qr$8x}q#x#a4MWLNt zp_CXsj{B+?^GE|+_Emj-%uo_>hE*iGYZW}7Xml5eS=p*uWKnng{=sOKFwI5eZu>D$ zE*E=_Ey{7&r(JM$jif=zUqV5-sXl#mXWu)!w;x^5E8fL=oIkd9{)nG3wYNeQnX9d5 z)Xjp7Wh=o?obk3^hGM41KTZK zIGvKS0*KAe_@2e&15*uO5(%u%ZFaWZM@!X^COF^NqiqXAVFMk+9fni|_Cd(`FTr2G z9#KoW0qI(#L#_+8=Dk1#ef4eNs$)KR$@op6Ym@KquhG&$>zp~=(k*|#w9MJn z);34)m#qIxoQtGmC{0)5maFKknf~(ftfZ`4BXKU*|J3$L;bou z5aZF01#me)X_%SmZv6TWuzn+{5uHP+9z{3&UVx)Vdtq?D_KblPlQ^Qtzb4JYBpysj?#a|2hsfcka^EpBe}gX;8<2_Vk8P{Gd`6R&Z- z)gKXU7|HrwcxK3`r+|s_4#H!ZhHl40BVI$NlaS{31ifQ53nLC|q4m|T!qEg%D|A^= z+B+P4X>zqWr86u-xP2TNpn9hC83eE<>;`|K@gnYZ4%SEZ$V>CogtC5~fsjFJ%0{V* zZMCi4i&7#xo`y=qj9>{*VL2uvBLHq#uTrtG=azoXIFt)HoAx@%;$A!LoV71Uk`|Y+ zi-hM}#U}&c^~CyWNX@NeDA?JXzA+gu5NW2A{|(!>V`y_g`DJz=S8P-aII{-{=)tDTLINg{NMR1F-W;1;I(R&-P~q#kWz6vJaHYW zr-S7=9_No)SUg~6kCy{?SG}-a&$kpr)g76Vc&+v9P8t%{12V7*Kag>7mgZe-TM+veR)UDCsIV>=ftv_Byd5DnqSNhPVw#mi7Z9*Wtv z>rLh6+KA^yHWS@11nRzX8&?hXXdFV^UD*rCh$%dB2-l;URy}$sYU5R)%MIJqDjcj% z*=Zvwk50`ioj|w}gsE1Lnb$UTJ)avW0W#s0mknw{N=VayY&8F3;2rktspdSjMIM)L zy=AzMguk+L5rcz*t|SiSSKF{Q8;?Y=09@2&l&lOw1U4BSRBZ*)=4wrtmpo(KzNCqe zkdba7{WSl;azHY#i<~3r6oVYv!qL&b?KdI<9UQMBT#F(lw{zR4wIOOAQ3+zbSKf^I z`KS$Lh*S3zKd^3M@%G5%K4k5{hN;`E&d3khuJHP5q1)rWJTjTjT#!w|2Nlhy89(h7 zEHZj_Ui8VPy9TOJyk@QYJl+&SN;W2GF7e*?ZW}no2_YPRu=98de3q!qS*#^ULmTUP z$_6y;95!Zs75yMnpzy)hb?9+m;4$3_&^Pt7mN^JTqc~Q@tUKm{jgmy_j ztMy(q{*0`s4wBFK-+uwj^>H2hoZ4`Fg{S}bh^Yq5SCtovYS)$ZYo`xI;Ko`N?#ZjuZ{_q2=>4*`7WPabOq?l zI~^<_^x?IeX6z5Yvm8W+P@Y*Nl*Ym(o|gQ4xOlAYxCjT$a;2-}~RZ;Jkq!5kJq98)H~DB)cPN zBO0$wY&8D`+h?~6kHal>)0}dZ1RGp%ry~W%1gw|3al)kVQQ~Uygj$f#@i)4C*}P3#SBJ~1 z6Q$qAcy<+L<1vz;G9q5B{G18?s;?GX6+SX8HlbTxBiG_WTqjED|KaK#qa$sbcHx;| zVoz+_wr$(&*tRE}*tYFVY&)6Qww)!fgr8>5-i& z27tZdeeZzj_r3`?6;d}=4J({v2=*Pe0_I(ExGrT^*U8}y3F?-h{uZht=JtiT(%=Y`~ zXuY!;o1|f4jVppikeo*=>Xg$xa5P$gYe_zF0=?LWJwPi*of=mVaW3j`gqWQ}LPxmE z&^Wdl2;piOiiW6oY@g;_9diUc`(ta|NnD;T41~Vzi4;49?W(DABlrHarRBAz8?;iI zfHd4vC3keYZVne$aU{K_|4t(YGp`+sl*i%yJ(Qz-l@NCG+@s>G5b)89JGkFn7T?;H zD>F>fuQSB)`iq#U6_dpq#+xA8%Z5ek+;vLm$_?X0xJ&3JW2lx=E=~db>vcOQCJW|s z36)%xAMWDMztk7R$eR5(Fb-KRNnIlwU4ScCf!vlX7u?lf7=p6`#$4nSY<%dJVwQ`@h&Kb=HDX zrs;l!J7XJ*8Jso4t+dk~8lg*l?;>nVYjUP`%iGRhbBH78!CkXdQ3C+wj}9~t!eoG7 zf5Cq@4#=Ri1C`pC4-S0ui=BlBb-s+eOZsw5x`Y6_)qX1DcmI!MO=lO3Cf+x%OXB=&BBr{!f7jI zs_fh4BUm`k@CIc;^78+f9stQ^&>$O_^Q{x2JE6uklNqEh2x!yVVxokz7v9R1V8V zjWiFHwZqLgX>v)Jh}HO%CDFXu=pw9`U9ln3L0A+iek!YPxbREDtwTrtVTMgfT{XJk zkN(~7G^TH~!w80p+&MqkACtu}9PpC$xKYw1aql@7$h>dohSAoT+TwmGSY}CLhj>+| z1$PF3&dhFx!`apJyxk7UW!%LC6t%WlQe5yZt)N<+X|bsO3nkqD0J$8hok};&Jinxv zDU&Rra|WC6snCDIgt)4lo+`kc!BamU#RvdzsPJzW2nLD?&Xgvwq>ilK6k+u{{n;d4 zpve_uarU`?{T|SB#1og(7Vwl+n9>iXMyMPr@Y6Cs(eeEM=>i;i|L(i%vO*+??_)+L zB60)Nm&=A>G3zdYvFjQM_yR!jH1D zYbEZ=7N3$pctSl-uH#4=){YjVi$hBs09G)kx?U(IaRbBE>-1i~_$FKCrMB%y=1wZx za%JyTip@YHshi>E2;uYl+>86gO)M<+#s~)s`GC~m2m1u!FpGae2Y-(-y|u`}V#{9n znD<2crDLVfv#Pfl*HyLvW!GJ-;BaHe`P*l`-YO1X`;C?mFgIE`kbW})`%wfj8Cv3h zHEA`%TLd#TnY@7_uS5k2*UjYlPE_ax%1@5O!c%~wAlHWaDz7I2J`qkbFDyFJfTe^t z0I|<&CV&ISiIBLDFSGEfwuVcxc$Vz={}ArKu}R1ZYS#GSm?a?;yD^FsqM?cjeM$zmkSZDH`&3vw5;wOZB#kvAaX+lpDUK62ll z*B+RPxb1{iGqXIEZ|SAKd;#4c;w(2AT0xNR5#w={OW5i;r|~N0iR{e+(E2^JiDyTQ zj`<_B9yCxtKh`AF(blBLH$AfUpPgy^`shUkG2igh6n9OC)KQzNsit=4eQMI1^pAdf z-s!BO#f*JzbhCMLCQ3e!6^r3QaCQU7YUeWNeUl&C_&;@j(9X&`C>qAx{L$LF!7}Bw zLV;h%9t__BW%Ont#9FOgyP6zczRHP2Qt^Y~EdKhq7e6dM?)(=>AuObgK_!r z2@z=Qn#q7KT-eBP8Hg%yM`lFlK>!C6_=PKLfX>2N0-~;`ZWw=dnwbvPp7vm*;7d0& zGw~80r>en1Iz2OA>!%;g=exi&z0GPg8S#O{!-_&ry;lTrFYs}uF3XfTze<}CB@gAf z8ie*XwGd<;WTz=m;f`HV_bGzJ`zg<)hv-CH(7Z;MrT*Krvi~8?SBC_1%OaPal?1$o z+Sbl<)IEy%=j@UA*7I*OO~i2|QSjA1d}rrl zl+gELKU??+3y>C%tMqFaVI&Z!^ftg~6-J8anW6ku&(#($j-jcz7qV@q4g7`8_VDYG zzTiiGjo39O5RQ>14B4*J%!^Amn>fh-qgqW}gg6;I-TpvT`LT$NKH}DfvYVX;Qu(iv zkr~9>xW1iJl5$6Tkfvacv}Wj#<;X=s25i>{l>Mo~{RI8b&D?TTgF`P@NmOXf2|==7 zEhFs218Kqt=f$DWR4v-uz|Du3f_%d-NtO=vZaawVmqs$76%>l0d_bqT0C3^c6l8P) zievh=WMUq&Dw%u?$z#>>$)E|eN0Hs%=}Uf#44TqM+f~6 z!kkUG?b>s7>2I*KrOP`fHM^|Ln@?Z-9Ox?d2b3ry#l$h)NN7wkRX3l_+V8}L2Y;1s zRLc8)U6Z1SHhR^PZO6mcVN6uP%@H~hJ*r=KK5`W52atP7MBeH|zg!zdX;?N)Vw{xK zacrg|&y6|Lr__0Ktl!5C;~e*}yc=!)GFT%6i`^GvlwqhJoQa(l4w98dyU1#x&GNJC zZwLk9vB}kPXD@(cU;G1U^Sp6_VrI!cSZ~U*hhFb*OwI<+cj021AscMGVdi}xx7Z#C z5sZ+L`$NV3ILQRU`C|TdTykNmd!pGM@rS8FoN9nj|IcM=$oqpV<*B+h!n)Pm(_c-M zS}n&Xzu;AKDx9xmiQCIR`;evb(e2NL$*QwiGgoX@?mxA>7=ut&J;&w^JKastvRQ1Q z&19+uesUekP%}3qbvEFM&Mi`*~Z4g)spsEskuOduQ%{}_oM-MGw$e{=}J7*L{rD%QW@ zde>gjD9$lHC08)0(J|)V`x;>qqBp|F_p6hH9W6U zj%{+(Dm@;-JJDW|S8+Fzl^^Tra<+Yq{jA&>gO2W858r=mn z0Exx8cb9q*g4nUS7LG-AgnrtSa-Fg<8H-7GyE$sP@4Z$Esf^7CcvlTi7{cL-JU=G2 zRDcgEfde+cXpfz71*;UJP13^oOI2&PvGq&SXsDB3D>qxX;&pwc@bnnYqd`|GC!>AB z)Obw4mbv7->xJ8=m4HGmCKDt@Q^znQVTnnm=@1O2csD(yfbu`X>lqU{&xnApEqv(y z5m<{g5j#D(AEcw>U0lN4U-T&|7njr}gL=6Z&xr@^BS8CHM#!#EeULS#(Br|rx!@+X z_Q#N;cjFa{&2myuMA;r=aOUZuF!uF|K0i!_6EO;!tHk@owBJy&F$+pM7nrh{dj9Xs zkLFigjmI#T9VKtHg}W)a3#Y3~^8J9$G11llbC*4==gyIxTn&+h6+xZ~IbB!)2LNS0v;-aVg$3j42n32IiSsbwFPqrA?}77FS#!uBE?sev>j|d~T_~ z;nw<4uc&G$B~TtZza>%Q!BTZVZ3;uW!H+foUM;#}<5m``*4<4tAUSs7BL9 zv~7i>BH*>oS0&t&4$-2lH{GQ~vE^(YW{%M`n6IKt@JOeO)y&qUQd&%DuZUc!A|tck z<+#VOKy&=R6N5mvr~uiqk&XYxh+)yR)Dq1RiSZzcmuPH4)JQpFN@P=%)+Sq3ma?|R z?l8x{v)XQnyw#~RSiX*%;))NTtXle?1mgg6zfKOwiB9OuSfQbJ!=@bfhA;ml5dD&8 z0oz|syKv-kJ7hA`WX^Gkj6#V$sC=FsW8R{&&vJdO+}E9LbUKA5qjh#5GI09y_xCit z7!+XPB}8Po8VP9j2mE4Tn)puTiFzviTgN(Pd5gTlm?>ruN81Urkv1maRM%Fiim57g zP~p6EGJw+67G(*O;tfPy%sR}fBA{On^mn}0DtJIJu6$7g z%@L=>gnCUOTB@GII@QWkdGJhY2-ZEnvXIK|y#l#{Fpl6&lr!NyCfU2O(385Om{? zT+aC4dvjRt*^+0cQdW$b`y=RB7B4Sn3Oluu0mv(8+}R@otX;KP^MQ)3R+k*Gn5lt} z4U_l3#(kchH~3b0_^L51O@Dx-wZ2`FmP&92o5ubLp#At^3?ob{aVcLv-bXjMzFa~2 zPZooT_(QmGuJA~%4VFixn|T1Y8HFz~L`*XCgls^D0CxrVA64D*%(0ey?%7mxRXqzi zQ%pu`PQkffhe7xkt$s2R)Ii zK5-u8{i1jLd!@25tui-}!ZMthB0O0E*h#Qh;WWU4aH^b}08BakX6nuSy!sKK!O)P< z^v|y(_X(MIOvROQ%3d=*kkFddNDe}wr$BnYQj?=ak<1&cIkedjEIs`Q#E;7Hzo=e6-D$3XuWVTfTO| zSkhUorVVKCAmAtN&tH605X8P?eiV?U*o9eI$C0wDBQfFVEs-5Bre%?t(l`PwYeda; zN5Y^VnC_Ynb!8M)#Sj4wQF5!s!#oMBSC{hZ)2k=jT|ev&U z%Kf0s5uh_3k+kAvptBrk8YYHB^d0U-u(vx0yN?q@1y*>%g#P{-O z-ECjS!iVP~YdTTY6TRwu7r#ekvnTOoq``J~!-@0xpw#44_UOV$JGfuy-&_M(_Meif z>c*6_u~oik2sK=Q885A6AfIGwW=|434C1N-O!GdgGC2r;ClB2%^voqCSNz&-Bf^2Q zX+=3F1_~u2D(CUP+Ty`-d$);!EI04(^U@8`n8!n_pcc1>g!B5*rt;OWw6P-tK2Phx zv-g?``1c%6DK)tl9oK&mIu><0>jzfEGb zEW^VW>Hl$2Ozxt@`xG2V9;GPZip)IByjTytc1JiD#~84yZ*IQ&YH-~Wb;P-X>sU4nLfJdf2{*y_w!v*F+b^Gj6N)_*BY_;PPTkO^*peKf_Ew>AxWV_$XzSn#mN$tyP zMtRAp8LJ$xci!x;Id}$4_5m6RLa+`H6$$CY1bWi=^Y?CXLFt@=ocp4e=-msvhL&*9$Au zj#h4_uz2g)7-c2)kjEjR$ zz-yKJ$A{BMLBp~NK2snjW0)GwibIr?2O_Y;Ro+)M^WuU%V*1Sv2^auy*Z14YXu3Qs z^>YYMQMOcBjX>@$Cn4ppEDwSJRYvcZNkHeZSE$r_3nt~-qsgNiEuDA1woRd8dlNyW zRy4_`Z$+TKG}-Lf_h$=2Y6-wG>_0ZhGf$A$sflT6ZQ+)3MSC>3osTLY2qxzgjtnJf z#awZgz$N?oT;N>XSJjx96h#}%0_Oo5+fGPI_8?3m)zsAB#NSB!(Z;+H3|7#V1Mi57 zgTbBQ>9oH?{ildDzKt(hGwWk#5u~+it3ZvVdvfMYG;GE4#efU*Q9*5IpS>Kp`p2#(_LKN(bjP?v*xsA~J+xt70E~-zGvl;EMTGIgql#-a5V*B)&+$ye)`%c6MjQ z5<4sXf4qr-=GB7!W=bA^h^~-(3z}eWc|6nRnerJo=wvGyV&}_&ZHLBeV5aTo)jdyp zSuX!iZqHLNJCS34z@p_pOW{p8Gg9?Ban<*(>0PE^Y!x7hQ{xr4ZQ1ur0E zqNlR$djHO6z~{PUhAHY5mBphQD_}k&DlofO*}t<5 za$o<49oH9!BYw>P<8^BPe|epTPj&o{pX>}jVy+v(3Z>~+OctU8P7u80Q4}SDy&4Nq z*tmUq&@tp;`(c%dh+6cdr;47)su?_uQ1O;2Pk@n*yxn#Rz+=BM%PStrjIIppAV>n5`&A-43oMDauaQ#A}Jh`yreAnD&MHx=Fht zQ}&FkW&UtB6}_+IAKl&GQQ+1{{iHC^Fz$`2IObS&_4%+Vg9Q7YK9w(B6%mpMcw zpXe00t#HI+KQJLm(uR0`N3H$iqv~6Kh5meULS9F?_ib+MHY#Xd#u#t>I2Xx2NI=^d z?(^*HJv6)4`LonTnJ#?-Xr1bQoP+nr!YKmXfTBnitdCE!q3Ke^1bW2; zcYF*4mCl+{0~LWw;g}HJ9`Hwy$FAwWSufqoysT^UYs~Wv+}nY=4BDzSdVk72bvHg< z7c12BbzsQGcp~KGCjos1nY`2pPQ`M( z-3!Mxa5M9iMFl3^GBGP~4j%u#Q#i*}lB+~R7tZ@0Z;ongC#7dqyxhFN6#79}!vZ5P zCM7S*-hPtazm?;tvDFnDAcOEHQ02?!I+n1C4PYyJ4FxX5liSM|M$KDZfi~}S~kZgoRzKFuXfi4j5a%#QaC>@fqij` zoy+5po}|MmP%XBuG#eTJf7#Go@S*=!?gvW$0pGA zp{}g(bR&-~$J^>946@shPHbqHkenR8swv6BEJc~G%hhXRB{6SgluS?(EQi75Fecvd zkOFzC`OkBUKrbCChd3o&)}$s0b;pAP$_u_i)$KJ7787@R?%B}fp@ zRRq4(p@Z^1L-P@B*%ZnpO}DUjQua#@p^>>sXbg(_)YA-Teqb>Y)W&iZca^J3FL;)1MC#8$RLbdyy+}bz4wy((QrkwtL}}4mY&Eq5taY})5%|TJB{q#Ol$S* zt6yLl5;#|QzrrrFf^yq+pD&!O-sJCt6%gl=qFbrXIweu_si>D5zK?Du+Bo=We8f39 zs_ecU_m5bV2T&$P5w=n-EB{z(pYyYlhKcBxe0%5bR!@GEdOL3i#moaYpe+-LJJAlIpR6xa`diSE@};1Xq^iP$j6fAL~9`GTUb>-oyVJODPpy z*c-5kW5Lso?f3dtk^0b}snP8T=kCByX2Vn6@u);1dV9peEAG1zf}Z08_n-uy>ie0L z%5IJWVgZl;WyqcM2S5!o_-?9h{JJ8;BJHfcZH}HDZO5lgJ3BeT39+o}Lnrj%zKh+v z?ce*I6r#SqUPD?%lE1kvVN;+vm5B06vT{Hb822dySaiV$p`Qkvu2t~P1H9l)xFhtu zmt9-HfP#L=NpYmvJU9uodEC`Hds4t(a{AwL`O&1YeJ4T7dsXmTSAS?w&Q@{bd`Jpb z2`{gVDg%jEIF_=aTBQ8^Ui@>;QA$-a-b8XiOq>aV00W>PD|kOgrqgnt?%E&b{UjAI z3aJIV-KdJ@>XW*8vtfI3VM!|@Aw;vd_bL+{82&5K9|9cQaQQ~4<-YKBC?|&n;<)D?NHg>8h`b&&2?q4$S0b;b~|IVUm%!NGtk_nWF^Mh-6q zF>!X~ztB^@Qz2`Sr zRJIVm_McEaCJ!`-AUn=$LKn^@56uW#D+SHki;J+op_(lUee$GHjjhCxUMCqm-hfx&j9-MwgI zP8)j%Nfzu!2KSigJC~WvNJ8Y(F3V%iejZm503LInqalDkG3DW<*<7o+O9Bw8Sj)gWEa859V{#Zkz8U{4fKNDrhp8OG0cV$tUIj6h#5rS>X!-SxNIr+DQW)H$zJiJhrCGl-J?rA|=HBf=aN0*0v__C@Zia&~^@k^5NNZ zwSnRh^Xu6dC9e2j9dwA7o$XMBo6S?E_s3X2At@6`)Wz*yFZ{eVF(Gqt<{iH=?Oa9#m^japPX73(V>#|nP{pNpu;{@2-DCC{ zazT65v4t#|(y;82CxmZpXLp7zP=C<-mKF|uE@y0<%>ae^_DEEE*xE>~kE}onM-{iH zo&4#{%9cyy!ho@SDh6uuiw{NhfqO)E;R*P>k^)J`BOAuO3+o!OR5C$n_C=1`acV5o z-anez&j*@^hydzcBvBEJOuDbE3SU#lI3b!)%&>4tXee;0pb#`0^<+*j`Z;}*-EZK? zffLXBNk^l`;$TVz!V3B(@rQA31-Q{Jlh2NW4Ho$xTM8S&WLB)%??)A>9yd&x%#_$< z`kK;M+tM!9&ZLtxJL6{G9JMbmg~Q;nFoQt(ap708cjwl`UW#XS{clI70Ym5vq+R}z z8k$1@b9>forW(y*M7bmyrnwRV2$iQ;stR5L@OYxKXsaM8cPW#5KwFy{w2FqG&8ATzy0+ig(*c#06$CtGPXIJ{?+_ZkTe7NS9pBiw-^%t`EuKfoX!J3{0djhd(y`RIDcNoK+kI z)^g2KhQr>ir_R)di|#+m<|W%c#sqvy`Ubq%zdB1~`%U%jf_k>NMiH zvDEp~PJ2w!F%jS!d9{tYY}s;3#neu5m~wJ0W z1VW?x!PXNvnBSQsonRa1Ta2#gDl6Ou+(dS9Qo;=X){9~s>W8-I=|%e}p_=kaxuw+| z%_se-uo94AWxd|2L-qB#GbHLR!C4tu6hV()tVvs}_Z#rPe-~0GN_kUg!{_ggHn8v6_8-O>nVig$ zNP0e&awQ%7!3Zoq{8Fp)S`4Ob5*-mqrl*Z+*@k01KK78ifbDNQi_FEfy{T-(@_dsc zY^f&=W_#u#R@Wn8FL(&Cu}kmslgx+;%}7t3U6XsSo0SZnr#w1tONe1%AGMi^sVt7f zzE5`3udZ`Ls7b%9rgI|Jd+Qv#tHc%i`pQs-XmW#)rZ8l>0EVGk0X`hZy^^|&{X+() zCWE6AKmkyb@`WGlS=WKrq9$VM_r{3}`8)C+*A;*NNYB$wf2(0NWIk>`*RK2dp=(5` zz7o!tqq*t+^z>sIZ@P#q`VST)*xcR#KKq{iBXPIiYS)BpVG647sINw8@;vI!P1urP=S&1_a(fY5B%o4le{VX>THgadM^&H-2)f zA7pU2ri&9<&fSWrQr zKOkV?F>o+6a0~(zUX-6=^lf#jVRu8ww?V{v!0A#t0s%>p?OG1>-h&m|FkcIynq29} zDy2;RzE@Y-QT+P+;Bmya_AzCM`bgU3hm*Z+2|ozQc)&h8wHMX{%Hwt2pEf3Ml^pjm z-gi#RAa5R0SS=_;_S73~SbFer53sL$#_(v*@5_#MI|2QOm?KM&CfoY$5LeY2k-QP( z=Fnq98_PKX5_8Cn$(6&xc+jIu_FUXqr5UjoeNNa2d3 zq9gQFJ&|WIJ4@WQ0}5twVhoxIH*0O2*C(X~C`S26sK>c-ii-*iYMMq)RSP-~pltE> zt0+I86EnFy;16Z+BEkjQ$w!8bg#YS!KTmnCA@eO0kyueoy}b|>7K%xErD?^WZ}$TS z3;%9!&y5sV=D^o>Bs973qK?S* zMVyKNI}sitWpU#ZChAKc7tjsY&e1@kFNwmU_{YY2kmPVM5we(`q7=97UQ}%ouFyjj zqoAANe>(erV)p|NLSsewQ|Ce91MR>Q2TTVthA3Iu>&r!bvm+E`1VEd~6_eJO-_&@I ziy8I&Y>zCLQD^>P`BNRuKsYN3P+z>4?R7{@Y07ac^Rlv3ixA7(fWQ}kay^5~ysce_ zi_qCMA5a-firqlk+xT7oYfshNdd=AdE-R3UE+BX$&#E?ay~LiOciEQu)CwgXC%kR^ zx4%!W8I$7)~XuEizADIlMpe4@&0u~rsmF!7A#e8>beFm46`@`Xci+l+@$9mwUjex2AIwM4rwSb0CUD3%h+=L5JSVoElcBT?I-6xJwXV1M&kc7t7?TsLm zp40VIC5?O)7ilfQ|^ldPm zZU8y0xV$Su^? zLa|v&Y41Okgy-C|2o9rAJ%%qBq7_Y`2VOB!Eu_E7IF#na@aY64aB-k!;NNdjwzkX7 z#nS%I#e1&f=m9Bst}`LVEc95xya_es!r`d-DUt+$5>%x#AX@4}H-&ew1B~ZA-;X^@ zu8zScUh>Ox!?+rhy;EsA=s#v{L>cWm1;`$O!vureqvOghdtzj{vBTx!IqmH)Xvu<)?3 z@U;XZ{Di5%(j!qL7!5+&)nk~dmR>k+ps)I*Dj<{;yGxW(-W zF@9{2R~-I^Qo~0mPKIr?H05fRAwKo5NNyxcxflb-zm3U18339J`o3!f2sOS@c2)1Z z-bc@@7mqX7akXml&v?B zNw}CWt%!`PPZLw7@#WV;&W>WURD_VSEa=KFW%phC38sqytU*$#80fIFywOYR&7Yi@ z-L0+>g#cFkvmkw?)k!`(PmE?eE{l>;T}en&+3bSt^(_ZRUCx2s_#)}waCdFFF(5t_`M{V7M6a1eYSRQDSCg+vBiOddXo$jC&VUo<`}5DBTu#T?;4(!%m9E z0Q_GCV}>IaO@^~ZXB8c!4z{4`8s1vF@~J zA3RJ(AfvRH7WcKt9-l#>tjz81Bqy=zyzXL%A+=h-XseXmDN@tv9c*mF5uP4{35hV? z3#uNHTc2jFRPh*ZRY>d%dtiG`krt&Hgj~D*ScFk$&aWvKN=#}DIk)>!XZpgdVdz9e z&r<6Rt|H4Y;v<0()nI;LIJE!(?$Cw7Mm@qGmsgb{9g*8*12!>J>Y2~)5`qR# zY{}ZzPqs$lTCHxtz!ZJB9DWNiCF{6>|NYitJkE{3eK#hoA=#ac7&B2ulKCTDvEGz= zY2ij^3I939q1Eaqrq!F?IaO9TCg7&^_;7G!)62hF9V3432Vq)NfLo4K-;^u*{&iu^UT7@r|CiVyVu9+v+mT>yR%Fy&M}TM>3m$Lu)b%v#m5cTRg; z2C!8Z&|Q-1+OxT83Jd5GZcD1{sYVs|p(!{+h5>?3i%6AU_sZUMV4}!W-7D!KF9}L< z$=pzYsKr(PnBNi|aAgC8C-Nv=uVx5nS-jA3l$ZwNN=`p*9Eo-k`yr?|#SpVBSxhBZ z9B+%I7(VA`6+*|z96l__R#<9ja$KxZAy=rmBsDUq6tvbN?lBx45@q?Zvx}OrGWgyU zmR3C-bYwPvrUigW<`(j~)yJ&d84&Hz^O0%wE(?eZGta_{K!m?k7Gn44bx=50-1kD` zICxPAjG4Hl%q^*F8V!FkW2vnbwa58Qf}%RnfFrwo9Bi%IEdSypy3c{$fqQ0jGflcS5gcl1>gqjBQ~g8 zXM@BSY+$y)iII#;!eL`o(RKS9n+l|IxQ5Pz`1}%X@7s&@8*SKZ0hxge2rksy1zzw$ zv^bZIkTce5#ZA`uo}K7qz>u)~8%m5-wPqAfI%rMz^#LU_1lZHV0LpOm@b$H;wTqWb z9iHXp(9OLkr=8#Zg0%gHX3&gmHKYf`;q2As<%7&j&|YUqfc9LA!{BZ*Hhn+hydcll zySi;mEnchfSDe>SU)b&N1`^1xaLgfkX47m#qSEpE&Sw$b;uEN@Qu0B%&2RATB`QO! zwct;DRB!pt=dHwF%b!m^l^cjbCzvF*%`CtBKefc2Md|#GTDEgsE&4L-xT4f{}V~pD)vXe@iLHH>U62C-HZyCv_G>D>RFsuDZU^ zHlw44_Q7spXXYeqhfeKVCznVpZ{}{%Z7`{aObUrtR%3`sRZC|I$xk_l$gF-6NvNKq zkKt50(Ku(o2&nwD>B_&*Zngt0VZFx@u7DT@fa3k!kIMNqT2?+h7S&*{cO%C0w8VxJ zIX4aoTAi zyzR89Sv#-xM>KOMXXu)3E)$m=DfyX@UMftA6DXf0aLo-uigK?R~~${HyP02tgF>D5gsrVBhC5apBO?U5)z ztFt%Zr{)4}hVxoX8tQ#VyJ^QJ9Zr7{Hv6;R5xgnnluOUkow%{?6Bb$+g{^3jx~DXP1N!?)y` ztIis#ywLXU-qcBqV99u-*}V@qqunCl2B+F+D(*Ru5jH1a_JsC%nyc#cL*O9vGuVwP z70#bR+~vJk@NN2DU=P;w(vs_Ud=r)wI8rr8l~xqIyz-0@Dn4tnMydy;vah8ABW^kj zwTj_L)MIfYG>ef-I!uX;#TNs-y6>yIAA3ptjYk??mY0tq%U1{4@^j}w-E*3duhZoA8nV79KPjhX%;sa383FW! zq=lN1sTItw>pCf#e4UD%u9Uc~Y>Us}%zVEkkKcZLIRwLJ~-eCv&{ z`{#ATQ7Mhu!)f04YkyE08Y(}Xq&pmr!iutI1!R@knpzCl<3sHdw+Us@medTx1 zw}nH2&rRBq68cYNrq*`TLMGHe?GFh%hJ%c%jP1h;2xs_V;P{k^^|vpg<82(`*L zz35VU{8ay0Vo5J8RmtJqxuLGqyw?3OhZTZ0+IgqWYP`&E17abBBn+_DJ97#Su;Ef< zZ>M#wH|6l}ms{~!!CjxwG#PFTaTiuHq0~y(E>`Q?`60lf|7G#JD15*i=7y8Yl%=}8 zIf2Kp(hVaxWMFUvBUu4kwV>n-6$KHZ?fTU`}#zPyBY(Uakf< zBu3161k1C(9K%l$oRYeN0Tv2o@X84lY$YZv3@Su4ddVB4t`=j^8$UQAT~c9cJ5*Qh zO0sHwXBac9lbq!th__;>z0nm7jX>^sXo!J~VsYNMzGi$WG=9a%;#WqR-u3f-!UIZi z3qR!!V#dq6scT5bxUECaJew8493GCms-Os+P@jvSxTqDQE8sI+a=eE@Iq$Te88HZ8 zT;peeLMxZLT}?ad-_b^Rtuq*D@hO8da90v=7#s2!vEr(NVX3Tc?W8^wNc#1Rtv>R zVY#v7+M}{~rVD|BAL3T+zq1p=rO`9xOWa>_i-DX+@IkAsqDd4~1MEL-yE`-f#JOy+k6^Xy@zko zZ?AW{imlmQPtGiCxg&FVd<`#7mtdMyTaP`?N{S*k(RY*gmsd*2f;~TaNXmhuDkk3) zo6y`n3O=7pUT@M~V@9h|)$|k;jamZQ;}SnV6n(`tO%L?#WT*PVmi+dsb0^Ps7ILiG zgEL}Y-26n0lsgXz4jQ-FGc`%|(7$qz^PESxSgvUfe15LZXZ&5OrYKy{4>~oui7ErL z<DgJCWF^)q&3~lhG*m>8% zE=cDuD48mNGZ7ZJZA5yV`i}OQ$X`ryOH_qQ%}|C^|36*;Ie1a@ApN3x(Zshpbk~WD z^N6OIuGqj6q>Y3Po(}@u-9#!-JlFupsvZYMsJ&mTW?^_};vqMLNe-ga{DI?C4Xc&g zp%tpgW~;;<1h>|=CTcM~C@o=k{Q2@rwJTK@w}#r{wAV0NWAw??QM*`}f@3u_k&sYA zf&^DJi}?y79~`N{9Vx2rF4?H^o1%3!bx(=5wn214z@G;$XpbfStb z*mFNZ2#hgKkXsg@NFw_8_uNnshYQ~vICr@ZX?`^t#_D}0w+m@99PF0Ut~hxU75|>K zW64=vqS_R7+%R7I0^;_Z`a!IsKa1c??j9vHc(e$higlC{^<&VG^N}912^Ra>A3i18iGQ!zo}8E?E5@FKGl}ph~pv#8sG$ zT5z^A)L-_XiRkCv&5TpI4jtjg*mHUkq~)&lg*kY8VcAB$Bybcql}_nesS@m=dSi^` z6@E!XYRGC#;d3{}bu!`f44TUhER@~vvS}kC=lr^>*8OqEuczL*-gL$-Fv-ec!JRh- z&)(Le-LU5wpW6&ixf(yY=Z%L=~5=M@sUzsDz+R+4yF$ z1)+L@=hPqBqvyI-`ZB2q&lH-E{T3Yp5CbwG35e(#PZt3fNIO4jm1(|$WA>;}2z``$ zneScF)<&A<fMW|$QuGLJUbhpk$vYxg%2 z*Fvrz_gFa)GjOw*;>JYxems9Z{d5suet?D-$4m3(fO%jYuB$0TMvsmX=-Vb7kxYgo zBtn5OJgv1j;lkq;q9)I}4Ri53`ZwFMH@rC?HT!Am*?lk6}3DNyXEB3V+NsPB1XUq#Kf)uyoczB>&S5)QOrSINRrP_Bne zN8;$x!>w=Tq-M)z?9=kclNbAKmaI;{i8i#8Da<}#dB0zXMWv?35KngoH%C_YJ&cW7GRM9UDaUZnNhA^0Z6VAH z&;#{XgN-na4|&8`YtZ*q;`rv4aA*%@#`w=@RYXc)coMI}PmP24_x|A%NONQkRD7Ib zg1J6M&CQu2NZ}G$F|Jo z$yqz$H?8e@k#v8sn3X~%a)~DXj?uOn|9@niV{|87x9vL}+g8W6ZQHhObZpyB$4SSw zZQJ?BwsG^E=e+mcGtQ`w^{Hyr*tPbWzd5%EN5<5&p!5>Pt2t{t{54q6Aly(A4lB61 z$V;#0v4xb3j+HIBLsm3ZcUH^~vLgqy+Z@6G3UVE%&oD=#r9mK{Kexv6pDp<#cT&=Y zpxQm`)jp#PRg9(MBA5V3&MAA4s(JO{%Dsk5Ke`t4UZe?3+V%GEsl)vk(T2SRQlKll z4c}akSI?Q;CUqxk(s*7jbgmTkBseKljJ@erY=x5HK1TrU>p@xhh#(&vD>^hgW{a@9G|< z)608A&(-Xu;z^igD zDqszcHhw9%J~@lu!4`kstV=-x92|8!7PE>lr&Z*almM-iN`SRHzNPk_Eq~NL%f<4?X^eGwn3;&}>Yvm6eLNlyH>ocl>^-iQ09<=mzfw|uq_@zV>Zuj>Ktc|J-- zoA4y`ld?ABx;X(DrzwHCEGBt@P|ks8aKgQeqBOxrZ{leEC)N*5rOH81nzV9&i^$Xc zPK`dxYr>g>5)OwW7AG1<{JpdV?a)&MiMc>^b#0>oUBszb!lV`<+Lt4cql6T4CI=36 zxr3J0352d47>$ob@BOtHd<+-fn9bX-qdt>?qfP!b^ZkLjwDqv*rdl#H*`7gw;p`@2 zfbn4@2^{)FcJ%6gOK0+iXJ=ERj+2F!m3DCzUjL8!v1V%g&W?63EQ_`LZ!e-$d`$ri z1z?CE=bk3zRPZQ6W)ako^BXbz#kKf95JO>U&+~JF-}}<5JgN^{c-U&5WsJKXcug*K zC|D5^sdU1>UP|$p{h9r=v)7RJ_{<)3=!Tr}8r=T|{dV+XY2H)P1kw!+lgtTttCkdi z*2zh@(9<_Dn3fvlh>1CCywI}VKJ?B5Jh(kkyfwHc4WI_wMgznpTmEZjX0y)9Cge%aamf7njo`v3b`*;3t$AN27vq!|E5Q!j?bWjQ|4Zb;-PogE|Tv}DS}?R3S>L?C*8y7Wq9)e95Z@D+tQW$+?0GoZHdx%7(-_&-0ra z7GlbqY22KI5S)3dJUTkOP%pb~xQU0&j5u4x0$YL6UTdE6!12;)vGeS3cEFqKbKS+i z$L&<}8-z!oct;%cQGq>bspCbu&s3ZRq$Hd@_LU8O;jfy%LvE18cfuMN4;wh;^20%p zO$e)_I3}$OBrteyU?Xq?C>$B_I)6j`oD{ox-QNE0%AwvI+Qkn5bU~Unye(^o06H|c zty-San~BO&t5d(&YQD8t8)Bd;`BUt- zJ}qvEwljI}h72!NQo;YC2A%Hczja4 z5NEtzsaRh_w;x^RqcUj>VYRvCxZ|4u2;k-R3Qm{WcHOqv`@z`25 z5vQ^4ocVS{#M)qsRJC53MoEnfHVQ54|BiQCyIoqWW3}$>8Veth!U&@12d)Y2I{%Hs zL7Y|>_%f-r>Ykl~R|J;*HvHaT+A?1o8;x&+-TrQ4ls_o>Nw~XnHolFY6Z#&lS5WvD zA+yC3MS4kj!{;qnTpBOrhWtllju*OSB^u}EA)mX)CPUw7&m`LvX{yBPv&KGLh3#=G z+OS(?pH$|^a48GyvaSo*-X5dFcVKHp{p=B|Ht6I0(V5uXYZ<}_G(Yi!la|7&#K{GG z^6-t&frQ2BKFb~ueDmyy1~ADxe^VIWeF4+|LRSSeEvtEj;aQ=UmKd#9MVn&Yy4?uV zD6y6Y`{6hltaq;EPCq2Ly0DI~9u)1@ZElU5SmG`ro1-{b5P}?MRH#A3{R<|XG<^h~ zATqXaIOfqVIA(Zkf|V?ix`6cOeJcNazik`s2GAp)OOOz%?^e!hH@q|E!zwac@5@k? zvu(0&h5U86md?s)oNf0rx$tHYk@bRBWQ#*6E}bo5$=lU%;eK|mjCNAYwS212^)hwl z6djtgFiwzth*~#_fw)q_(2RUqOpmy5?$#vUI@F?aY#7~YBCJSbRhguFq44is>>-LP z^@dvw0#iwL@HSke*e|*>w>R;wH~x2fZ9K*TuW5#|x<%!vK-3Fyap?R+H}j!5drEMo z7_^mFQ_BADoz+0`jA;r+Us=5zoPP!4^3J>)uir_Uv=Fetj^A@R|L|-CaLM;~LB?l* zHu2THddL&~Gt1W$GEb@v|hoBfAb!)%dKCa~ZNN?*~Ec@p~` z?3uFu0^uJ&inDL6J%5VouSIHhN*_ggZyd;63r;1FN*VI~l3&!~Jpu2+# z_7X0@E_U~yTglXC1V|Ak;j{uWuOCQpm)?1VmCN|4+rP71hUOcJ51yxDRMSR%A)Nx) zRwH|)9`;f3#LflDC(*-oc*7(LdC_J=f9|SJK9Hl*{-U@#6M7i=WaNxFSB|`gC}|LS zAhsYFTzN%X-nmHK;@AGOYTGr-#>sb}$!CN2FHf85Z7oX3ypSu+5|dCC0yz5fwt6#v znCJP4fdK~2z4rq;2#4MEQKTE4AveDyxzhS1?W`gMvMyqUCu^a?}1f;uaB7S*&=@ zy%Kg8I&3tSr4hETGdLM~v(3mLW-~(jj&!IN2j8AvX3z7OBU*2MhoHmQ5I=bgkF{J0 zu0({I8o5iI#){kLIqe%hIY)!ymuc4u7PwH?rUx=dSh+&tn(sFLSX3FkQ7W^2i5_F@ z7@o9E9-I0o96w=M)K!~vd=E8jE}^(Yl&cHiOfPsDy{oB&T$ju)1HRV@&*g@Hs2%NL zWd9TTEe1M1B0nr1Xa-OK$Uzn3)rKWAe(LRnF>cnrCReua@r&;3_=CsZG5*FNokot7 zc8skLDUQFhYcpiU_x((W#w`J-<26vnuT?(bZ47@DdfF*@dQ~cVIWYDN+pD zFSWl0`zaSt-o%|(0R9w7173J=9o50mAOpePWLFY0nKnt6Cp{vwnKnfI&%SBBthqM-3oY>wVJIF)Zvd#T=X4jL!zN-j3GS$&{dxMwmi= zu}r~h>HS8dqTGL>VeXU8WuqAtfCweL;%1Fc1!-!4mCX*=&cctFdnDhF!6!^do%t-u z`4xZPe|?v#uOUrPfyptFpX?#!g!w2r{_L2k>Ilha{W$HQu>hn#|4k`GO*Px`MgULp z6hdEi zcGU+GC$^`jH$}EGp&qpDWEEm@!+GLty=UKAEqHmenIRtTa+)AGZK3?bi zXNwBxexGv;-%R6T;*^N$hP*K7b3v;sHt*-D$f79sEr%Iqc>AG_TqthZt{GR7RHR=lIfnHtdnScRA?u z@YAWPTEk_1A$xjN#%~tjiq>Y3yMq>hVu!2R?36Wz309#vpkjuSoNp2N15OSZGvi26 z?{YCVoaY4#^DyZ6nxXuiCk#@I(kzc~%5xgP_j`*6+q*N<9=Ujt10LF2#mwYI^i zaEW(tf*(y#4IV%v^4GOyY*s%Qd0%r&6lkJHn^JpW?^1&w`jS@NUMKbtG}Bd^TgC~-3)F& z_BgvEOtnXUU@FmTT)%61(i0a#9|mGRKV&<2qdl4g4C(!+d_A8RsYu1wPGhfRx_ru? z7(;dtE)(o9=q-ekwcphmOPe_ttoEZa$U5vXAtawiI=^4ciXc!rpK@Cpy$6IO9z)CZ z2JjLCGaN#$U>pVqwmfG(nJ$shm2TOV1j zGuQzecCB1G7vqx%uR#Osc`_o<*}E`Dk&P@Pro^Fqa%ovYT5){48W8R4fxxhj^5fzH zBHI~wC_yaf^$)nF&DXQrD+X)(C&Mw6(JRtWk)ZV&JCVn zSl+FW;_Yq6PvN`|WP*pmmiv^hT+zGDCQf5Ke|&-8n?TWXZe}asB8TZRb&4fp5uL&8 z5Gg4yzygot9Xi$7-jNsLKFs;znwXLv61l@09G-sXlNf2gsN*8;ZRk38;eLKCPwO-% zp~c}uk*eyzuI{*2D;xH(zlXWl zb5KI}WpnBaDAC)df-If{4XoX-<5QzEms?d1m9|BXZjONanANMkobQY1E~a;Juc?)Mhc7YCv7Y6F&6%VPwM!t?VZb- z{PX8iPd!v?#6LLT5x(6_?els6#dJ=!dF_w4E$kSH?smvsg3*z}1jRd&5vc+> za3#nsF975@arAT1Trn%sBA|FT1A%JGJnafi%v>Ec`a!lhJsw#|>Jb-FT{eIslN0Av ziPlr#PuzZ%6*U6^c5!pIV$xKqQD|DWF}`z}r#{$0KO}qDDy8`9E4w8;6)9%JC3qxgrNqfFR5{AfBBu`C21(5>{u8<*9(_C0vBGV=2f4 z7Z)-M%RjZB-QLjZB&5&d4>zc5O;<9A|9V+RImZ)=^>CM0O?6&VFq3eOO$WZI`oj)K z

      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

      u+l5Dq0}Y_=FrqfyIMoN%j9$l%Z) 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%0D3k zqw%4ZfrQ1nU{_d7?C^GlCHVou^{sDJnCn)@q{t`$qevYf&vW(WH}-Oz^iApwmPRJI zb$2k$&-6^}ionDjikh@>DS8^kjGIX}jyPPeWC#)j$$)^!(LG9W({htZ)5_M#*xj<= z`Acd}x0|d()~2@&sxP==&HRnRR(Ra;SM zuzMg3YD4ERst5Py2x^R>bHw_mCh>pgWd2DpD}wp|Z&J*EMxl8*e+gjs9R`ViQp|(R zmH(My_FLA8&Xi>Z5TqWX#ekWZN4FI)6SJLSfE2S=CBTPPuaCU3Gh>ul#J>cXiQhIl z_8{vIY9BAOczDE?3RT^(6~DO>pDWbfu=E^AF)MEwJt8!FJ}EU1HK>2z6Wdp@_x$OT zwKqfoJ7-i5RCMXKQY2~br^Qp&nnlse)&8+F2FyyGUK)~IO^l;LN9aqB z*6bO{oImp$c}SnJS8YH(_#q6|;`QstcqsJ@aZUqLXBs zcDf+vUP`TSktjgw4&_fMIQP=znr4Co6au4@0_GFRl8!q#3L*ysx>~ZVTMQ&JneB~} z_)Y_vzml%6IPa)5D!NE;;Q%RgW(wd#gqNpZKr4TZD?=C~UF%w)AbJghqv8EARv;-X zp825wA+PrAWL)gUG5Qfs;i3WJA~Z^M0z=|1?c!|2e%}abEBK~;dB>m2sbh?WMU75* z;Zmao)oazk=XKaZ;|8S&Pl)JRuy9E!>ofAbp)N|fZ4q@%nS<{tzvS1)QRgIYq={}+ zAayUMTN>UGZ=i!3h*CaFBZ;^L@M-YK;5bwFx!<)4wx4Pf9U;d`Idy!c&Rf08M+O}qg_$yIqIL3 zju}~LpcEV1Q8h@KcHK=sRc7(iNPSDapZG>wTfa-AbX%c?GZ8NQe|0Ngq^nj;H6@0_DRbCkCX zGV`pno=2h+DAB~{^a#GP0k|21NgNdi$bH4w1;5w_I15W+5|6cxfc~Z$uNXJAr~oe& ze^St7ygF}=`c7*AZHwbt>?4;l4x&J@Q5!6f%rQH31Y-qF>45BQGph`(T>eyPGZ+LC zS}wmr?*d9>tl{^ymNP_pp`Q!p0dZS7Oj6&4Belq6UE4AoiU}Le=@SheLO9JH@;vVW)=|?QOai%@?QohRtWk&AIW$a>bdW(5w@$!RrYE7{ zYk^A%G6<*P^26`OIyP`dhg;T)4 zK0fMzaz2J+gwtC}hO&-muVR`H=`Iq>C5c}I@6(|nC_2|lCBJOkyd3Xw_nhpCvi6Gs zuaR(uvrD^eKwSUpnvf1@EUUQ#CN6f9;VU?{rR8+^u4pCkx zly!x5;O7zACI3r@+s+Ks0}%=$0Dj6okf!j~o7#5aH*w3T0XjiRiq>`xej~p9T!Zo% z&W9{Ds7*!fx~5_FxcMDH14E;8rQx|P)X^e#7NPQm+Rm-2RNO2!EoIy49;cEV0-4r? zYfv?>gOGSl=ljn1smILb62GQPJ~27|;x2DNRN10CVzyfj}Y! zAjvjwm;gG(+q|xI-K@s3+=S>*-R-OluJ#+|k3A-<+G@S}-!hZ?ca)9!B&Hr_ ziY%}sPJXP&L;rOTcDGDqzWIUMl?i_)kE*-#B^11Asz z(SE=}nf{CBAkQTzOv6@nn%>n}Fced<@aGw(D?_FH-AI}|FR6!Z*+W*TC`G&Q`#M!B znmbG~p{k_7D+5emw3u0VI=r@9O;Fw}JEbItm5V`A1_YbUZ8Ctd=fn6M*R5j=$x~ig z9SdePaaxP1!X638R(#A??u-@VYABT(n0tSJobr8?f@di<3;w<}0q<@Gxv-N3mob7v zA*Jtgtp>dTKH;v)4sV`!nz6DOA%;3`%3b|s!DT{BpnMY(m<}3hR1*EncR)owdX=k9 z8{D*`sxIG2q}W5Muj2AD@*S`f+yZ<-YrPn@ZkI#WP1Ql+RB<(K{5u4sx>aEUg^^|+ z8Fm~o1s zZ)Zz0QE9hdrXAJDb|0+QlUrk&l@+#R+)DEHP`W6=RgiQ!d7jSs03FRiE_e{K(@;rb z*|5!@oz!&hyu9EVdWYe;XQ%=f;=fbh=YVBq3=;U?cjSL5W5WO}$B9DfYB$gkmA*b; z{O68L|DVKaG9X&2NZT07f?qMG)A_zUn2++9_zx|LGSK$4>;j0@u-hVqE6k)gWIkJ0FD1?a;fibWcZtm!rlRBbyXmQnfQwkXLaZc_^yM3Rm zeoxM#H19YE#fuEP%5LKBcsqKC3K&QOBs(Y}6j`QilIDKbK*OS(>8c{)dea%Xg{P1V z%^`vsN`4rXQWkdCs)TZtI7u&a+mv2!za40MlLi=Nml-4N8G##FSVA9CZHvJ1&S!8> z@gMp<1~gSgb>3+$=9bI&z~%vGP~*s8Nf9|xfIc4P<_zStmK7&3Z%(|Na_Bj{k+(b%@o%%7OtEsOR zAyU%+*9IqrEMX9Oey#dTGr2>=1fRKH>j7HBUY=mFRYq)z)z6fvz9h>wl}G(3=%yd1 z`k1=@%=8%zl8TOhHwvdL*jF#|jV6Px7M$%jBzr0UfMj{W=&i8HW4oN46nb#seMHi% z{CA_*XRanriu)sAI`2pR4g1Jnq_m>5itW^mldY9V2VZA4!Q0KCY1aq-vb$E~^Z9kF0@uro3F) zew}UhnTSDMBnXf^1Zi-}4Y1zQeBw3=m$1c)vl%dc5IH(Vc1c;Z@NTXeJAWDwps6sx zNI~kC$3gIqPR~31dpa73Fe@IA10P3-8`nL;=aE*h?xkvjbJ!*)1H6Hd`mc!%Qb#cd z3fB)<{ZyNsd*~$g@Xzi(^|Qpi&wsiwc_T`cj50jfsL){)oV`?8hx2b-Az!Vy?`>1M zSTr7@a5r2$;2YJ;14c_U-N6OCFMTY?eyXqX1Evx8c3GV~-^L3DSUXAVy24H=4#;u&F)l`B3m+dFfLBg?-;)t+KD1>~_oCx=PbpX1*qK)MN(>*@Y z7e!N-=ZP={9+%##&eGs2fwp-&my(yUTe#f;t%>r4Azx?pT>VWW@x0ETNOwbdz!gjG zC=2%^_&%+6d~Y4M3qU%g^)4PUte2(On3xpcI!w|SFSct!r<(v~+1P!0E+94a47=Q1t64cP^Hkw@@!hmi@ul*vF@~t=1}4-h{g#b4lv?xCXmzbxTc}-o>(xj;ev< z00ngM88}b3a@5Qjm-B3I|2Dec=h`yrEo@nX<>36L(e<9J9(z7Vvfb?`lczG*#iM<- zePelxLVdN`Ix^#M6zk+E;|6;D<#C-v!+jI<7fn$(%zJL}yfB2PP=D%oloi^C&KOK@ zJdF#~eUm|S z1!ncemb}dCh`na?dLyfRoxvI%ot@KL?|rxCPKwYVy1@lPe^8vG#w>z?ts`u95|GC zxVv{@I0tu+oXp>8IE?XhtR`~0IpW@9ZIOJ{ z(B^$4fp?9wbf}M|Gd#(;$=Retmn7z%O6RjhsV;ucX?-hAI_4ffD-+8HZEY}99QOvg zEC*_}T9$cWrpoaYOG%A;^0X|fG9I=*8XLZb$fK?%LikziW>~Y!3q%E|n6(9Er6TU% ziIJr0<<>N5Z_4D}&l30ojLXjJjgO_U5zfsK}_O5}nMSp4)@p5@T}uT#MiL zh7VeX2<3EF#PTtLN4Gsyan!~-=o-FgcUXsKmHI4)&YS*6u`X*20Ar|Q~&pk=^y{)AAh(2)FH2d zRsQ!K%Wk0Q-)IW|sza*9qqfE!@abei^55!^0QxLXM8|LhH38I-sr5c^|Emu9FPcKe zDk>dau3MPbQak&|s>K_qLyBq_UlEPsvDLYbZuFe4yE@!n|300)JPUR$>+53Ot?xTa z!%rJO#$17A9V>A7balq=#)IgGks(~ z+S#UMzIHa~YxVU!IxJK0MAkr|?(;`d1Z@g%Hp0V>;W#BZ!j$ue>Te9ihA%q<9;IJW zyKAnkqxP_k%8)Efb6;%j^Vakuhw=R|U2`fw3lZacj-?ZmrRDD9uV0hNA5$%dRq7Ul ztQ^VQKNywT3ijiD%M$0#-P)w^T#4c^%pO)Lt2iJ*HVUMZeQ6EU5ciA|E$#g|+qYH| z(neQFxJ)HU$1qA|AB5lDk`Vlk=r77OqB>igh43igO!eGAXs_Y~c}x((qk!%aSGJY) zG4eO(_C~g&Naa)v_%@X>wvk%4=uYLKg;S1CKSoI3V<~n*49-gAxBjK0uvr{R8IpRJ z5=yKJf;k0FC|Bc-*RECqGx;SM7Ty>;a)BEOr%NCbRniE81dwjB5IjoEzHX;3Gq0i? zUxp*6nes`}%`D&~WB0cr18D|#8cE$=Ch0U!(mvr9Xl6WF#-iHX>bf*VcM}LdTQI6x zR)gI5EZ9VP{Q6-?cJXx9wFcm}=?HN@$F@GCB6t=d{Ddt0R?O?B>fNuePVCupC@CVR zx9~--N8?hEE_N=fRbAbiuMt|0-=TnMzR;)N&LA{+%WhGGEVwZKRxvXBdb9WTS-QCF zIKqGKIV^QPRLpuvBP*Y=`0@9#>jwNorj(WUkVcrnHs@?5p?ZHC;T4#fE?lQuu=vx) zi-TFKMwt2J#$n#!TgT6pIvwMe5+|mes_O$y42)FYO$uio#(^_Ou0CDzd+0m&?%ogb zsYx3yFOYpk#?0|}MTonhgUR#v?(y0M3d77>x7iP6Jm>DE_4>h!o@Ey|(xr2V(2L6b8`9N>TyEh$Qja;Wr9viaUst+G4{D>~p8#aJT zMvlhZ0?KDxhNjb+v}kgEX7cI~h&)aS+E@kL)O#gSa-8Zk@sZ;DU6m0>nzZoK%p*kw z)em>RhFuMH<)X+hrWQ1f&lCORMLDj=a%hTQFxb3AIE?AoWvU?zivgkyDqFq#nZ(oA z{2oN8blypJm0UTKS>UKiSMYU*lyWgoc=q$2liUN_P1~?R1BYKS*Z=19;gkqYKN;!g#4>%I3miJ0Nt$u;z}B12Cz? zQzBu~1j5xBEN{}SIU}!)MB#XOPW75Ur4Y?Z#>;ln@m$_ENpZWX)I2LY zBni`mj-?lsN@MvDAo`_hGt;o`KP_QPIKh#6k;O67$fJ5ImxWar{TLnRwHeTLXLu{$ zt74p>_V(|$WQ}&7(+xFp#@_RS@a@FyySD^G^(82vgcLeHL2cg5`+_xIx&FMD3nkf@ zQo{YiV~^dEJdY&4a7yQIH!sI914%*&Ibqp$4&Ij%roSOX76<2C?B9G^%{8%K*P-F% zpk5P8kI$~s_Sh-!WbzdY6S~)hj%r;EKWHZZ6MR<&e)E$#ch=*DKh9Qq=VmcvF}%9& zU9N9{??L(fFI@-JI=7lP+eE+i1ZaDRmz-|DkhIBXxi4-%1;miy7XZvrAEgj#5e|}d zI2uHO10N4CSpS*thcR;;_uJSU9FNMu|IqZadj6pa;jXL=))i6`BlHW%Mo3MFF8eiW zS?3!P#vxBazrDt&w0y?!rXMs6sSDM$Xh<`Qoxn|A_na=M`vzM=`836jmgvn7<;g<+ zsnWCjkNn%Fm2RubOtC#b44dfoFg$q=yZiU-14AVhU`n}rCPjP|U(X&g_#oXOY9UI< zSn~DFSAOjqgy#>eW+etA0ypz~eZONuUa9{0l>a!=Z{=xn&kr~wgZQugPLJU;61rL9 zK_hFWao`)im>a*pWq zrMmv%{q>98O9@kc7WsG8=Ck3yU&6t!?i@g^xo`YFrO5lHW>YG0v~Kgx{NjT4ghGCo z2VJ}V6%S(o1DHGb#-xs-PO7ymQ)J~{TqoW`PvIc)W9mQtr?dWlEnogW`|uyBas({` z0hAY)3ke*04gZyncnO;QzgAmfyEk#;|A$m%ZHyNv{tv18Z`b!f)s{_@+5Dq_0TNI3 zTWkJPZCzrs|J(IVy7T5`RBhvbRa@6;YaYe9Vf_u-|Ks}V2D=jgtS=tb{}Yi`eB!%0 zm_RT3Qf2RB8Ab2EbrqHz;wx+_v+wFuXLD5T;K*uJ%i*QmfIwmWTUf0;-Hd&h&JC+kxkgODOIokVxca-;Z1&_hw9{Gifg( zE-7s_8Wc2)4DnMcKZu?}JE+3J@ma4?9JF|diUvm_;u(VCoa*}u9LC;ZdGsw4Wo zr%Ta)7b-W}bWh|{hgU@xVp}LTol3-};rmtce_PRDkP@3|JTsLDnYKCNLVsU7j$7C? zrg^Ho`otbCL+$R`}0qZ?;q;iBA9YA0yKID1Jn@G!) z>XU1#jB>GpsJVW+>w@G8v{A^%R}|6*1giFF-V?QIqi7OOE`mSR-PL`G@S?VVw`tHT z3im?q$>HN!chH>|1phjG=26lOzM*Dw!8*zu(b4xC04&`jOF0emWr*ywf#sYH_VCx~ zg07kTQl7cxE7a_wJ*)rRTR+#sYj#p$@n`Qsm;HZy2;Zr@t6}>6;;`M^6d3u0{D9d> zxZd-3-Or7L+xBhigwo-kn-6vWp*?av|Iu${huqx(TS{19cM%zpv>v&*Yt7rWuNfG3 ziGwQ&2Q6ykA+Y4i%LnxBKURN#X$uK_aM=FpNM#pg8EpqQn~VItPuG9r&r`AjMEPrv zTEEK4C&%>b2e3D3f6ppz86(Bj!aq@o?YO4BId8#9kok{BZ$13{)BKb~Z)KA)d|2P(_s4a#YBoy8+$nQpX8Pwbruux9XfJdNP zKwq!&-e9njy1QjQwi|vI0|!MTEY_T!pu(ddR#K0P>2Fb8Jn&NIys-(~7{kN$O_SK( z;{Z6K_P!z@Svs5qUDbQK6y{7pAI?q1s^|D`#D@0K5p|T+7-x#17Zhq11*PSW;@AoY z(&>@Y?$mzbIP@B2e`b;%K2*v$$ zjAOb`rVP~$S8h&8!pQ4~2~ht7evv3IA-i1{fV@;3eI^cJj9NpK5{HHToI%EUBsNf9 ztbl{kC8eYUx`gIqec~-dFBnLm3Fo}}!G`oNu_>L=p&vjKJ`FvSM2cPh59SUK`}P;^ zMJzyIpNtT=PRtDHapqwKDRX@}j^AmazxvSY0!nFoRMcUx1s1TG_)OLKm`ZGGOYta` zX@LZ%upyzTNs0U@Zg43}oDA-K($vOVp^42e%gDCb%6-bCzsyhF$RCx)AC;lP)oH)l6DBrGQPH}U6s28Wl zv)Y@xwSuIaH0>e{|GrV z<&gj2Mj@-H>!lpa#4axgJZML{p9TXU7^nmcm$bhz02#TwOsdMOY~TD_XioQ$@%uVI z!}iK;0~;`M#pBi6-!ws?uJnTHZb7_Ko!2$RWo8!fFz1m6{zbL_Vihgxj3GH;2izQ2 z!u!3`G7+T${fH!_)nwnD3m%S@DiLZl(2!`%O5NL!Hfc09*2*ry5@lWd4ZU)V!=u?Y z`GeI*SO4m)c%DFq5Q-+2{6838Ewjr8i#%n`au(s}T#Fl$Tlb1cvhGL6x<#iaxa#Hp zNIlysy?+b$kt=@wd8r$af`gZuGrMH?PUJ@#JKW^;`i@-eO1wxW269WdnM}UMrwV4h z$rQUiYDM`ONz~os|0J7`dg`s1ib%N8XGxzGIGkN<>K@C$idJ`$zuxckOG(ei%cQbZc)oK@@zel+ zmf7+K-&IeFRZPLads>4XY3^F_Rf<5;^6K=)?;{64Mw+#a*@TfMd+s<--RV!R5KdCa z)%j-=va$sW*V>a)9OPv(Yac|EA@1Y_P?>BnP$e*{cYPRP9O~wceO|Ba)q%0v$RmpF z?m>@U?7?7v+P_!W)f>=y-Cjut4@z7cwpHB$`?<0!klaUSZ#WUuzHR2?N-$pMFDDp!(bW{~n=RXJSNPP7 zkYBoZtatug+&wgWMK*Z*>efZWE#7*H?DuM8V1D$9=-E&Z4LPY^4Ylo&^}u8F zDq${Q6VtB>aJKK!(`_#DWYb_q11tcxZW)vG-PmivtV!sm5YL0GANbfGZXLsx2nM%2 zH~h{;CQ3OZ;(aWxa#+*cJ+MOvbCXHM&c-<)Tjk%DF_y`rb3WuLG&*1yI8y4Y+lI~p z1dS|M=N_3tFpf)W$Tlg!8+WQaDTJC7WW>$dZ0ND@otU3(Iy{va)fF$ulSgL4w%%?W zZzy8RT>-UdYBJgGi{On+&v@liK;v1Q?Mhtg_ZSjIC}dVoE#V={wd-ZDkYP*T8jsjJ z3aPrg=pb!~{F;Gmn4>t(5XpUsnt9Cm-88(-PY{57t&?(YeiOc6|6|$RlJ4%E-7tW z=8rSXD3nqvHl2IPplt!9g)yCkISE_?th!SPYA4SOThD~~psE!tWSoz}f-TP02?S+G%okEt|GB4!P9ENT0@$2O&-Ui7BCsXQMmp`Gr zrp%t8J8SJd?h4<)0LrYvjV*qfYe-foQji2iuib0(gb#*+9iz&jG++-oyMGOw_b0 z@G4XPC#(9p-KaYe^Fk?un?>Eb#ckONKAUf%M?uT&mIuLsChDeAX**pAX9mG7WGwgTxq z=9KzHH^+z+S1)0QKIr>IH7xG77G{u7pv>x46@&S1f^pDyFa!h9!~hK61P-(yS#y-J zCpSt-B{59T>%J+cH!7wV%cqvwo-!nLcuIeahE+$KQ3FN zFVSOD!6M4clT>fnsxThk$R(H_ev+wazMn>0A(y09G_NFn3|JunM$w3pz%XP}i2KBS z&n`u&W5tky%D1MKDW#Q>6Uq_$3Xhbla_OtEnpFvQitzpb#}&rVB~ zLwV`KfAOB0tDW)XTsf_RHC7jODSwr%At=*lzpZ|fL|5)p&C8Qhw_m-`Uwx=4{?!#V zLZGI4!kouL-GHN@B_i3^kZ1IC=~rLS&%S^VU|@2sH(Gm4pEC=G>cgRGl+`u>u&KAT z8?0*JW0uFAb>O4gVK#cRxfie4Y8!BMmA`0dj;LG#K-#rB?x0$kArrI|EDZ2GFsE*M zqK-U4KQYgg=Zumdz`WN$zuD^S)YTdQKrSf&ZE^#v$xBYt2KENv2&v&MRvS&st1vNm z$cW_l%mPz^!Mp2^cUV3iH5%jntWCn6dcbLrO_LW()*u2sHL{UT?lyABBPe zz&=dV_p8)l#KyyY7H-ByM)ta_BQP3ZFj?VgnopmzhNvbWh=gkED6OeQErp}VyR_D< z+bW>_e$X9-KrpZ~|4V_^t+K~?v05Pl9cI2LR$K?3 zsY^LZ@5L|`qKYX<8z65&)lYyldF7rZ8N2S^DE`$wh^*n&uQ2qai#c?WhN+X%fyQV=stQ(ytM1>arK(4AUsDB6Ww zN$xNs2jxj4`tZFYv3O(V`d^2;r*Z}oY;HyM*b$h96ayP@ROo_TiC*yrA=$$Ptn z@GP8rm20odx88K%{a-&F)`$DMNe%_@>!bQL@z_@o6H{h~>t}XNKZU#3$pD-$qxm~f zMFW)!MeiTGnj>&^c@pB*)w&(cTFh^ruYA|t9r~s@QnEjC%R!CGljZZh$3=in)Pvq3CMvcc zj<3VqgYSS}=k&ecYw5;!M_l|K)Oa_<8Bs@9H00q8r^<=8=|NVZfiXnFZ9la^Eu<-` zqR^)f`-cT5=BRwsSuEPOqdA1JuP)J_@G?}}FnJ~4;MwKYSl)${Nm8oksd4@@kuE)k zZI~GJtt(a?o@kyL@0#MchnOa*P8EsiH%)Ob@SB{l%}?RM_UMTawm0wT{A|GQj+(;c zOI`Jm4FK5jKFAtJG2Hd+^8x7i*NjWi%r}mD9O*`h7{ ziM``3Dn26Ev$gcqXn{Fucz`vg%N-dGH4Np(82;( zaTNPX6pHA2=vCo5s^3WHf(`lZ+z|pG?i1cfCHX zk>BN;JGLv45NrOL^%~8+?4>%-BThz$jyOIAY7ytG59Vka8b5aeyN*`6)~Hhc*3sY* zVF0q_Q{aIQy0FsoA+nF@AylQ8EZf{V9Ehp|fSxz>?ViG`O;E!`yLE1=Ix=FENG-)J z@SFr7p%G2hpv$<_Nes2aF`PRP1wNxG;VvA-yhkMfbcsN?6mpJ4B_$;$5~bCFG)1lr z$X#4hYdNCAk+gDsJF6?7ZT)C`<*^#@;#rPk>((^r)E z@#ccH*`K<>wshkU{b{tTSGv=4?Ga>OwU?W~r17;}r1p;H__QSzj=8DG1YGl*=U)+w zOCo!ls<(5YDam&AO*!&3sSd;0oH2=RFYHDXL8=uxAV7HUS?6wYOXZ^PZ?BgA(>g@j z$E*JwS+}UX*MQD)BdFHR82l%Mb3PhCFvHYSN}xH2NCy&>;^^b{_599Lur+Bd|6Sc@ ztWB$1=OO_zEY?i?(Fh1wFJxV(=lU3}V)zkY!1iTy*<>{w*Oji`YUI`#ZqlB1q27!( z+1+w{{H;s*nf+8Bp&1fY|Fd@+I1?nn*A2we3_qz|VgZ!QNY-EqYt|%7WZ+xe`^`kV zN=)G=08(dlVPSU1bBRP`a&e2InNON3NYar}TlU*f% z>WtPW2QM&>8~p1GXvWjTnQ(BxfB9(?*4`OpSPz`qx{LyNY8(ho|H6X#;)%pjb*~{I z++^ERQ`Uxb3cO(-(FF|vvZG6L*i8r0k@r8hiM)<4T7zg_;E>WaNb5B)dd6X<6;MU~ z({U-Z$(1>QUj^5;Wtnaj?hLfyd%?s5O>XVG9fONdv>IiLlqGmd*r3I$*sP6|T@5w! zV>QtAoqKhO0^F-Iowmq?Lj2adK+b~_oaKg`EH0lZGQdSJ6ziSiD z^*F@Vkv~bFcY^vo3%Xd4tbd`n+Y#iNz+iAK=Em6gUQ)fyHTht}%(AUXpnQNBCeD|X zDr)9stFJgdXCMT7PR;0peFG4}QXXu*NVL*V$J(v2-E$|jJ3>OaY;dX0$^0t*sdP3; z^FUA^n{p>?ZnxtpLw&m$hB#uf|`q0N;}W)=!+ zEl<&->vj3sg+~JyC8ETONCJL&KF75Rhmo?!`E`;OT`%1lC@uJ6F1J{=f=SDLWNePZ z8(}83d@);0MmeO4ONzVCdPIbDxjp5LiL($?I?90w0w!QqP9j?H6dz|nyg7nWTg?q* z;?5MT)p=W+=~%Nmp3SgfBo|t=wn(b+|k)3Oqzc!C*j^%Td+ z9&*2(dNM{WRbFi>735pqkJd zG^NZ2iIYOdOQG}AI^z?EkD)$C;(SCd#oFwR0XCmZ=G%C{i|4uXS>{*nzKKgx z_F$fgvWU>+2&(14H86LcHeVymjqd`foy?L2yJW_-UP$>S8>`xz76&ufMcf0zao(;RnLiDC}V z%w$Eg(q+n_yp-H{$~?Cck(qS66Yb*KY}roLW;?!~+1uQKJ~0sXV3xhgg`Z)*%l1BV?jGW+1n=pvX^5GU20Jq_v)Py7j#`Yu3&)Y7`A;u5<`(^= zxSqWKiHcnFqqOx-I)JH9Qv1}@yewgSH5mHKM=wS3#~=KMdw*ZlmN9koLwF%<_~eEh zX&yK^R2UvixvT4hn4J8z)Tb}^hH@FKSRTk){Z128s?c}tONr`qcpDiawjs7AH&GQO z5}4KA+rO!AEzIyT^YjAm)F_}zW0H3p(JqP(c5_i_p47mp<55R-I#`pZMpqkYceULt zHZ+UYq+o)@r(!_3Fh&MPmJj-Hz%ZRhnu#@ogFnR3Nz-eSb7hMWiKDP)li_%+C?2#@ z3^R8Jl#+TjC9sGuSS`w|`m3*0%#@F3JNiyE(9Cz+8;rODybtRXi4OO}Z z(5e{L0e65Z7Rs}Lc>s_#SzCMCqs;B;ZPX=wSzssw$a0L$#x|JJ!2m#zpSN*r5RJHB z1{3S`VM&M*V9#Q#Kjl3;n)=5FURewz&d zm>CD*^t(72&-TU}?&wQrIgTCs3npN=FZy$`^Po1}`<7G&I?p^8ha|or4Sx~jvzAx9 zq?N<%^%4lVP5kSyDB3L%K3u1N?TPV57h|~G4zuQj8-NS5$@};S+^%}bDBhg6)M+f& zG`7h2Dr2SZq0Qf3m1X6?6Rl+IbH(XHuq5P9JaUdO*5Wr93IZevR+uFbQVmt_cIMKf z_o79^2Qv$@EEwM@W*0(ntW5Vef+MT|0yblbJAZVQ@=RNh0vPX0;y#e>=rY3EmF-v^ zZS(wXYqf=mG|~p34th*j_znrXI7*`^Z_hcfCBrFLNI;aY4Lw<`X=q-r2t9!ep)p4971nosf4GRY@5N@v--$N<_JWZ^ zS*~4>C?=$@K66HSQg=p65h0u*TLXh8!3ZugB@L~d6nG7bIyTX+v0}TT4fo0m+=*=7 z)TTpi(1=(QV-wejLpO9#EJoCki&?ohbe|xp_E%4jk_hhIGYSfO1MO>ZjM=tKvO(FNjF<57ay&K}IQ0*kL`1rKsR?|t| zR^pb7%3T4_kYa_;dLmc%@{ZaCt6dew%B7(*RsW&(s|)j;35TKAY}s!EzZeLLs~Qm= z$t#G9S7ltHRuAraqoyeh<$)k00vp+FkfU$WAc}7JUEZ75$_>MJ+;k1cd1ORFq`!Z(TNhUpoR|SG1>8J}6Z2e>%F5a0=OZOgTaQ z>uKrI<2~N}mhCf-hYctI--z^;Dlx zE*^q&;w5-{=tUN+M;}K$gKM=}+cD5ZI^L(NIPglexXfi!R;26OvTX_(Kenp~uj4!n zmPm2G{y9YYO{pE;UNtCfK0gal4>hl9=}8-Cie!QJuPIwya#hc%CF;jT4Akq*#0GL& zZC<8H)Tt$Y-aq+zjaq6Yzc9K;xzZ_)RpQyZx%`j@en4RUd4`Up-S#5)F)r)8u*CD~ z5nMVmmE`}tuSrE%{SkW!`E*cd4?n+zk)pob$h*<`&mpe{sr>2!`}I*nq`131b^I%l z!{33SE-dGhI89k8(2Cv?WT!Lf!~B4T_V{3dCMgo4b=1D})BU}0zZEi+Xl}^(XG7#M zf!zdTWa6*E{)>Vo1Q=acSLC7f%Rv6V9HfsYnyp`Tp`rW8xsXG>qPvitcm36*Qa4Zo z6V69mwFR7JUV|AXta<~V4rEA*qP)y{$if_5QS^o~#j$HbrAYwY$rh;+=GI)-KmnGhRCBEDH>D_P&bH(fE1;|Bb@{JZ&6kSVxP60xqp{?); ziOBPlvV5&9L>TxtIc zVZrLa6kSjkL}w7{4=FEZ(&Hz@5jX% zG?Kw_5X#5qYryE_r0Q|Czl98nen2nQyxB3igCh=QWh(B*7?f1}FdIo~h~*YOPF)Jd z?fuk;LDhmZ5;}%(ZHS>_;g}&u8DZ-`qA9|(;)K-U(Rv_GhYaiy*M=A37E4hG2SmeJ z-l0=vmPKnRq2che#D|TixiU74fvqr&v={0Y|j0sCwh{d;q(RT zh;fq?Pc15&y{cz`q%NN4_!iFNBMDyN@klrMjgIcLKYDF}Ex4cc&^4-y4anv@wMW^B zJEEDCEU{FWt{|npjzV>IxaKt_T@^(tzI(O2a=DS?u=zDquwh{+DUWwH&QFVzvqN*O zw1HlwvZyL5Q8hKmkKv$!!@L8O+?bGlpS_=QjGQRjfV|Pn7oGoJ!}TaWtVh>jY&7Bl zzRC>xE3b*W6yj+Ds?I3*=Gs&(qgH%;RX-0(A$&>Q1Gt&Qg$P3`)bW}CTC41WYIVGc z7qrQ4q~M&bREx5c?+Fv8Znaa8o&|K_$PJ*>11rsAc9Lk<`Df%<7#8}W^eiwfJ7X!S zD7nBWrBbL33-}WREZ3dutXCM@5PNuF?7)(M@IgHF%?P5E#`5C#<%~Z%XsFK?`kr&N zW;06ZWhtJQH_<|!&S5NxWugGEl#SvRspTQZ6ADB2(?3O@8JDrCTzEy6YDy`lP?Q@l z>IFRK$c%I_P~~TIO3n~feEpLH{LzAk?JYY=I5i=h?gwl9H>}x}R^x+|-rJyxyq0Go z3vp(YD0*QNsTI6VBN!|YeIcxVg;&wUq5(?3qQ^@HvRMqiNPw!+nqs5zbgiYg*NiCv zG2eQaxcO0bmm)*RXSJuUKZ&&tk9V_)clR2${X;<5z6w!}ZZ?baT#ItS#Q}&A=sE$r zwqP0;@5Wu~kr!u9q^WG0-aAhg9arGWgab8@X+gE4%Es_TqT@p`^*6HrKq#lJ>~Hza z|4>V@g->c(pyA3(my9JQTBb=>m@(y&+c0G5jp^vsWMc@mgL(HWJhH)rnl6dayefY5 z1pjvKyUo=$9Jr6>eipigACF z3dC8DHgR8Ulrw&Q6GLh9If>(K9Uz4P+Hp$sW7%~|XI`!Dp4M@x+z1$ums*{^|r6W2in!5Bvn7`KQMpm!e zoA)w{FD`DH^6%o{4wu}l4?QG>_xJI)Dc2tL!XX}AZhIf}WDL8|^xN>1>H8l=^>p?5KlY3z z|2lx%g|A5yvs7cD%z9!mv;*-N{;lYb-NX-j;#E346JK>D_Fo6z&5HwZKaQWIY%{{!c5H;@fugerkZ>5T3NljeLiLki9v*M&1!GK* zxvtIip}@FU zZzDCk1-;;Td`uEvKPkI-g2i3Y4MdKcA4^i+)}=a)SF3QlwYC(a{?w7h7^4FK2*NrLFrW^~3*&uE4YO9-CtKG*%*FYO7s6016D|*O3pd|eL3ski|epvraCd-c;7R+iaG2B~!bwO+dBlBb&VR<;10%URY1r4}a^ z=4PD6kRUA>c>eh27q;odq(AcrquxF~MHmGDSZX?g1;p7a#@pivh6$Fot)Eo57)5zA zLmCGzkqrG0dc+xeb-2b$v=7@aI2*p!MJW{RQ;hei zpx&(+$;wn`uGit!8_6p^^D55RZ;Vf3>T-8}CIj|R3TW%<7$I+&C`U6P6#n?wma`Fm zdZlzE(ro&wYU1!DLn}1w zVC>l;yMqq7&Aa9-;78=wF9F$S|MuU#^meL%x;E%;R*l7X`-5a)K}T_abq0QOak#Q@ z{F^zH)Fl0a?aAlg9*;cw7JnP@#J}2O8`17NH3xNE0oafN`<(m-mME{VfYmv{S4h@n z0a>Dd_~{jl85D$4q~cNGL6ix{SQfuir>rYSu-iY6AdhM&0HbsdeF>|0^*|u~bfDnt zL*CA4_9Fnj&57VBeO6~RI~o2L;@r0la3w=kq+pcKUFhD@SIApm@YOF}VTnn+YMWqd z$KEL+F`6LrnAR;ver+3};sqp{A@43uw@33j9^vIkuWPmj~GhDfHm zJB*Hb^P&dP=|_w85)zx7v2wSRx=9U8Yhq8M$KaB60iAT=jjdQr+`ej$%pl^&QJJ-* z^qaZkWmuyeN!E}#TeLxgM-3(N@wN2L8_v46x;MjK!-|)xVNdtF=l}Wtb5>fcfVPh> zfxV)5@B?}pbuP=&XJvwa8E*9v!YIDFE2=U&+@{q_K!sGr&jnhMG;kpNGvip6YssiR z`;Fi$UrVHbAvW-?Cc6BF_t*BH(}w|>6+g1ZloZ(gY=^zN(ER$j+B9r`CM)9JV=og` zp+qlx=VMVn-)lVnAhR59g$jT8dA8d3FHv!vvrq9U=DZys8y2oCilDSMN-I;he|)3& zoIN6z?*(w(gSs0g!ctR!TW7k>Q^J_-$zXJ zfmbXDe9=$j0phGrSI;d>69NZ3>hEUJ^{7_|{I)t9&Q$mn{JcOP;P>(zf?kU$I~huXW_!Z6%KQB8e?Ur3Z7hU8Vy)wF~-tNLjc7ojg%v$Sd0_2l+O9H zP4$%oupECHFn*fo;vD#D)en+_cwYI%0?=Jzmnxa`a12Z5&V|#UbDRTl&~mrgR){om zc93asDYg}G3RIxBGSYU=(;)!y)*(6T&@E9$P_cj9d~_I+muLKbFP6UWo=2jhGAfWs z$X%w*64H{erNKs_*k~m0A1S8;LrO#Js0IUF5O@4X_NIl~QZg1Q3i64`_a)+enC^e- z-4wo=D1NjGg7EjlAxr$fY4}$^1P+4CS`ywjtt5GV0w?Y13)UB|Zy+VWYf%NM6G>gp zy-GpcK83W3Rfb4gjqmCH<=F$Gl`rr6I6SZAB*9a`_CrxJTpSUe&#?SK!<~t6ITEk} zRZvj68r0}p{c_t|10t3idr_KJvpHZuP`hq|Rl2HZGGHjrDGLW(6T8G-Td+Npo5S*r z^eYIWTs5>Pi29RZ<~+k5NXUu{l2#D2mI}ztvreVAH7G{W(%tV&mhi~WY!!#ZPGON7 z2rmu!3NhR?O;9@_N|H)`I*}f^#;g4vi8tNVyQB2)r$xrKJGef9{3(yt4l$`cz|C2g zRjCEqetFj-V#QmD2{d^?Wx+NkS>EjDo!ONhE;KC=8F4rnie-6uKKL|5?|1OFvMA%` zcsl2U#?0b^6T^54d33F?X7RYd0EDmcxJe!Qp22J5~F z8#+dKNCf*>DdOGxkzFAs>GK)pSH;7^DbA=2vP+`2t0 z_^X2c_I81|FjdW)AqyN@8q=|tcQX#_Ddp7Vx%v}La+kp_w-hKQIUaySf})4HEBSg+ zyj!s8MoXB2bxh@-5i2v1WyU?tE5c4#QDoo-H`SYR$sFW$W-Tr*bEQfwAP|7{ijsL* zmRp(f`Qpm&UsfG$mYKoVW$5#(V(mfa*Ss>%U>SYN|A1 zxcKjv?j(hcWHhmbkJHj}j4h%;FPEk02nLrjb^|{MKsoamNaN2hpW)>Yp=K|G01oIA ziqs(|M~iSu&bSy_Ir<6yhGL*c5ig)p4`W0}j0VKIazNLH(XutOsry5&Usyp`P1NyN zB@dp`pE|aN4O3N8v8uTyAAx@u^Sl0hDz}+s2cj~~E6PGJe!L_(&bzcpIa>hDJV8!) zTa-F}9bw!Hf)ue?O1WVW9pt1a{&)_(L~j5UV$#y}ljJvC@)90%exo;OLZ``S2)f?T}mm9y5GJn^n_5IxeFjF2w zBkWP{*l$3*HN~(&Xj>lBLWDYiCJ%=$#duV=z~Za)TU$-0@%t;;YD`AaE^lKIfL1#5 zL@Y?~J?aWVNIFSReD_77J3VH0i}T)G6aR0}%?>Zxfiah_*)(}t;&cRnH$ND55$=35 zB{oGiHl`$-QdiN~6klkFFa7fHD_V%B6I(LyoX6GH=g(DWU6)&DnvvC~JWoW}W}?NS zmm}Rab1jo%Fj)YB?XsgbewVYJ4~I)aWBcjb{)cHh)05O0`P~mMHhh-y2}|W zR<0BqPGM3k)n?)8Jn#K{saCIM1v}q-@gb36$jZk6->Inf%H8AT~TR1t9p+!GQ_e>zErQS3j_o~){I<()<%k&|cH%BovB%k6XX*#rG zjd70usxuyf&ZZ-C+dWu+v2V#fts)Qrq)lk(teE;*dq2ofOz?N+PBe1L@|Ur^@QPra zmyaBe(u*>*AhSw~q>`{e7~NPt%;S*+*nQn%Krsg*gxwhs?e$*r?u6JE+_Lka54^tQv!qdJ0|5$D{zO}a;^LvBLu+*7 zY7tH^v6Gzas1YT+Ph2gVAUV@29^bYtFl_nGSW!K+Vdol9 zv=HRF6?{9;!eGzsmUXcJ?ASd8=)9%O64$4LTmb1n{!iul!xEAn}ul>|{w zz=00>n~W2!fk|=QsgCr!xnSi@ueVb)WYvzlA|4$VrF6t!@e(~5ed8*t>>V9Fk|wiD zJ@W3>{T(xWeDhm+pXZ$P!ajY7MlpWW^%2DhKP+ruIB0SfY3cqsqL4<@J+brmXWovr z;qRWAdlfMJRNW7Q$lu=%Z)#8ZJPcTPqeuL3%VOnLx%XS4MYfZZkG+ z5=qEn0J^QE!4s2KG$2-mF{-+x z84k!*X{eM9hgjta$LQ-(|% z&bu9#v=_JjQJnOB^HcC?@(}-6RklUnLV7AZ&wOnlLEY7F)3WM1Ms&&O`<}f_E8uDb zP5;r&34wgd9DRtJi9Hk?WoZyo$EiJM@i&msHP9)TJC1V6f%tI4_&t3&(9s{r`qwr( z2ZvR`7Q9HE5|v>78&tYSRghdun8Gn=bb@4x24v;H!sHk=M zZ%y|N4R*>t6|Ja$oE{I9UisXsb$fWo6m~Hc{d2PDAe!?hfcFqYi<^a}mSNDbbd042;`on~M;S-v%6@1#TbM0KgNoWbPK@kK}K~;iFE!#P`=}1Pp%Q3b2?xphvj+&j5wuAi1gHEQKJV4LMYO!P?+C}e?sF~JaBJp#~L={gZ2bRRgQSoCk z9b!dWG(;Jw?BlCy1Yn+4`kGUgzDWon2e3LC^LDL&*{?Ebh7+QNSx(VmHu_}SB1~&Y z$sCdDvl30=H^SIa1wTSWR*%5)E&$$)BIvW^E9bEehqG2BHb@>R9hA(~X_gym^z8l2 z?NdPo!TDSMquF$NetMKFyRWsm`Mb46=D*)coHk!R&^Ozs;C`xIlt*IZMi%$yV{@SKp7aQy1)rA}4cMCdst$mNVMr#UpoJPm;m0Pt zxX~(djK|jf5lG7^O0Fe3!Rqt!Q*$-~y+6TL-=Fm{e9ocOnKY z$=a8UI%|U7Cyt~%eyH`7wqh{@v!Cc)Zn1U0ID84kVj#u0yttM{y_O>S+ycPX${OBJ zr|zhNT9K--OiwSOIGPA`t{vME16bkwx+RKzs>){K7ILeGbN`CCGy3#)J+4q3j?5hG zBjipDFyb2Yor;E?!c%YK{l?;P3yzdYDTHonJkk#zoDe^xj_^ez44mE569zmH@L+tj z+!UzQPV{4!bw&{-#1GTdG0fNjsB4K+1Q>qvLg zv4vv@TK)@GO$%+JaGcrEUZ)uMO@>5=Jq@H@YDEv6h5t=g+RL3^Ai;$Zg_J1dPg0O! zoODAH&8BXZZ6YQ@i>-q+#q>d;18|bIc@S;57x_}cnS2r%3zw6eHyio7FHxvJY!goP zwFK#fA+bpL{M6UE8=ml;E5M)8jOfRH&~(!=K@)}noXm|nYUOCS)f?gwKuFTUP`yB> z-WQj8LqiSA%M+0ZWIKvln~PR#_=3s9zkDld(E(*iQ9qYxSZ2^+7MDExC;ozL;J^c* zY#5N88qiixEak>rt%{*KtwY_mh@Ty8GaMFH%&23)g7!#gFF24z`1RjX7%dR}bvXog z!KB0%RNFhLkd&$>Ee#aQ5-@_YjdQ`~ zm79NRv|_@n!bD#3Nsy0)Q9NT)%+F}*Z<6ln#{xHxne1nFP*QifP4tREtc^{Q2{AnO z(pT4_Wfo3+ZgBF%S%^Mn5H2qjWPNOb)8Jv|Lg;8OFN$X;fP`O5$r`{nIRed!=U6IX zoZ6pJ6Yk1OW|}DjEZsZ?QJ?rmf-ihL1QzKuqCy)kY}XU{YTwSuq7>Q}ay5GCeLnG6PV-2Q-N4B%P#6N7hkt*fCj z`=MW<(3=#)hV;WASgR>&fMrbg*FlZG<@1|GEgx&-EOc8fZpvF)%cGytL)KWUhsG!E zTCE?++dOWyNtc%q9LW)cHtNxsXUW^Qx7xpwcj&%zx4{U4#=v$#4;exozRKS!#ohW5 zD+n;fUC28RHr`;q<|5SQB6$t1G;#CM9jt7dTQ{>>@~Ol7~cUCiFXpC*F&Di(shNQ8tX~s@y>}wiAl4=HHC;MLZHAI$V$&h4?EJaj9luAXb zwvVsh`TYa;oO{o?_dfT1U(f6PFm7OQ@qSHB>QC#hNFJN0Ot?*uDOk7)3bAmc_9I#`{L4$=P+eDdd6pSjf9l%Q$m z*`)6f+yi)Af?8ycsY(0N#@TLLuyg&hmv^F+-g{58jR|sw;&Hox8EryaX{Bd)*@B!Nm#TnM;x~@kz)8-lqmLv z__&hTs9~dutUign^kKsVj;yXxsV<_|e)tx6#1ct=R&(Zeonl`gFEWSz#&q;2u}dc~ zO}lz%uEtm~P}02abZp^JY|4+L9gD&u^E^85;yIVkCr*5pUNMBT;+5%!ZT+O?xg0fp zXgg>BKlL-!gjto0hm@h9H_=>e8!4&AmT#!rB#z9JV}myT$dOvO*hhzA|00^K@vy6 z>L$|5bojnEIMVsbnMB345j7l1PBTH%M*kSO*Eip9^kN)HG(oBT8$_QJH)M3V=Jx{) z05LiMi7Bf4moNx{JQ#v%uYn&Qw`w%hH{oZgvw-mjeNQ-eUaQsmfW~#4DNZ3#@?@3A z@8W5J-z&P01iGMgb0(J>$bOjNiR?7DY4K0ohRdI=xLA$K`$h}Jrdo|2jETHaLVH*_ zbM5?5zwMEQ^ufi?=1Z?j+(vO-)U9d#R5jJ#YHJo*HV-syhEpY31XW|8yhx#Oq$^&| zm~?-W-kL{lOHtBAt(;c5eSk!H zTg-rKb+@&7W^jEjF(`2I5ELww`S<510Q!I4lFH+2kt2C<&q#pnaLW?GeJ)PBF3}YF zQ2V}~)`yiQn!Mt_Gb@2U#6aQ$ik19(@7Bv82N-TL;~gc}Uh&kO9M*QHYiBY4ceyVI z!wGKFyZm9i<5<*4D5-A7lOSXrVHsr z|HVc4PUOiu_rwWxKD6x0?`~A1vl`PRWm6@|2@4ED&sB^NdvmOSQaJif4%Pu<9EEbz zgjIdDjhL3)?B`cV_~MnW&<0QXl%UG2jt#5YbTv9xO1b5iktq<*`JpT0AGrsg+63#V z{cCZ^)dsq4+?SX9BDBBF(S2Ul^+n&^<#_8r+(zWu=IBZs(22 zC)H(+t$TsfN1t!=9W(m%=*bIx)|< z=DK=cBTLQ_nuOHb$?2T|-dX+cYk9Kw_k$RD!UBPdl@xMESgy@~ zx+y6Zel>FUZDPOdf==!6wpMdob*W5}3Y&>6`qT4OW+71mtL0*Mr9-N{KwMN-5c58? zWdtY=s;{#j3-XKid4R^3V4b=Y9y`~|y_4$QX@xSd%wW@rx`-gt0}V*!Z>xO%k5_tg zuO0m3pw>1U0StLZc@k3Ygy^l7&idHO+=#!yl~_61ODtdrMK_em^lZ8-#f1-jb2je5 zuMh4guly&pUC9*xefqJ@u5!GwIchO6kgIz%*CSt7xGU5;N1))te%@32b@&&}U@}29 zD%iH1NJoGdJy}a4`Kw!HhNti(AT6#m(Is7pv6$+01>4l{FZ9o;u4W|$^C{@&O|5(O4rm|dAw;ng0_p(l`WV6iB|JR!w%Onn*dJygaGB$Z^%D3K1 zI@Yt(dO>!Dr4qQ&qr4OJ2*-Q@v$q4&E$+9CTqsu z$=6|bmONghhB-;P#}Vo2pnY>xMYEy20H2oOr4T*=cMB|>Jc4~n6$zUX2o5tvLz70G z4T89W1!{5J=uh;$^^CQaVI^yuOajj`lNO8@8L&JDn0|9W-}(ZiXPmdV!XOhJayUH^ z$f$Ly6;R*7W2O4=Y@^TQ49mD?fdfz%y-D{%sK01j8*3CaMMRSv!JxlQs-efaq5BtpCbBOf0%1zD9=7MG0Z z7<7<){`rNK4-dCgP+o`K2K|FS)bVf-^ zQvj+!S;Yo(K0eo}Cb4E@UsEO3IXnK~SXUGs*2vWy+-df7px(iH6hnETCu1qjDzBJd zWax`BZI8|g**mm0a+W48W<8Y$0d2C6z%K^Ya)7(rx4iZfQJQoRN`%FNYaJxRGU z*kgoC;MzHRZWoy*&&>QWKMKhhmhLra5op>rm5Y7iIvXJXuh>tV8QIJ5r{mkZi%p5d z`l9I@;G?Z#C0-3xcE#8U6?qU762bUH=IAq&j}%qZ`4gVeu_x$xf9@V&Mula zRa(i#$~)Yw06RUa$bqqzPi*byj0Nn@)9!h&Hv)?y7Gu>6)8P`nWaa&^Q^wv%g~0FR z2(DC_V*50tC$tG;<7S$1FqTbCDsnaZ`qc46BH&Dy==#mH>9eJvy>{vH*e|Idr{kO# zOf9AI*fc{8#>0r%GE-( zIwz>S(CS!%oxq6j;38NU;p7Rv8ZeiGu4^g>^DRF{Htd|c&&mN^Oq>_od@;0w9QF7q`T+HPLf`l6$QYPjA+6|PJUi{AY$0ROs9%^dJ zeOcg<3uVkskp7A3J32>%kCMQu^p1(M)$K+8|8+3V+fj@zOkf^gB1GOy7DV&e~qJ^&~)l=b%#im3#Nl5ixWEPUcJ zX#`t)n!l3qTa@)%T>jWLH$-Eu&dJQ4n}uu}e)U)Rb34oh4oLhxh5!5d4D`{^0r&RN z#wnAu1v!3XQYKsnl;5flzkZ}S;^p8^i@|F#%UM$gL5bsBlIx>`k9V0AkaMzE56^gxuyDVgzrBI2!E2ML2 z4$a5p2$;`-kzdATUEm5Msm3y++_yfN*lu2F86VZ0<3FoL*M<=E9}q;rj}NUn;?(mg z)Y58ZViK?>w=H6E48nd5^BRWPuu(Lgu>Vvb?P$~j9uh~GU4E~15X?eW`-RcMu?h?b zraGvcMSugv_x&`zQD7T3V1+0)NziAp5}#7UCwRauHO02Cg>SHR$m{vqK2EhcE;ljY z+8p64e$t<^`TeVaWsJI1+A&S4qJe~$1D?QBui)!@bK6q59&hmpE;)<5fvV)s4ymd1 z7N}h>_pB9k{7uO@hdQlKot|4zTU$_P^Xk3LGf+%W ze4ud*q#XE(_vCr&lQnsYAHJTpQv!ax(}wXG@;Vp_<{KuzF|H@n2s;?b<{K$48m*E? zUDky(@t!J+#wYnqj2%eM@tqmACa3vKyH6P$*yo%6^EExgXLf>5#fJ|9i9F4nZ+5}K z+%Wm%MZVQ98Ty_npPV*LuPj>B%`1DYi$r=s#*8f^uJ$LC8W~89$#M?QQO^YJRP3KLpfn78m+|z2RTdn zBqLzR4=OHN*Ii75T7}QuD&+)MF*pvW!I>H0GiTRD`vQ1pQsq^epihrDJu3KQl>nbH za}%I~Z0Mr08_x1RCsWuB)!nCM);UYe{ z8Bb~2YP<+Zx(Znnw$Qk>IGD(1;iw(J6R2+v!^wW4G{hfbF(S6|YEL8lzS}3q{7^QY z4(i-7xCjb7@z8%rjo=U%^fTYW8LF{ElgFEQ{WMZ41Y2Yq@zp=-7Pk`?t%UvnM`52> z((-*iIMHLhLvjIo?FaZTG6n}%NrGc6C|nS&ZgDb$08u}@o!F>l{=-VJW7d)o7X4f^ zgP6qrq0avP$;_#ZE?SVo_%e+}@S`KwMSh0?c&hL-J3%=?-Dc3^6nr@4hv_e^&udW% z8wm#U;k4WM$m_>kGyp-ji!?^6-YgB0!v0L35Q!v!^=1d%?nZbOA=Cx^E)woz_rre1w1p{@dxSgk0i>5>}y^!a(&T1Ls z?*SslVSqdSr$Rg=lE5{-mzc|j!vQq=HEj%^DzGJN(U_RTKb2ufr99A~BWD9a4F2WP zU|2+<4@4>kIA~PGJq`vmKMN&0Nu>##X;)DFyaX}pg*QHM){#t{2v4-!W?Vn*RIR!x zydTd2S`+9_6xa}UDRy0*3Ne5r6W#{-jLmy8jwt)&*c!svG_RWTlJrd*53QhdCE#fl z#&=!*b5W+&gowSo+eStpFH9sgp~!}z7jb>Em-T9NFRST6eiD&OUllh%6Z`jx`B4j1 zQ&&W-A-6&9CsjGc$e$3#IgLvSouG**{mg#EX8!E%%jmiG^{0VRTTw)BB1n4g_i~ny zi^Q~@Q{Qx!q$yr+i{ehrKD91}tIn$kFBBND(@^zf)}GCnfrxjY~9yP;E6tb5t9*+dS(73Qs*`$A=BBG(XfRi&fD7 zxTHa3M5u3Vz(<5f-UO>K9itO?eX}J3YqZ+n#6q9Pc1?VfLi|qBMf$t&=6A1Hzcmj8 zS~lY!^1b}6%!u@Jej2Zz?D*!FAE+nFG%S z-`6+4u}<0z!H#|hX#?ms;68zk+B|cAy^M{$49$t|d+d0k9ou}k_8SHe6MY&3z4~hU zDa|2(jirEjnL{mJ06kx-M)|doQdRbjs&%TRZWI2>w&E0c_wh!IZfULuFdxlgzl~6Gs>P0k>)fm=`gosIJw}-#znJf zh@{4GkDz4ennPeV@mmSR@L@Ap(zQ?DZDwgQBo#dq-gKQQeY7U#WkY7@A1ko2hHs*L zuHmEmzM!*Jd{OQToq3SZDxKIksr>>n98LBO4%^g!$z2yeJ>6I4ho~s4*Yx4DJ5n6- zgy3G6m}=1)-3X`Aj`^qX_5`0qR3?VKSWcCU>VVCL2e%ZCX*bXD9gKDmax3B7tQf`1 z@e0Gygv)%Gau=nBf$Qf-Za6*@Jl3QSdt~XIUFl7jT?E+K9CKYCe8G20!yYX|r8nZs zbZ)%rpV;U_p_^(-FKjkR|y^_XLBG!pknZ>UiSf9seY$c=_bO5|OwyL&)pQBih#B%nZDW$AzL5EkvCfnmIJYU45Y_bIM&^hYw z%{ddo&8sBH4=UGPL}fpYc=~`8I;RFtisDPVkPD51U(odHwez<+j`z)DJ}s&xRfy8% za_prMixFl(vy|kN5gfyB3sTJo2#E#L&m0e!0-h;eNy1^{Udfaa9YEH0Z4S(XL95b{ zFSoVmhF5r=7;)808M5R==cK52;|>D>IZ4?pk8q|~ilc8lZ#^0SfuQBv zj5H;)Z_gmL9+AS{%_n@VxFB7?F#k(@J+DLjN^~Z#+|Efbj(=*p>9ik;DN4$QZde#5W(hM!tK(ZDTeSzBkS6)99kOitvhfbjWi zrK*j8gHFf6rRMTb`kIgs%DrN}RK;6Kyxf|de}9Lla7k@@b&QFphu)b~37I!}wS@P< zCQ64Vq!mtYIbpqe0!zGd!z(!t&Qhu1V(C{gbIy96|M{dw64EXi3k%`LWO*RyJh3$I zOcfWV1uGJXh z)Ej{c4HJe$+LR2!2mL0G@3aeA2ctC5%H84qm=%?Stm8t%@Q|)-I(p5gGS1^&>8q=H zD`Z7!^;5KgDkLm>VFJ3*AGkIU(Qv-9_pjLB_6o+JdL}edq*W zuz!2rXp=*(?-bT~r*|&Ed)%%bW-Yipb9hwIuvgub3sf3%|JlukM{-^3Xxbt6)Z18 zIW7moiriE>RBpa6-MVo|go>UdrXye@3=g(9f>#RgHzUv^K8`3!ply)668$@S6M~H- z7~x(ac^Q#gauCS4h>(xI&7vV^ZgwL5R7=6PcrFcD0V_&yV9888N=tBK+%ot=+1gIM z4y8Kv+VmT#XPQpIQk2JewL#^MpbRy*T9V@Sh(NDPK9bf!Y^q(5TKQXl@&GwUM@3e? zSxozZC#TubjH(1R3^Qvj=TfX9tNB_RO{e^kK6H?&ZT6~5ut|D)T4b%1a+BrhgXb-W z5=X&TDFBapB`3y+uTHbI=~Vy9Y*|F7d%&=iNEB+Z5*5{G^3Y22r|V*^LR3>@wV&n* z-%j5dhYEA%7Nz95EeK>`6z6Vb3v9A(M>{gSA1XK{f73l~LK19`;j$}xKkehueWS_f zq3XvpXCF+s@-NL>SRQi5!M|XaQ%$2hF4b8b5ptx{m*}AEs`$~iRxH*i)yomj6}3Bi z+nB4A(_ySgb6ipEyjC+&yB#zT1#NCJQhsS=ZR-=~)YaA68u&<6Z&}?jgrGL3c=e8J zzJ8_XbTM2=x8Y(U6<%KnQ#L$7nkPea@R#4$q_Fu_rhM(87po}vrMj)7n(T- zqFLwUzSnT(bBglLbt^ve8#~hYez{~y>dvvR+poWS-p)JfjZ6F8lXBdTtNye1y<>X$-J3J56RA&M zSZJt$CQ}`;CA?6w04eR5jLeWY@@ zus2XDbl~Xk?<18j;?RCZ$FF-(GQ7J+Ko!JJd*~u37gZai1$ub%m;E?7v05n67Jlr% z``M>OU*qD7XGV8gxV!51O!m_3X7>43c6AwPwSP zo*bt4-olICE;dyRn~lk%Uj2G^dEo8RyBsp!N1*r|Os?;D>KQ&szDhQzs&4OSy*?YE zfM6}zNZ_{wU*lM+zTG_dxFu^zp(l?Fz?19fAgTbaO~>-f^(X0XWa)FmBXZq~Bd2^{cXy^uX@kh&e0x`u{u0!JDIcLd-()K;n5 zQvpfU4H|v!ivYAoz3;28ml`?)%O&`gQ4KnqKFlzv=4q-z!nZ+=8=m5|5M2bQyWU9sGyCdf3mU%m=`1?yhh>K<(nUlJWFVjN$$!Rt3 zq8>5R@@UXA#>w{`5juMZDYqne;knFuY?NON>ZY95ZQ%UR1|^*Z@S%OMyB;I+MC{|d zsh2zRtjc1jfr4Uu@YvTDQl<)=0$b!a^oJa?mOkXbn z+c#35fh@5C3D8%2G9hZk8~0%Z)I-8S=n?Ip;5xSGeY)tO^-p7-^1N4Sg9ckM^s`kL zc(5RLl%csd%o+WRPn*Q|^Q)p-6>1jG6r*rj_#|~=cyH6LlD9l0!09;*yX-e9j)6De2FN)KrqiLs984m zJr?9|XI=y8z@N0@e>X7czC^B_JVx~wYN$7NuF~}gG_^q$Ce5PkcK}pHdlEaK>O_Y(rJ;(jhnk>53Rr;2UJV;#>*2!J$p+rut$sUKeep-G zC8Q!lqpFgP5)tNZD>h#=KYV55#f4E5B$rf5+5)?-l5U{>8|l8C)I3)qoK{g47?4*& zF!tvB&=Cp#Nvf8ZM(6NnY4fdTi*%yY7P-E^T(u!_0;BbqI$`X2d!O8rB}oR0pnh_a(b;lYA0E051&#f6`gJ#&%F*Aws?Zdlqqz#&RXX^iVl zjGU6~if?-tpJ?MFe((~XB;6$EiFpBG7P*{Hl9Zabk$EkW6X};CbGf|z!^SYjT-}!( zk*}GRra9;o9i%h{Rl&j_$eJH}s+v_>D35q;6}F%jhNxJ%qExEP9>14bV~U~d2eqbg3eJwCGP@z!NSCQb`Qo45DR1YJHZp{^0~}No z55?wu4o}mhu+WohAMG&pbj(yEPJ{#G8{h4Gxx4U7c;vSOu*SY<%Qt>Cb>NhRaA675 z-kNiHUDA$hO=Z}C5;)KEblDjJCM2jCr*G39K%2Zcv3uDm2Zz9;2T2wkKhgW`m06~j zd=uKo=j!ZPEz_*F(Q2(w-J?}AH53x4|c~rt7t@}rSsLs z9BIHey!{#`mJ|^2qt;km0dra5`R_^+;dbs%51uk}3%5%)giA}$csIb zcvy~jh#En`OU<)mt{lv@oc;}n|2jVt4+x8J8_Hj)`jC=5cIGxY`Qsd#n|*P`zK@#( z`kH|LDOrO5@L;_j>*Efv@ekgFkPDE4{IXV|l5*i4qCU6o81~-XQO9ZacK%Y7xt1$j zqKY}9hF&G@d+nUJqhF zX^nTT?8Jkur1q(Ek@|h6kjFkg0d&TUL9kZxCDahmf4cbbg`IPE`&~J6nY*q*;Yc(} zoeOjh=%nEvaav6LMoAg=>-<9H%XK&|YxTQ;>FYV`)V?1b3jMdRYF=JqPx61Pjc3^$ z<>ZxoTGJrgAyZBR8m&y{y`=b)MgJ&H&k~IE6(?7|9+u2;F}?0up5r1fmg!X5)OhjK z?aG1MG2}l2*x@^`auzL59CSU+Hs+hY{$5?}qqksvJD^utnl+a2ZA#@D3chxai?e;n z&YP2D=c{^Xc&Fc9-$l=`IJKz|yeenfE$G_}P4e3LHyL9VLTT%xMd}3anfauA@+Fyc z|1jK`%u26im3!`;XLIal)6Sfo?Ac1yqo=oPJqP%XU0OEG(Yme9D{VRd^yi?6UIwSy z;J)g^_bsT?3Rgy99lGJ||7yS*C7O0}gYDI|=zdK23hGZ^>jtw0*|(~4gOKKh{{0O6 zF&sOhl)YK4ItUTes-DPoM~2Mz6yyzs-Z*ha{pHC-WEbA_RfK1c`w$_Qr`ZGs>tM-k z>K2WfUR*Rh0^E4Vb#Q8MqC}adhM5x=-Ng_>k#A=jfSo)le#zf0hP>4=ogFj4=t^WEIC2o;*t(Zy=9lD`uOp^5ma;bX71Z0H(~=REcvP9 zQN$eQI6KLpg;#`~nnBvI@tJR0<`q^RG|9<(>e29~io7eQHasS9D%Yl86O{lGN^D(`;Hr2PJNBV(Kx{pr z>y$0;2Yf~P!0P+wo$D^`)r0SA=YM?NQ9)tHE{>wgHP~OJD{k zkTF%EXtTp~(3(^36B?=MkqSP6n;PIETmBa-_b*2Wih zZlX-qxw$b1=Zp=J-U)o4roDhK;;XRs{0|SjKcAm4urenNw$j4h3ZJXnN6qXaf9S39 zUx_*E2hnF=T3D_79#CPthf2KiobnsxSqVKq8#XV{5*`;;K;rzU%Q=9@x6wwqB{19N zXwP@3gd3Z1F0M!T2Ym33`5PxH0B{xl$35(5Iusk$mviiQSn<(;$gAHC*6(qgJoRc% z{ZLzUJx`*YCGlYQ@X~o6VM@kT?VWrfK0XZ_hY}BG6cG|9-?}_49M($$CSQXv?V$YN zSE$$W9`j<|B@%_|h{acaMi_+x zwy>C`P_PMv@4=we7)$0cTw3Z}9NQ{k+#co-V_DE)r_AM;bE8@_WaX(-g~C1GhnlX< zKF${y*&#@$=(nCOem z47pPW=QG|TTsyJV0>E7Aoy0tTN4{TbJ^SdU$Dbe9j)?!o(+-ubUgguWYU}6n>kf{Z zz=>*p2LCZ&c1kBO4K<5&LXC{6gFjtFVAn7Apzn_tXn*51^g3F#WHk3LJo|c{Fx=?$ zphqMIgFcX{G8JO9wSOM6B&zx|gvT__14oWbXC=s{uzgwB;~RLxeQvz>iN~4~xATL0 zys~-ia|4GnoE-_k-0;2$gS&l`?U9t z-|D499WeA?Q>|AUV1?j8?+ zAP`I&Nfn;!9}#r34V{HX=h5Pau&4j}SD~9VF#-r1K=OvA`1?@7Gf6lq9b%)p{_23Z zY&r^Y3cU#MrdT8wdfXR!06mJ&AhR_+**eV$XUG%qwa0RY@ zw66`q&s@9jFBAH3N+rWS6Rzwp;Do8DPMpNB*J-29ulh9H+8(=qoitsaRtbW>MN4$+ zHFQ3$cexYx39#i^l5{Th+7g=JTrE>^^19f6fl?bES2(OI^6m4=?AHCupNF1><#Oo% zCzF7P+#4(UPVMv+bciHK#3O25W=VR=9f^g_$00li<%XLqIVdshlGr%u;~zsP0)NsW z1I$~vZS&t>4iU_|*{ghAqX6u1qt-DV@>|l?Tz@}7V7J8_lZePZtSOOFVhL~%03}3> zA>`5yhY+3x7I7h67fm_8Tw)@PAr+q4-QYbKHwoT3P#^G*s}{UVBOR;M(D5f%gKP&L zs*UFyU!tj{4EI$ASNc?5XT8RmDh=aK8jgDA1E~w?S^s1}W1JBbNgpLcg|r+~k-rJi zOC^$_S?x+M=C+dC2{XIB9m>}oM&PcA)vE0Md$%`vaCdu|Tw~)x$LEo86;MApQ>28= zT=mrv3F^NH?Y0_=h9nVmO%%7h6>2_S02=cQkYFFp)TcufH)jFmly>nq=T8u7rK8?N zU$zhxt%Y;WH%{Vr2)oTs{BB)r_IIjQ)-!byASo^7;eUPi~? zwc{(lY-4&fj^ksE-~yy7DKsNkwRv>z$HLKr122u6Uu^tk<$uv5*e0^`O}rEZHS5b^ zCRO||9zzruTyRkcT(H$z+WjyC+68n%UHN{J(kO*Ji*@`n9=c~^PlwYPoICG@R16lU z&PEKI{-^uaCV@ldHN8{vCCJ`?O>S|!#o>l+l;1AaH79NKP#SHE zF|tZ6^COn&QpZ%m|G+227sPMjZfN)gQy@}V98V)dJRfO|-esN>;G!3L!j8L)2=rY3 zHqYRu?aex>TMD+59{z_GX(fN#NSVKfMH_kDn~09qbG~DEOo21)9c8hz!Sq}(GZ@cp z(SGyq)TzHZP|Hrv^F}Sv zs!5?Mx)y2W66!kPtGl+849i8Z;z9c82kR5O*qp@~5JBM8Gw$zsCBSFBo0jzQWZ6vr zM2Xq2d`_g44>a@7scXNY6c?#;^)0~wgC;4YQ%jCoJ zDhA>?gxYw+igSyY0a3MClLzVk`a-Qrzo3u9OYNgg+%nqHG8*ex@#d@EVOB9-PV=95 zH}%!9ks7Pd!=f+P6z;uyZxa<`Fgvx#Q&Oj9c;Z+D>Q!Z-_otKL0{|*o!=Q4Vo}mPn zeZ>A*)mSRmTsm;~{hPO-Z`?<1^Cdh3y0-&D+!E{t8ub>J)GcJX|1wI1hnpu>$ zWujC4vE27;9N6eLmEVqOIX_f#AosYAzk4#Wp>qbS`aTV)gI*GEE4*we7nuK2NCCmC zxyTr;O*Hv>&Bw+{Iq&_`yoLUeGks1rX;??Tt#4OQusz4{tmw+n;>WUzW$r^gEqH?<>E|FIiW~@TL03BjmD=mMR*y-wsQuGBhL3>d zMbJ+N_V@3nzUMS5$BD{DCKqemXrgPdEcs`~#r%EpP6VayhM;h}2Ge$B)@97%%PNln zUPmGqWjt~1;5WzTDZ_U_hLvufQ+Amo6(AFF8;5JWtXsRK+GHu^mk8qtIxCfR@3Cr< z(lE!{-Uhdl5yx_peQjTY@Z?1h$}q#~(f3hhh#_Uzby~=Brb!Ms_)q!4`Q3K1OFvuQ<>fHy)_xA5ciZBoD(7fbaL=d)#N5f4uNiDEg zn0zYUA^}k>=(bGP!~sij$@_sg=J;LV-yqdpU}?H81|p0jaHUMa*1zWNdC@E8radK^ zt!p$L=ZrJQ3#$X`!VGP$=?j8IWgpW;_Y`f1(5c}>-8Tv&ySm`>x}5h8nhKo9Io2Ow z--HYnuF5#ifrAbCrvt@yiWT>&n8rljCzyuUjl7ARCwl%QW9e!X_Hev))>P9y-eFhPkm*dPDT)6A|&qKjl*zPu@_w*GE%7Lx)Q9 zrlwreF7y^W@6fP(GSW|Gh8Ke=EX5-Hz3_1~lnD0^9%Vu(e(uRze_Qu>a&97Lc!!x6 zEy0&WnCIIClXZb)HKqs-IF5tyg);;&*Uur6r1tHYZN1#wwk72kh3C+lPVH2!-P2AZZEvghGwHVUL0T~+7uTJ!;=77vJ=37 zmNR|Xuu~AJY&0+ud9yDKecHFc8>jgYSr+gbbdONrOygip@S(nAA%=FXE%#pr>ZU3! zs+B6dH>phxL`6_ll6jH&({l4Esd9;2-l-Ym_8?CS$*g7bF*%#%MrHsR#=i^VvRE?U zks$Py>hduoN)^&potA+HJxua}t~@$~i34_~SD-VLm=uf^xVM%VLAg3k3i(Tu*Q>!I_VL6OqBQj|;@%xyJOFQn5K!OXU2Mzc$gJ;4ro z@nbCDx;ZDL(VX}fND;(??oPKBk6x-}?Z;9622qN5FYHx~TVrdw$>dyLdxlX*{%xOe zneVprf1=s=3?EFAKTiDYR|Lxi&J|b|G^3jm7@zzHS;6(fbB=zeDJ6Ah+#E2dg@1^@B2rrF*z3ru4jbt zXGySKcFEAKT#scT`|TrOFz&}eAcKL&I4r}W2r2qE5@q)-qy5%ihj_}hLJg&#;G6la zSmO~y*!$H&!yps6Epdk%FwC60Qy^SCrpIX){f3x-w*>YkWZ78K(f+%N5d|iWY054} z!V@O4Swq*_LB19RzVruKf1yRwOW7gZ5%iQWWHQu~4S%!J^DRZDIE9Acw?vpsh-zBZ zBqsT-k;+mkIH#@TIQ(Np+V^zd#$=MFusRQxhR9aV4(a1SlA1)pTN|p^Kg&4wg26BA z=E<~`tqMtMRuGx_c9E-XfIF314^D}{(Wok+1cCx%_GAzTkeNnI@S)O!N^&8}o0*K)O+$I#U3j?t$ZZv@&e3i=3%7x(pk2$8O@FVJ- zihGvyc$=ije=C3dw4_at?K@eaIs7RuygtMH4pECziRHp@5T-K4znxKsd(i5K;-@nb zM69xEt(uf=QOi_}r_|Ns%&~hg%wdE<@-o$;v&B}AOB5-t>%AxwmxX3R&E5cHf39&i zuhx6j77Z`=3Uv|+;6SoTesgM!yWS-_nUv(uhIt{nP5wMt4_tF|8H5G`!Ed;nVwfj> zaiDCT1lgxgcXS&)mtm!BMHl;dQPP$tGM!u$E^IwdyP83eI->Fo0Iq!xAiqYZB{HUwY7fyt31xQ6e;5r=vR)$3l3NmNzl(B%}- zbzi$A1b6SD9xWIy1h;QI76Bd+m+B}T)Cd<5a-H~;J86*am^IU%FTvUW+NzL0rt6#E~tW@FSMD7gxZbRO~0khsl_q|hRV^b_szL;Kv<2%28 zasU%*B*Y<>G$pQb^G1yL8%6p95`pX!?V1dqb@)hm zv;WLe!C!`dIp;#MJ&j}Q-rk4>xA%liukBm$|8{6qUcAZFy8m%>7H&;`4H(|W25i)T z4F&>^7~KsLV{~_ibax4e{>JE(4iOwFQqrKJj?p2E5J3TH5kbK~Og^sfe>m5Bo%cD< zbKj`Pdp?M){KvuV8Qu<~cFdC|+GV%svE`o_d-mp$xph8)d5V$J2#wU!U;){VzEh{0^n?tpIK6-4e2MqZi z_As4eR`D0z5ZZx!DikPRVu)%pC5{=NxyoS%2r@<8MH+(mI;dIXW1P>EuA&5VA3yd%|*NNAmTg@sO=I61^Mw1YXPIM(sv2 z#|Q(Tgg}DfpQGm9>3q`CdEN5sU)t|~@CXvdOd0RGozKq;`W|qdTN!_4!ZH0I$BZTj za1qbWj6nbGY#?+A+XGT-{9@|%#s5_ZegI{Mec<-BXs#=-v_6kG7 z1&U|fUBs@E=cWu2i4-EV*1Q8~kq?pTQY}m_o)|D=-eI69zn_Ia$K7xCIr*ymcn|ktCNtb^yE)9K{O30ZrWniX--l9jVt6kcDj?E@ zahVV?W*mr^S zquKMXp4Ok%>V7?K7)-MfbEYG4`Ddh8hl9Zcd*(71}LB_=LYg)HW7EJCKTcoT?Y7qpx?rmPh? z@E@khw{^6&r75Y%o8{%GSb#2}gj}uKpj2dL^wUX8_aIPMr(XZ6xS$gNv1DZGkhU}Q zaj6Aoq!U;b5bfcgSj~FPtSv#|<8rf5u9YIbD3kVi;s@!iltnykohQ>pQv^w=%~h59 z$PJCL8!{XV3U|U!u}e6)OZ;`Ps7r%})itxf+Z;}4Y!;{5oQB})gR&dcyYJfs`6l<% zF&v5GzuyP?7W=ALKtZ06j=b9}>L+*?iOZxYs7Q@+)lzNH2Mf}Ph@uGWN!J-kG7k1G zi14UxIyqbep0nu#4tl>B zYmwsr47ZifuA1tEqn*$(lrs{I9!cH0Y_yhqty(g=Ne9hfP!xYwm{WNF&-Y0gba@fw*JRgj7-!#TrOPDM4(=bnOHNS{HhQjcG0S4y(`k)V~x%1ark9)O$`qaX_D?e zBc(y(Zc$^J@A2izL-6@U@<6pZvMi^|#CCe7RtCGd_PF1?KtYvNj*e=TfT^4sI?AZU z+$R;!B)C=gS-1FpEqPDWzdg(PKcAmd;%#e%Ki@Joo(&u|x4P!QqEh+A5e0BM*NuH&@~`+0NyI;{^eJ_6N|BdSFqvF>EsQu6u;KTwlclHQ0Fi1ns{Cz- zM>e%i>p3W!+{ld2e@3=2aGJ=>@+MyZ(qIZLmgww2!9JIcR>=y$be4lWYY`w!y^vz0 zZ&L#+0(S&3Wtk`o4%hf(*H<#-vJDu04Er-fP)ugaGzhXt@9ANuBt;MEx1X>W0@y#xKmdft* z?B(dvu0g_$jdVEU5dk2mjAvyG$FqsM0|Nk5@!`1at9ag0xO5Vo?1@H)S`c7RZ5e=u zCq?5^(X^WxGq{GqhNTNnHtFDsnYLo9Ur-frm6O13S;h_dt*EtKUfBb#Q@oN&d=?Fko zgHV0tv3s5=>og^PERFR>t~wyL2W)jui?`a=9NtR2@%-@&EleF1f^}tu26it?WM~;= z;4RK`fNkZWA@Ovjp}qT3tB#cikwNe)V|nbl_))0vhOR4*UyHUzkGRu z*;9Hk7SUsx8(Z;YDAT21;TD@*jjiE6ZFYrKs@pe9v<;m(n8=7S-l*A{@z>FBm}&Jk zZ;&|l8?RrruW~beps&7fd~Iy0)kZ<@B!U+xJ76@U;P@!hpKtm3ZN=V}kmDe)Yj0cb_4PeHJ`PL1wzkcq^msbt zQ&iox^+UJsPu?Df#tv6@kZvnI`}lW_#_#jcnZ^y=QTONTbJt$kK$Wd%|9wvGcXrsu z>r!9v5$PN(^rvV)$71p}>HV69H^)Eqzu*-k=K1OJw@YJ16M(RMdv;?*08q-TJwhHj z3?SlxQ$nF%Z)jq|b3EW5I`&@nwxNAn+t-lhB(Zv+J@D2xoblEeqUpCX z^}U)5{=1_RcT;@r-K&Hp;`Lr%4Eb2mHDFS=3)-_k#fF$~(<~pl{V-wHVD$#Du8p0M zq+A2BQg=i(+8j#keny(}`-qI^=R_f`>F@OIaxoA?^GpbobU@v)S%MQQjmig^Zc1{A zc>C*jp}!*DyU@5~EK9M616b(+pI40Ko?|xl-|V~{>wDe*C_>Zk+RpEF>q0#-qpKI6 zXmX6Q5GdN)Xj5n{LPLyxvudx^X@sdNfWOqQoZ6vAe^K)DI8~eU5f1mWKlcG&QfvTGAYTJ+3!4gL!^c@;t{ro+tIcpd3h z+0m384kvk?u7ql_ieJ9X`NLX?xErY;;S+#lyJrUgVaYXxE2a_?07&C;qG0@P$wsC(#XlJA zSHA$;8dttOnm9;K8euR@DJ&0OybSJCoVL{Y-U@`{gDGiY_|!BC56#4Sa5+dQobU^t z6k`FAI3Una=74xQp<)pD004{wJR^~l_qc$YTAVIP7r!YWaX642Rj;*yr|~8UI}nO8 zhLx1-<&(01m6QHLVQx88=OOt(z{0u(3&fF<=5Lm^nPS$%Z)cISFFh=tLT`Bwg#0(W z7(Dx*dR|@%6-J%;B)ax^)1p9}@qw)gKmZRz7=b_Ns!#*u)U+|F^room?-3T)$S(yF z2@C_|3$=Oc#8fj1#0-UXs=gZJfb&S4h>%Dz3uXxN$H<%T(8Ytzws*YPoWHgjf3LUW z!LiAPjDI^R?AojXXaHyuvqgfnwFHw`V&w_-sU z`)RC1(I>B$>~{)i-B@99+oa+*L4IAqUTo!j#}!K%j^=-4cm`*6&54u>#7N?xac51$Z?W;7~qqT1tC&5)3&d3DG9! z4H5#}A<@*NT}-}50yVB!`{Hm0L>p|aj}SIX#HpYFRN-TBW+Q4wW6>(Mz__Bs@)2b; zFNg@sz7*67qyPby*HlS@lG;rGjO9`Q)SKUOi6&3Q$ryo^3U}P@NMSV7asM>(GeGCR zrk&&iOryAE^S61}o{s)E9n3efi}WyvV=5gK)X^ZUx!?2y;0iupkiMnF`_Tt_@dXbQp-jyma1*2QiOpIZlYYTE>G=C+ymxMLwOaT1yh)mLn#9m2lC2LX zL}oUl_yUzl1{ayQjX{MA~sLGqPPODn(>(%K9NZdyko;%f zgwm?fnbB|$U(o!7`BvZ>%U4;ZK%)SxG7%n21Yw-vSsAkK$WQ%YCfNqx`(`5_Zt=PDLQO2$5G^)_+*>r6?pEGSMrXn~h@ZL)c?Jop z6I;LZ$NoXm5v@15xj%8e*YzKD{p7y)3?~`Qz49<;t{r}9+BGi*tOU$zb0xQ@LS_K8 zv|!4G>u+X z7MQwst-^PY|7?)~E8JbtQjrJ&)In8$aC)QznHW-5xfhi3WTbu~*QE)Rm=jzn>i-kD z;0*KkJn#mlAL%I^?dn3(vC@JKb+@)hc#wAl)kv4`G2kK#i8XEOHzT){!Lx~}M~p{a zTuj7BxRcsDk$Xv_!38IbhD^Y`{Z06%=hS;MWXoQDsqm98il3Q(+|_U*|EU21x$s@z z^dw)A6oQ94&liv{+>CIv{Kc`a`$XpL_T?YBM>kmGKyZ0dv0QxHKMiT&T9_}q@}0Yn{WH%gO=56 zW1P%LfgaPER4RVihIO$R5L{CrPJ@0>7GYu_tNuy&?P^>zSPCzL)pxh7F`zuspe+Df zM1+)l;fs)}bK>kbX7MIP9WB0Ll z(`^bwaww0;nG?Cv7RTpDpAIG&#~nFyp4e-QMrZASA4e zGnkB;Ez*QD^#jVd53^oc@HuIMh&U}D}JK~+5 zk3ZlK?%JFV5U=fHa^F}OXfvVf!kS`cL$SMNc;i1&!oi+0B^dU`tY#_Q6%Lh8`JneQ z;2Ut2fQnRoQb$#yQ`v*jyBGN%6-VpZ4DDZtj)#rkvLR?yPHl76r^Eye8J^WcUmADf&xj4H0`t`U6G;}m1 z!eAT#>;eShfyJW6bS`%y%JGVoB;+RHVI`Jx0RODsE#%tQ9ubIW&c|ym$*8ih^C`XD z;RG;Vi?bdGrg(VYG8O@-=*bW9IxuUH44&f*s{QiiCKyLhCrtyhvOVNkX}A{GH>Ykw z6wE-%AHd{~-ESg`i&HV3V8v{XgntCf)f1@JtQS|VnfKt{mg_VMrP0VqbT6kbwpgAuHx#B!-(fS97tSS4l&EmydSkK zi=l74dBiM)86J0eN7*cYu#;$&BHXOqrnTRw=|oUIu<9wUH;he>!Qy&HDOkLJBm)l7P>z533*fYLt6uoaqzfg1n?|yZ7EIm>@yQ!nc27t=-!06Kn1?7Y^Me|J8!tPj zBXzWqIH^CMlVeONI<|6u9==}JRfF1q1`YgBu%tFNTj*-&g}RD4GWfLGOU65 zRM9cidU1TR;d3VxEec;>MEWhRJ+#j|zR&uQ@)b;6&)BRUZ%fj9b775PRrXD(jL0~>2 zr%%9w0ij3l?*zUaf8jaC52WkUIXf0G&X<{gV#3nV;HpWlPw|QWMrC{-IGua^W2@e% z9eXP)4tAZYPl}gEC6;dFfuYGeC(LS3XGp;nu}p->;ZFlFF%KC=kd~C`YL~GD<27*pp+YtSN6M2(cd?= z!v^fIH806@GBXy#3@S&I_Hn%=lb*3RoCk6fsHhVhl{zc4;tTXz3k%o?i+{$SpY#ZL zNDLC!dwM$&s?8$vr}Oz`jdQ;O1S&RuhJMM)qBkok&?O?QK4Ud4@%U(AngvK_-6x&7 zTR0=Nb9V&Ea8Yi#g|eWBVM}70a7BHxy*6JpBRhH)=QM!~HWaO6u6&C2VxlNsR|JYL zv?f-Nu{t7cOAE#_FKrf0Rn{pbp5-+LEsk6cEsNHcrnawa9YbEdnnfS(y|Bx=60~3+ z@zVCSYdk~GoSV;ZaGi6K#PW()fvMul{o;`2Rlk~Cwl_22Ve2rOU_m($qo|eS2IG|6^x%7IKDai~@C-!9srCME@ z|AtVbZ!|wfr2_5DfDbolF^wzRi7KB~y!?bL8&f$82gqB6vGX-)RwgI=ySd5^ad*?~)hqGH#37hyODBvm3`jo6UwY4j zzP7*YZh28Q0D zwCO-=FTpcZ^y1V7Y3nkrz5;hsWX4FToJSO>5(>+Cgn#zya`T#{q4?Bfn^h4` zt%H(&++Wj{Ii^LD@s=HZVpGc|>rv>H5tn5zFw6^A8L1^RGa5C4FeMa&TWZ_FwrZkL z&BRGPNu^wGn{n#a@=Wnyg20TSHpKrP*JXvvK=*b4%eI3Di<2*u@eiK1K^Xu8ex;JG z_W+nxI-ate0bO*nX6Tbo z>1o`l^<@J_jdQx10Qg#rUyw1w7nv}97T+Zh!nLyu~tl&4`#B#Y> z+!*h)ZhKJ`H;88=LkU(8;Ryf>ySe{gltn^Noxcq}g8*4C|E>Eh#z2gex&L4~Wx?8f zk>?8*Q}bU+2A8HE>@MM192(Fw#1Zi(*-S}aNsedbDbo4OdHi2IHFfFt5k_cw2KtwI zUGPkxnG8ejn-S_tF#uY{6Mu8!0|F8b096*`sP+~;G~J_~)PzYw9qOFFuM#vH_ zyR%OnYBaC!t4-v1BAzNU0F?_;Al|t(lQUfWrJ{8-@--O)ITr_FFZZYa!{6Zmy0bVJ zaxmup)3)>~UKa??xAM;-BU5c4OdCy2;R4#w!X_P+E(c`NH|DE5iH7<)26~<Tj6_6l9HMw>ATHaB(ShE4g-l_N_2ocMM;&R7NsahONr$@ z;HQc)x!Q+K);%~@ALtuY{1yPdwhb4#H7aWafZ2^imS2g-U|__TMw`WDbEmW#3m?m! z=xs|8(#N+>pSBi59zh0_g(umJSPVvDiy7Y1>-*Qx(H7StF5BYLCJ_w1dN0#JlRA3- zath903J0nRn!*w<9fx_^buMbD+>^Zd{5ht`MGM{ii!`>pHXA;~7J^PcaQ=1hb8vTP z)Q<1pgVlEl@*I}s*z~WJyD{6L-h#?G&|e%$VI{^MF2rMP|I=J~u*i>DE`xA^@mP9YS)pHd3Vdg|{S7m&5l`t)(r`JcO_`UB-0R;0t!HP5T>3)+ z<99dDdE_3p7V=iTOR^}erbB}!**3|Q{(ODi$F5O4Csed+$Ayqy2(VDv!`SA%N`gc| z+Tx#`zNID>jI?X!RPg+u$xGyC6#=r^ zHqcOQVz?okqGLfj{7NaH$w8(4!eZ+_wnO&6%Tbs*Z`y}2DmL}$N za6=Y2eAKxXGb z?9ioCj!34$;%Vucv=jtp-c}F)&WY?wbfev7wi6)L0r6=UIaw7=teRIJjT@@eCm{vN zmP9R1GNEBPXWPw#>-M1%rxz6=?QS6uoTo+Q%Ufl@1ROB+CjvR{diXVZ+=G8q*T|yD z@?cA8yqanUvcTU`6*Amq#`BeW(d< zTRX8|GUrQ*@8OAO28zVWd9gRTFU-~G@x;KBYKyA<3Eu}dlU%3I$l8FHiWW!%`q~*| zzMLjY;jMfJSk|vYq`RSi<4e(urboLeEKMR@vqRl>?eha#s&3NM4Dg4HbNHHp4nlHflZTJjEBWdbKNiq9`r3|SU%GN2j$!8$YaZTZ zz!3T6lL}xMkVXYod!RMaDX=4G0{2B(F335hU?z9v^mye_{JI(7V2yF@U!9V{g+^;+ zm0$r?`1I2_;_bKvf!r^`Wx=MGl)zA+8O-o3UsklC@F5TWJLhP|Hr4IMNU_I-v1lBX zupaNHIbdtM*vl{C>eN8omL@)ly^mR9OIA|7QAUUsjSrZNU5J)Qh&clRgLZe zqNJhS(hOgvndM}VQ8FCeGTdKfc;#d{f97s^B4~=o6(F(5)EqRWU+NDJDuOzFXk} zugV2-DiN&F*?RoU@b{$(Et;m#S`q8>HJ`r$q zPUEE$wOBV`$-I_I>tKtgaVVrGN-yY}{?lF7P!B)Zak`0`G8Y}vXLWn_?zR-?_{ ze$yaj4hj~Veg7u8hR}YfZSq6j;yo^UK%z?4#tfohiS&ygK_wWG7DxpvXTOO0Y(q73 z4a|4_q3*wCGaa(ut%XV~YqmMuwm6LFZRC1YcyTB!5$VK>KqGB`6svmBSo+wS2b8FW z*;;zM$N0zCC-q9pC^!Tx326eUu|rW#Lf>ufIMj8?L=yPV4uN*5=(8;TrV^)@yVmu* zyl%Xhe;((}4*^z5*Q$EgBDW!T(L#~6&}CcaYspq`N?hN5ckLfhL=hh~i>%(hpwh3_ z5(_+axf9vmMS^v0LTMH05Q=2J=ZwqN$?9pR@CzJ+e119-2S4=K&qdVl^1 zba01AZhBwGLt4=RZJUtR5`nG~$#Nf0W?A1y-`DSwyn#tDw@pa?8K_z@P<@1-xb-(p zhRNK6W2(@F%JulwW@DP$`xwuQr={JXBUT19J?n!Tg+-N zv>NSc+2`Y|==2sDYgp#-J}c--Ka?CB{A!05g}s(VWxc)=%-o@~q$nU-1DERmEZZMd z)_0>uQ3$r|y~7r<7n^V~Q=HQbObBA^sz#O4#!pJ+%-DpI6VCWdvByt&K4 zlBA@Eq@cF3K}=R|xj*sm7(5nQ;)i zvqViL&#z}O|D6loF6GPVm)cFO982or)Y-|(GM_L@f2SCJ!4?)23#mTOTo2wFX=LaS35RD_@-5a#aaMmP^GJO7<)PPRYUI#0Ho*I2iJ5TVTv!F6CO zCf_?xV)sR>cz*>wbceta8b%eH_4!hAQSc*&l<(zt-rKsCEi-ovG<+sxeB$NJar%#S z^Pd5eI)76(LD9~TQLAN=eMfb2?MB(PADO_KUn*{%jp{j#6kGUmPDt+LMTC0tYc^G=xDjRGSaoK)-kfPZJ$` z$3p&^9qxSA`?|OEcsQ*8?dDocKp9)s!*bZcg+hw;jo808GsVUErF&V%%I^|u81tvm z-(m!%nVFLns&}zzy!H1WK7B&<_yr?ON9*mK8Eh-}#&DR5rJm0g`D9Bk43n@&$YBy{CcP7fP z@PqC89ubKc0@b>|8^$s_@zRr?Ne;WyPyh@d52%3K?ss)b9goA7e~109A0q%NI=nE1 z7IPdBR?aR(#Ix@|hwr;FKdBR8)1W`U{kctJ>(uid^VQ=U&kuo_TkoGU=+uP#B=0

      uG6St6 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

      vgq^5qtUzY&_ow)^wCK3hv`mnK2hztU{c%_ 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%0DFq-t5|e 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

      hAlrweJ(*fBJ_dro?X#p(~oc*fd926SlW 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 ZtUFHGMByJk%<>ez{KK4i`DO Date: Mon, 4 Feb 2019 10:00:30 +0100 Subject: [PATCH 0402/1182] Fix several ResourceWarning: unclosed file (#741) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mickaël Schoentgen --- httpie/input.py | 4 +-- tests/test_downloads.py | 59 ++++++++++++++++++++++------------------- tests/utils.py | 2 ++ 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/httpie/input.py b/httpie/input.py index c753bcc1be..1ab34c9b04 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -752,7 +752,7 @@ def parse_items(items, def readable_file_arg(filename): try: - open(filename, 'rb') + with open(filename, 'rb'): + return filename except IOError as ex: raise ArgumentTypeError('%s: %s' % (filename, ex.args[1])) - return filename diff --git a/tests/test_downloads.py b/tests/test_downloads.py index a678d0d807..5356721fbf 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -131,35 +131,38 @@ def test_actual_download(self, httpbin_both, httpbin): assert body == r def test_download_with_Content_Length(self, httpbin_both): - devnull = open(os.devnull, 'w') - downloader = Downloader(output_file=devnull, progress_file=devnull) - downloader.start(Response( - url=httpbin_both.url + '/', - headers={'Content-Length': 10} - )) - time.sleep(1.1) - downloader.chunk_downloaded(b'12345') - time.sleep(1.1) - downloader.chunk_downloaded(b'12345') - downloader.finish() - assert not downloader.interrupted + with open(os.devnull, 'w') as devnull: + downloader = Downloader(output_file=devnull, progress_file=devnull) + downloader.start(Response( + url=httpbin_both.url + '/', + headers={'Content-Length': 10} + )) + time.sleep(1.1) + downloader.chunk_downloaded(b'12345') + time.sleep(1.1) + downloader.chunk_downloaded(b'12345') + downloader.finish() + assert not downloader.interrupted + downloader._progress_reporter.join() def test_download_no_Content_Length(self, httpbin_both): - devnull = open(os.devnull, 'w') - downloader = Downloader(output_file=devnull, progress_file=devnull) - downloader.start(Response(url=httpbin_both.url + '/')) - time.sleep(1.1) - downloader.chunk_downloaded(b'12345') - downloader.finish() - assert not downloader.interrupted + with open(os.devnull, 'w') as devnull: + downloader = Downloader(output_file=devnull, progress_file=devnull) + downloader.start(Response(url=httpbin_both.url + '/')) + time.sleep(1.1) + downloader.chunk_downloaded(b'12345') + downloader.finish() + assert not downloader.interrupted + downloader._progress_reporter.join() def test_download_interrupted(self, httpbin_both): - devnull = open(os.devnull, 'w') - downloader = Downloader(output_file=devnull, progress_file=devnull) - downloader.start(Response( - url=httpbin_both.url + '/', - headers={'Content-Length': 5} - )) - downloader.chunk_downloaded(b'1234') - downloader.finish() - assert downloader.interrupted + with open(os.devnull, 'w') as devnull: + downloader = Downloader(output_file=devnull, progress_file=devnull) + downloader.start(Response( + url=httpbin_both.url + '/', + headers={'Content-Length': 5} + )) + downloader.chunk_downloaded(b'1234') + downloader.finish() + assert downloader.interrupted + downloader._progress_reporter.join() diff --git a/tests/utils.py b/tests/utils.py index c9b3575e28..23bca713aa 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -62,6 +62,8 @@ def config(self): return super(MockEnvironment, self).config def cleanup(self): + self.stdout.close() + self.stderr.close() if self._delete_config_dir: assert self.config_dir.startswith(tempfile.gettempdir()) from shutil import rmtree From b6309547d535287dd11429ba11a999414149b7fd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 11 Mar 2019 08:41:24 +0100 Subject: [PATCH 0403/1182] Add a bash here string example --- README.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.rst b/README.rst index 9bcca0bda3..87f0454352 100644 --- a/README.rst +++ b/README.rst @@ -1112,6 +1112,13 @@ You can use ``echo`` for simple data: $ echo '{"name": "John"}' | http PATCH example.com/person/1 X-API-Token:123 +You can also use a Bash *here string*: + +.. code-block:: bash + + $ http example.com/ <<<'{"name": "John"}' + + You can even pipe web services together using HTTPie: .. code-block:: bash From fd44f1af93ce1d2c84f324b8474d2d075b5a7b13 Mon Sep 17 00:00:00 2001 From: Harkirat Singh Date: Wed, 10 Apr 2019 16:51:37 +0530 Subject: [PATCH 0404/1182] Updated Readme to fix a typo (#767) --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 87f0454352..a210d1ddae 100644 --- a/README.rst +++ b/README.rst @@ -1566,7 +1566,7 @@ Best practices -------------- The default behaviour of automatically reading ``stdin`` is typically not -desirable during non-interactive invocations. You most likely want +desirable during non-interactive invocations. You most likely want to use the ``--ignore-stdin`` option to disable it. It is a common gotcha that without this option HTTPie seemingly hangs. From e92b831e6e044a366d1907761fcc63a254a021a7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jun 2019 12:05:24 +0200 Subject: [PATCH 0405/1182] Create FUNDING.yml --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..80d84ae3c9 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: https://paypal.me/roztocil From df36d6255df5793129b02ac82f1010171bd8a0a8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 24 Jun 2019 12:19:29 +0200 Subject: [PATCH 0406/1182] Changed the way the output filename is generated When ``--download`` without ``--output`` results in a redirect, now only the initial URL is considered, not the final one. --- CHANGELOG.rst | 4 +++- README.rst | 20 ++++++++++++---- httpie/downloads.py | 52 ++++++++++++++++++++++++----------------- tests/test_downloads.py | 14 +++++++++++ 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 39da325332..03cab7be86 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,7 +9,9 @@ This project adheres to `Semantic Versioning `_. `1.0.3-dev`_ (unreleased) ------------------------- -* No changes yet. +* Changed the way the output filename is generated for ``--download`` requests + without ``--output`` and with a redirect — now only the initial URL is + considered, not the final one. `1.0.2`_ (2018-11-14) diff --git a/README.rst b/README.rst index a210d1ddae..a18a385e62 100644 --- a/README.rst +++ b/README.rst @@ -1316,10 +1316,22 @@ is being saved to a file. Downloaded file name -------------------- -If not provided via ``--output, -o``, the output filename will be determined -from ``Content-Disposition`` (if available), or from the URL and -``Content-Type``. If the guessed filename already exists, HTTPie adds a unique -suffix to it. +There are three mutually exclusive ways through which HTTPie determines +the output file name (with decreasing priority): + +1. You can explicitly provide the exact output file name via ``--output, -o``. + The file gets overwritten if it already exists + (or appended to with ``--continue, -c``). +2. The server may specify the file name in the optional ``Content-Disposition`` + response header. Any leading dots are stripped from a server-provided filename. +3. The last resort HTTPie uses is to generate the filename from a combination + of the request URL and the response ``Content-Type``. + The initial URL is always used as the basis for + the generated filename — even if there has been one or more redirects. + + +To prevent data loss, HTTPie adds a unique numerical suffix to the +filename, unless the name has been explicitly provided via ``--output, -o``. Piping while downloading diff --git a/httpie/downloads.py b/httpie/downloads.py index 8c714c54e6..200dfb8477 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -224,13 +224,13 @@ def pre_request(self, request_headers): request_headers['Range'] = 'bytes=%d-' % bytes_have self._resumed_from = bytes_have - def start(self, response): + def start(self, final_response): """ Initiate and return a stream for `response` body with progress callback attached. Can be called only once. - :param response: Initiated response object with headers already fetched - :type response: requests.models.Response + :param final_response: Initiated response object with headers already fetched + :type final_response: requests.models.Response :return: RawStream, output_file @@ -240,14 +240,18 @@ def start(self, response): # FIXME: some servers still might sent Content-Encoding: gzip # try: - total_size = int(response.headers['Content-Length']) + total_size = int(final_response.headers['Content-Length']) except (KeyError, ValueError, TypeError): total_size = None - if self._output_file: - if self._resume and response.status_code == PARTIAL_CONTENT: + if not self._output_file: + self._output_file = self._get_output_file_from_response( + final_response) + else: + # `--continue, -c` provided + if self._resume and final_response.status_code == PARTIAL_CONTENT: total_size = parse_content_range( - response.headers.get('Content-Range'), + final_response.headers.get('Content-Range'), self._resumed_from ) @@ -258,19 +262,6 @@ def start(self, response): self._output_file.truncate() except IOError: pass # stdout - else: - # TODO: Should the filename be taken from response.history[0].url? - # Output file not specified. Pick a name that doesn't exist yet. - filename = None - if 'Content-Disposition' in response.headers: - filename = filename_from_content_disposition( - response.headers['Content-Disposition']) - if not filename: - filename = filename_from_url( - url=response.url, - content_type=response.headers.get('Content-Type'), - ) - self._output_file = open(get_unique_filename(filename), mode='a+b') self.status.started( resumed_from=self._resumed_from, @@ -278,7 +269,7 @@ def start(self, response): ) stream = RawStream( - msg=HTTPResponse(response), + msg=HTTPResponse(final_response), with_headers=False, with_body=True, on_body_chunk_downloaded=self.chunk_downloaded, @@ -324,6 +315,25 @@ def chunk_downloaded(self, chunk): """ self.status.chunk_downloaded(len(chunk)) + @staticmethod + def _get_output_file_from_response(final_response): + # Output file not specified. Pick a name that doesn't exist yet. + filename = None + if 'Content-Disposition' in final_response.headers: + filename = filename_from_content_disposition( + final_response.headers['Content-Disposition']) + if not filename: + initial_response = ( + final_response.history[0] if final_response.history + else final_response + ) + filename = filename_from_url( + url=initial_response.url, + content_type=final_response.headers.get('Content-Type'), + ) + unique_filename = get_unique_filename(filename) + return open(unique_filename, mode='a+b') + class Status(object): """Holds details about the downland status.""" diff --git a/tests/test_downloads.py b/tests/test_downloads.py index 5356721fbf..e14fcef3b1 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -1,4 +1,5 @@ import os +import tempfile import time import pytest @@ -22,6 +23,7 @@ def __init__(self, url, headers={}, status_code=200): class TestDownloadUtils: + def test_Content_Range_parsing(self): parse = parse_content_range @@ -166,3 +168,15 @@ def test_download_interrupted(self, httpbin_both): downloader.finish() assert downloader.interrupted downloader._progress_reporter.join() + + def test_download_with_redirect_original_url_used_for_filename(self, httpbin): + # Redirect from `/redirect/1` to `/get`. + expected_filename = '1.json' + orig_cwd = os.getcwd() + os.chdir(tempfile.mkdtemp(prefix='httpie_download_test_')) + try: + assert os.listdir('.') == [] + http('--download', httpbin.url + '/redirect/1') + assert os.listdir('.') == [expected_filename] + finally: + os.chdir(orig_cwd) From 6dee49357d793f0112ad806a480b53f2c2d1e627 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 24 Jun 2019 12:29:42 +0200 Subject: [PATCH 0407/1182] Fix comments --- httpie/downloads.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/downloads.py b/httpie/downloads.py index 200dfb8477..9f4c761f45 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -248,7 +248,7 @@ def start(self, final_response): self._output_file = self._get_output_file_from_response( final_response) else: - # `--continue, -c` provided + # `--output, -o` provided if self._resume and final_response.status_code == PARTIAL_CONTENT: total_size = parse_content_range( final_response.headers.get('Content-Range'), From fd6e87914ca70f0825f47d226c1454e9a9a191bc Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 24 Jun 2019 12:36:08 +0200 Subject: [PATCH 0408/1182] README --- README.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index a18a385e62..f5c04a8753 100644 --- a/README.rst +++ b/README.rst @@ -1313,16 +1313,16 @@ is being saved to a file. Done. 251.30 kB in 2.73862s (91.76 kB/s) -Downloaded file name +Downloaded filename -------------------- There are three mutually exclusive ways through which HTTPie determines -the output file name (with decreasing priority): +the output filename (with decreasing priority): -1. You can explicitly provide the exact output file name via ``--output, -o``. +1. You can explicitly provide it via ``--output, -o``. The file gets overwritten if it already exists (or appended to with ``--continue, -c``). -2. The server may specify the file name in the optional ``Content-Disposition`` +2. The server may specify the filename in the optional ``Content-Disposition`` response header. Any leading dots are stripped from a server-provided filename. 3. The last resort HTTPie uses is to generate the filename from a combination of the request URL and the response ``Content-Type``. @@ -1330,8 +1330,8 @@ the output file name (with decreasing priority): the generated filename — even if there has been one or more redirects. -To prevent data loss, HTTPie adds a unique numerical suffix to the -filename, unless the name has been explicitly provided via ``--output, -o``. +To prevent data loss by overwriting, HTTPie adds a unique numerical suffix to the +filename when necessary (unless specified with ``--output, -o``). Piping while downloading @@ -1578,7 +1578,7 @@ Best practices -------------- The default behaviour of automatically reading ``stdin`` is typically not -desirable during non-interactive invocations. You most likely want to +desirable during non-interactive invocations. You most likely want to use the ``--ignore-stdin`` option to disable it. It is a common gotcha that without this option HTTPie seemingly hangs. From c5ca9d248eaad2dc04f2388a784a62d2e2bcbc84 Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Wed, 17 Jul 2019 22:58:37 -0600 Subject: [PATCH 0409/1182] Allow stdin to be a closed fd Before this change, the following invocation would not work ``` $ http http://neverhttps.com <&- ``` The "<&-" at the end closes the stdin fd. Specifically, it would fail with ``` ... File "/home/mgsloan/.local/lib/python3.6/site-packages/httpie/context.py", line 26, in Environment stdin_isatty = stdin.isatty() AttributeError: 'NoneType' object has no attribute 'isatty' ``` This can occur when httpie is being programmatically invoked, and may as well be supported. --- httpie/context.py | 4 ++-- httpie/input.py | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/httpie/context.py b/httpie/context.py index bc555863f2..3873024de2 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -23,7 +23,7 @@ class Environment(object): is_windows = is_windows config_dir = DEFAULT_CONFIG_DIR stdin = sys.stdin - stdin_isatty = stdin.isatty() + stdin_isatty = stdin.isatty() if stdin else False stdin_encoding = None stdout = sys.stdout stdout_isatty = stdout.isatty() @@ -61,7 +61,7 @@ def __init__(self, **kwargs): self.__dict__.update(**kwargs) # Keyword arguments > stream.encoding > default utf8 - if self.stdin_encoding is None: + if self.stdin and self.stdin_encoding is None: self.stdin_encoding = getattr( self.stdin, 'encoding', None) or 'utf8' if self.stdout_encoding is None: diff --git a/httpie/input.py b/httpie/input.py index 1ab34c9b04..2e40d82ded 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -142,6 +142,12 @@ def parse_args(self, env, args=None, namespace=None): if self.args.debug: self.args.traceback = True + self.has_stdin_data = ( + self.env.stdin + and not self.args.ignore_stdin + and not self.env.stdin_isatty + ) + # Arguments processing and environment setup. self._apply_no_options(no_options) self._validate_download_options() @@ -150,7 +156,8 @@ def parse_args(self, env, args=None, namespace=None): self._process_pretty_options() self._guess_method() self._parse_items() - if not self.args.ignore_stdin and not env.stdin_isatty: + + if self.has_stdin_data: self._body_from_file(self.env.stdin) if not URL_SCHEME_RE.match(self.args.url): scheme = self.args.default_scheme + "://" @@ -315,7 +322,7 @@ def _guess_method(self): if self.args.method is None: # Invoked as `http URL'. assert not self.args.items - if not self.args.ignore_stdin and not self.env.stdin_isatty: + if self.has_stdin_data: self.args.method = HTTP_POST else: self.args.method = HTTP_GET @@ -339,7 +346,7 @@ def _guess_method(self): self.args.url = self.args.method # Infer the method has_data = ( - (not self.args.ignore_stdin and not self.env.stdin_isatty) + self.has_stdin_data or any( item.sep in SEP_GROUP_DATA_ITEMS for item in self.args.items From 88a9583f4c0682fc4d26525380d82802eb242784 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 20 Jul 2019 13:03:30 +0200 Subject: [PATCH 0410/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 03cab7be86..e40df2f3f0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,7 +11,7 @@ This project adheres to `Semantic Versioning `_. * Changed the way the output filename is generated for ``--download`` requests without ``--output`` and with a redirect — now only the initial URL is - considered, not the final one. + considered, not the final one. Thanks to Raul Onitza of Snyk for bringing this up. `1.0.2`_ (2018-11-14) From 747be30d2efda1b4287a84f1f27f4328621b222c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 26 Aug 2019 12:42:34 +0200 Subject: [PATCH 0411/1182] 1.0.3 --- CHANGELOG.rst | 30 +++++++++++++++++++++++++----- Makefile | 5 ++--- httpie/__init__.py | 2 +- requirements-dev.txt | 1 + 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e40df2f3f0..d9e811e8fd 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,12 +6,32 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. -`1.0.3-dev`_ (unreleased) +`1.0.3`_ (2019-08-26) ------------------------- -* Changed the way the output filename is generated for ``--download`` requests - without ``--output`` and with a redirect — now only the initial URL is - considered, not the final one. Thanks to Raul Onitza of Snyk for bringing this up. +* Fixed CVE-2019-10751 — the way the output filename is generated for + ``--download`` requests without ``--output`` resulting in a redirect has + been changed to only consider the initial URL as the base for the generated + filename, and not the final one. This fixes a potential security issue under + the following scenario: + + 1. A ``--download`` request with no explicit ``--output`` is made (e.g., + ``$ http -d example.org/file.txt``), instructing httpie to + `generate the output filename `_ + from the ``Content-Disposition`` response, or from the URL if the header + is not provided. + 2. The server handling the request has been modified by an attacker and + instead of the expected response the URL returns a redirect to another + URL, e.g., ``attacker.example.org/.bash_profile``, whose response does + not provide a ``Content-Disposition`` header (i.e., the base for the + generated filename becomes ``.bash_profile`` instead of ``file.txt``). + 3. Your current directory doesn’t already contain ``.bash_profile`` + (i.e., no unique suffix is added to the generated filename). + 4. You don’t notice the potentially unexpected output filename + as reported by httpie in the console output + (e.g., ``Downloading 100.00 B to ".bash_profile"``). + + Reported by Raul Onitza and Giulio Comi. `1.0.2`_ (2018-11-14) @@ -363,4 +383,4 @@ This project adheres to `Semantic Versioning `_. .. _1.0.0: https://github.com/jakubroztocil/httpie/compare/0.9.9...1.0.0 .. _1.0.1: https://github.com/jakubroztocil/httpie/compare/1.0.0...1.0.1 .. _1.0.2: https://github.com/jakubroztocil/httpie/compare/1.0.1...1.0.2 -.. _1.0.3-dev: https://github.com/jakubroztocil/httpie/compare/1.0.2...master +.. _1.0.3: https://github.com/jakubroztocil/httpie/compare/1.0.2...1.0.3 diff --git a/Makefile b/Makefile index c477abe827..85ebafb562 100644 --- a/Makefile +++ b/Makefile @@ -93,9 +93,8 @@ publish-no-test: @echo $(TAG)Testing wheel build an installation$(END) @echo "$(VERSION)" @echo "$(VERSION)" | grep -q "dev" && echo '!!!Not publishing dev version!!!' && exit 1 || echo ok - python setup.py register - python setup.py sdist upload - python setup.py bdist_wheel upload + python setup.py sdist bdist_wheel + twine upload dist/* @echo diff --git a/httpie/__init__.py b/httpie/__init__.py index 6ff7658c58..121cc76dbd 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -2,7 +2,7 @@ HTTPie - a CLI, cURL-like tool for humans. """ -__version__ = '1.0.3-dev' +__version__ = '1.0.3' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' diff --git a/requirements-dev.txt b/requirements-dev.txt index 3384c15230..e0ccd39ce1 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -6,3 +6,4 @@ pytest-httpbin>=0.0.6 docutils wheel pycodestyle +twine From 0a0de1755ef9f182106271cadb401bdb7377397b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 26 Aug 2019 12:47:31 +0200 Subject: [PATCH 0412/1182] Fix link --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d9e811e8fd..7509af4e0e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,7 +17,7 @@ This project adheres to `Semantic Versioning `_. 1. A ``--download`` request with no explicit ``--output`` is made (e.g., ``$ http -d example.org/file.txt``), instructing httpie to - `generate the output filename `_ + `generate the output filename `_ from the ``Content-Disposition`` response, or from the URL if the header is not provided. 2. The server handling the request has been modified by an attacker and From 3dccb2e32589bd6521d1d8587f8b351496be8372 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 26 Aug 2019 17:42:47 +0200 Subject: [PATCH 0413/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7509af4e0e..89ef0ca96c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,7 +18,7 @@ This project adheres to `Semantic Versioning `_. 1. A ``--download`` request with no explicit ``--output`` is made (e.g., ``$ http -d example.org/file.txt``), instructing httpie to `generate the output filename `_ - from the ``Content-Disposition`` response, or from the URL if the header + from the ``Content-Disposition`` response header, or from the URL if the header is not provided. 2. The server handling the request has been modified by an attacker and instead of the expected response the URL returns a redirect to another From fa96041ec88298c342698132b9e4069001d81281 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 28 Aug 2019 11:05:07 +0200 Subject: [PATCH 0414/1182] Update README.rst --- README.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f5c04a8753..baf1323d33 100644 --- a/README.rst +++ b/README.rst @@ -25,7 +25,7 @@ generally interacting with HTTP servers. .. class:: no-web no-pdf -|pypi| |unix_build| |coverage| |gitter| +|pypi| |unix_build| |coverage| |downloads| |gitter| @@ -1751,3 +1751,8 @@ have contributed. .. |gitter| image:: https://img.shields.io/gitter/room/jkbrzt/httpie.svg?style=flat-square :target: https://gitter.im/jkbrzt/httpie :alt: Chat on Gitter + +.. |downloads| image:: https://pepy.tech/badge/httpie + :target: https://pepy.tech/project/httpie + :alt: Download count + From add660100949f31c9e37d863a98321412ae043ed Mon Sep 17 00:00:00 2001 From: Jeff Byrnes Date: Thu, 29 Aug 2019 01:38:46 -0400 Subject: [PATCH 0415/1182] Update homebrew formula for 1.0.3 (#801) * Update brew formula for 1.0.3 This updates the Homebrew formula to: * Install httpie 1.0.3 * Install the most up-to-date dependencies for httpie * Add myself to AUTHORS --- AUTHORS.rst | 2 +- extras/httpie.rb | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index 13577d3aba..22bbfa8178 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -36,5 +36,5 @@ Patches and ideas * `Dennis Brakhane `_ * `Matt Layman `_ * `Edward Yang `_ - +* `Jeff Byrnes `_ diff --git a/extras/httpie.rb b/extras/httpie.rb index 5db5aff9fd..04f6123db4 100644 --- a/extras/httpie.rb +++ b/extras/httpie.rb @@ -9,8 +9,8 @@ class Httpie < Formula desc "User-friendly cURL replacement (command-line HTTP client)" homepage "https://httpie.org/" - url "https://files.pythonhosted.org/packages/09/8d/581ef7bd9a09dc30b621638a4fa805a2073bbfb45fa06ed37f998f172419/httpie-1.0.2.tar.gz" - sha256 "fc676c85febdf3d80abc1ef6fa71ec3764d8b838806a7ae4e55e5e5aa014a2ab" + url "https://files.pythonhosted.org/packages/d5/a4/ab61c1dbfdef33c7b7f5f7df0d79eb5cd55a106601a4acc17f983f320b4a/httpie-1.0.3.tar.gz" + sha256 "6d1b6e21da7d3ec030ae95536d4032c1129bdaf9de4adc72c596b87e5f646e80" head "https://github.com/jakubroztocil/httpie.git" bottle do @@ -22,24 +22,24 @@ class Httpie < Formula depends_on "python" - resource "Pygments" do - url "https://files.pythonhosted.org/packages/64/69/413708eaf3a64a6abb8972644e0f20891a55e621c6759e2c3f3891e05d63/Pygments-2.3.1.tar.gz" - sha256 "5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a" + resource "Pygments" do + url "https://files.pythonhosted.org/packages/7e/ae/26808275fc76bf2832deb10d3a3ed3107bc4de01b85dcccbe525f2cd6d1e/Pygments-2.4.2.tar.gz" + sha256 "881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297" end resource "requests" do - url "https://files.pythonhosted.org/packages/52/2c/514e4ac25da2b08ca5a464c50463682126385c4272c18193876e91f4bc38/requests-2.21.0.tar.gz" - sha256 "502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e" + url "https://files.pythonhosted.org/packages/01/62/ddcf76d1d19885e8579acb1b1df26a852b03472c0e46d2b959a714c90608/requests-2.22.0.tar.gz" + sha256 "11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4" end resource "certifi" do - url "https://files.pythonhosted.org/packages/55/54/3ce77783acba5979ce16674fc98b1920d00b01d337cfaaf5db22543505ed/certifi-2018.11.29.tar.gz" - sha256 "47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7" + url "https://files.pythonhosted.org/packages/c5/67/5d0548226bcc34468e23a0333978f0e23d28d0b3f0c71a151aef9c3f7680/certifi-2019.6.16.tar.gz" + sha256 "945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" end resource "urllib3" do - url "https://files.pythonhosted.org/packages/b1/53/37d82ab391393565f2f831b8eedbffd57db5a718216f82f1a8b4d381a1c1/urllib3-1.24.1.tar.gz" - sha256 "de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" + url "https://files.pythonhosted.org/packages/4c/13/2386233f7ee40aa8444b47f7463338f3cbdf00c316627558784e3f542f07/urllib3-1.25.3.tar.gz" + sha256 "dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" end resource "idna" do @@ -53,8 +53,8 @@ class Httpie < Formula end resource "PySocks" do - url "https://files.pythonhosted.org/packages/53/12/6bf1d764f128636cef7408e8156b7235b150ea31650d0260969215bb8e7d/PySocks-1.6.8.tar.gz" - sha256 "3fe52c55890a248676fd69dc9e3c4e811718b777834bcaab7a8125cf9deac672" + url "https://files.pythonhosted.org/packages/15/ab/35824cfdee1aac662e3298275fa1e6cbedb52126d1785f8977959b769ccf/PySocks-1.7.0.tar.gz" + sha256 "d9031ea45fdfacbe59a99273e9f0448ddb33c1580fe3831c1b09557c5718977c" end def install From 4d299a553177175eedfa65e42580ea97627be2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Dur=C3=A1n=20Balda?= Date: Thu, 29 Aug 2019 07:59:18 +0200 Subject: [PATCH 0416/1182] Fix tests (work in progress) (#796) * Add pyOpenSSL to dev requirements to fix tests on py2 * Add pyOpenSSL to the install requires * Remove pyOpenSSL from install_requires --- requirements-dev.txt | 3 ++- setup.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index e0ccd39ce1..66b9e01183 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -6,4 +6,5 @@ pytest-httpbin>=0.0.6 docutils wheel pycodestyle -twine +pyOpenSSL +twine \ No newline at end of file diff --git a/setup.py b/setup.py index 3cb04c8b6b..7103569d58 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ def run_tests(self): install_requires = [ 'requests>=2.21.0', - 'Pygments>=2.3.1' + 'Pygments>=2.3.1', ] From 29df4cd4f3d0a9b15213f00556c8a3b6d97478b7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 08:05:31 +0200 Subject: [PATCH 0417/1182] fix test_ssl_version on pypy --- tests/test_ssl.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index ef274dd508..7b0c29bbf9 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -5,6 +5,7 @@ import requests.exceptions from httpie import ExitStatus +from httpie.compat import is_pypy from httpie.input import SSL_VERSION_ARG_MAPPING from utils import HTTP_OK, TESTS_ROOT, http @@ -43,8 +44,8 @@ def test_ssl_version(httpbin_secure, ssl_version): ) assert HTTP_OK in r except ssl_errors as e: - if ssl_version == 'ssl3': - # pytest-httpbin doesn't support ssl3 + if ssl_version == 'ssl3' and not is_pypy: + # pytest-httpbin doesn't support ssl3 (unless on pypy) assert 'SSLV3_ALERT_HANDSHAKE_FAILURE' in str(e) else: raise From 4dd9dbd3146de5e025fc5a41edac98071db31cf1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 08:14:19 +0200 Subject: [PATCH 0418/1182] fix test_ssl_version II --- tests/test_ssl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 7b0c29bbf9..d4227d1e0e 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -44,9 +44,9 @@ def test_ssl_version(httpbin_secure, ssl_version): ) assert HTTP_OK in r except ssl_errors as e: - if ssl_version == 'ssl3' and not is_pypy: - # pytest-httpbin doesn't support ssl3 (unless on pypy) - assert 'SSLV3_ALERT_HANDSHAKE_FAILURE' in str(e) + if ssl_version == 'ssl3': + # pytest-httpbin doesn't support ssl3 + pass else: raise From db3016a602aaae043e96e4772b1f6682b9b02247 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 08:15:39 +0200 Subject: [PATCH 0419/1182] Temporarily disable macOS stock Python Travis build It's failing with InterpreterNotFound https://travis-ci.org/jakubroztocil/httpie/jobs/578195789 --- .travis.yml | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 90bb9396b7..e89f373901 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,32 +8,32 @@ env: - NEWEST_PYTHON=3.7 python: # - - 2.7 - # Python 3.4 fails installing packages # # - 3.4 - - 3.5 - 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: - # Add manually defined OS X builds + + # Manually defined macOS builds # - - os: osx - language: generic - env: - # Stock OSX Python - - TOXENV=py27-osx-builtin - - BREW_PYTHON_PACKAGE= + + # FIXME: stock macOS python fails with InterpreterNotFound + # + # - os: osx + # language: generic + # env: + # # Stock macOS Python + # - TOXENV=py27-osx-builtin + # - BREW_PYTHON_PACKAGE= - os: osx language: generic env: @@ -46,16 +46,22 @@ matrix: # 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 - # Travis Python 3.7 must run sudo on + + + # Travis Python 3.7 must run sudo on - os: linux 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 From c1d5a4a109776e7f7b27811a279cf050a844b682 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 08:34:55 +0200 Subject: [PATCH 0420/1182] fix tests --- .travis.yml | 1 + requirements-dev.txt | 3 +-- setup.py | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e89f373901..d340af990f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -66,6 +66,7 @@ install: - | if [[ $TRAVIS_OS_NAME == 'osx' ]]; then if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then + export HOMEBREW_NO_INSTALL_CLEANUP=1 brew update if ! brew list --versions "$BREW_PYTHON_PACKAGE" >/dev/null; then brew install "$BREW_PYTHON_PACKAGE" diff --git a/requirements-dev.txt b/requirements-dev.txt index 66b9e01183..e0ccd39ce1 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -6,5 +6,4 @@ pytest-httpbin>=0.0.6 docutils wheel pycodestyle -pyOpenSSL -twine \ No newline at end of file +twine diff --git a/setup.py b/setup.py index 7103569d58..bb304288f5 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ from setuptools.command.test import test as TestCommand import httpie +from httpie.compat import is_py27 class PyTest(TestCommand): @@ -33,6 +34,9 @@ def run_tests(self): 'mock', ] +if is_py27: + tests_require.append('pyOpenSSL') + install_requires = [ 'requests>=2.21.0', From f27b626a96e4bdc21c5bf90a2f79669148a9b705 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 08:38:34 +0200 Subject: [PATCH 0421/1182] fix tests --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index c394120e0b..d40d5b90ab 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,7 @@ deps = mock pytest pytest-httpbin>=0.0.6 + pyOpenSSL commands = From c297af001286a8612ee3725caddbfc756d8517c1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 08:39:23 +0200 Subject: [PATCH 0422/1182] doc --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index d40d5b90ab..7bbbd0d588 100644 --- a/tox.ini +++ b/tox.ini @@ -8,6 +8,7 @@ envlist = py27, py37, pypy [testenv] +# pyOpenSSL only needed for Python 2.7 deps = mock pytest From b3d2c1876e23e7de7afe588e4f64160d17201b45 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 08:53:56 +0200 Subject: [PATCH 0423/1182] Python 2.7 support removal WIP --- .travis.yml | 20 +------------------- README.rst | 30 ++---------------------------- httpie/__init__.py | 2 +- httpie/client.py | 1 - httpie/compat.py | 35 ----------------------------------- httpie/core.py | 3 +-- httpie/downloads.py | 2 +- httpie/input.py | 14 ++------------ httpie/models.py | 2 +- httpie/output/streams.py | 1 - httpie/sessions.py | 2 +- setup.py | 8 ++------ tests/test_downloads.py | 2 +- tests/test_output.py | 2 +- tests/test_ssl.py | 1 - tests/utils.py | 1 - tox.ini | 7 +------ 17 files changed, 15 insertions(+), 118 deletions(-) diff --git a/.travis.yml b/.travis.yml index d340af990f..33e85b2517 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,15 +7,12 @@ env: global: - NEWEST_PYTHON=3.7 python: - # - - 2.7 # Python 3.4 fails installing packages # # - 3.4 - 3.5 - 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 @@ -23,23 +20,8 @@ cache: pip matrix: include: - # Manually defined macOS builds + # Manually defined macOS build # - - # FIXME: stock macOS python fails with InterpreterNotFound - # - # - os: osx - # language: generic - # env: - # # Stock macOS Python - # - TOXENV=py27-osx-builtin - # - BREW_PYTHON_PACKAGE= - - os: osx - language: generic - env: - # Latest Python 2.7 from Homebrew - - TOXENV=py27 - - BREW_PYTHON_PACKAGE=python@2 - os: osx language: generic env: diff --git a/README.rst b/README.rst index baf1323d33..5f7a6da3ed 100644 --- a/README.rst +++ b/README.rst @@ -47,7 +47,6 @@ Main features * Custom headers * Persistent sessions * Wget-like downloads -* Python 2.7 and 3.x support * Linux, macOS and Windows support * Plugins * Documentation @@ -125,12 +124,7 @@ and always provides the latest version) is to use `pip`_: Python version -------------- -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``. +Starting with version 2.0.0 (currently under development) Python 3.x is required. Unstable version @@ -945,26 +939,6 @@ available set of protocols may vary depending on your OpenSSL installation.) $ http --ssl=ssl3 https://vulnerable.example.org -SNI (Server Name Indication) ----------------------------- - -If you use HTTPie with `Python version`_ lower than 2.7.9 -(can be verified with ``http --debug``) and need to talk to servers that -use SNI (Server Name Indication) you need to install some additional -dependencies: - -.. code-block:: bash - - $ pip install --upgrade requests[security] - - -You can use the following command to test SNI support: - -.. code-block:: bash - - $ http https://sni.velox.ch - - Output options ============== @@ -1755,4 +1729,4 @@ have contributed. .. |downloads| image:: https://pepy.tech/badge/httpie :target: https://pepy.tech/project/httpie :alt: Download count - + diff --git a/httpie/__init__.py b/httpie/__init__.py index 121cc76dbd..6b28eeefc1 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -2,7 +2,7 @@ HTTPie - a CLI, cURL-like tool for humans. """ -__version__ = '1.0.3' +__version__ = '2.0.0-dev' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' diff --git a/httpie/client.py b/httpie/client.py index 21a7f67aff..91677ea8fe 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -7,7 +7,6 @@ from httpie import sessions from httpie import __version__ -from httpie.compat import str from httpie.input import SSL_VERSION_ARG_MAPPING from httpie.plugins import plugin_manager from httpie.utils import repr_dict_nice diff --git a/httpie/compat.py b/httpie/compat.py index d81e508b5e..f508bbb360 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -1,39 +1,4 @@ -""" -Python 2.7, and 3.x compatibility. - -""" import sys -is_py2 = sys.version_info[0] == 2 -is_py27 = sys.version_info[:2] == (2, 7) -is_py3 = sys.version_info[0] == 3 -is_pypy = 'pypy' in sys.version.lower() is_windows = 'win32' in str(sys.platform).lower() - - -if is_py2: - # noinspection PyShadowingBuiltins - bytes = str - # noinspection PyUnresolvedReferences,PyShadowingBuiltins - str = unicode -elif is_py3: - # noinspection PyShadowingBuiltins - str = str - # noinspection PyShadowingBuiltins - bytes = bytes - - -try: # pragma: no cover - # noinspection PyUnresolvedReferences,PyCompatibility - from urllib.parse import urlsplit -except ImportError: # pragma: no cover - # noinspection PyUnresolvedReferences,PyCompatibility - from urlparse import urlsplit - -try: # pragma: no cover - # noinspection PyCompatibility - from urllib.request import urlopen -except ImportError: # pragma: no cover - # noinspection PyCompatibility,PyUnresolvedReferences - from urllib2 import urlopen diff --git a/httpie/core.py b/httpie/core.py index 8ad0e2a67a..fb3d9662dc 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -19,7 +19,6 @@ from pygments import __version__ as pygments_version from httpie import __version__ as httpie_version, ExitStatus -from httpie.compat import str, bytes, is_py3 from httpie.client import get_response from httpie.downloads import Downloader from httpie.context import Environment @@ -132,7 +131,7 @@ def program(args, env, log_error): 'flush': env.stdout_isatty or args.stream } try: - if env.is_windows and is_py3 and 'colors' in args.prettify: + if env.is_windows and 'colors' in args.prettify: write_stream_with_colors_win_py3(**write_stream_kwargs) else: write_stream(**write_stream_kwargs) diff --git a/httpie/downloads.py b/httpie/downloads.py index 9f4c761f45..839869caea 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -12,11 +12,11 @@ import threading from time import sleep, time from mailbox import Message +from urllib.parse import urlsplit from httpie.output.streams import RawStream from httpie.models import HTTPResponse from httpie.utils import humanize_bytes -from httpie.compat import urlsplit PARTIAL_CONTENT = 206 diff --git a/httpie/input.py b/httpie/input.py index 1ab34c9b04..53b9924a6e 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -15,10 +15,11 @@ # TODO: Use MultiDict for headers once added to `requests`. # https://github.com/jakubroztocil/httpie/issues/130 +from urllib.parse import urlsplit + from httpie.plugins import plugin_manager from requests.structures import CaseInsensitiveDict -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 @@ -615,17 +616,6 @@ def __call__(self, string): class RequestItemsDict(OrderedDict): """Multi-value dict for URL parameters and form data.""" - if is_pypy and is_py27: - # Manually set keys when initialized with an iterable as PyPy - # doesn't call __setitem__ in such case (pypy3 does). - def __init__(self, *args, **kwargs): - if len(args) == 1 and isinstance(args[0], Iterable): - super(RequestItemsDict, self).__init__(**kwargs) - for k, v in args[0]: - self[k] = v - else: - super(RequestItemsDict, self).__init__(*args, **kwargs) - # noinspection PyMethodOverriding def __setitem__(self, key, value): """ If `key` is assigned more than once, `self[key]` holds a diff --git a/httpie/models.py b/httpie/models.py index ef3594318d..52174859ab 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -1,4 +1,4 @@ -from httpie.compat import urlsplit, str +from urllib.parse import urlsplit class HTTPMessage(object): diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 3483a6d3ce..6f0d5620b1 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -1,7 +1,6 @@ from itertools import chain from functools import partial -from httpie.compat import str from httpie.context import Environment from httpie.models import HTTPRequest, HTTPResponse from httpie.input import (OUT_REQ_BODY, OUT_REQ_HEAD, diff --git a/httpie/sessions.py b/httpie/sessions.py index 56614f2000..0971eac076 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -3,10 +3,10 @@ """ import re import os +from urllib.parse import urlsplit from requests.cookies import RequestsCookieJar, create_cookie -from httpie.compat import urlsplit from httpie.config import BaseConfigDict, DEFAULT_CONFIG_DIR from httpie.plugins import plugin_manager diff --git a/setup.py b/setup.py index bb304288f5..0914da1fe8 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,6 @@ from setuptools.command.test import test as TestCommand import httpie -from httpie.compat import is_py27 class PyTest(TestCommand): @@ -34,9 +33,6 @@ def run_tests(self): 'mock', ] -if is_py27: - tests_require.append('pyOpenSSL') - install_requires = [ 'requests>=2.21.0', @@ -77,7 +73,7 @@ def long_description(): version=httpie.__version__, description=httpie.__doc__.strip(), long_description=long_description(), - url='http://httpie.org/', + url='https://httpie.org/', download_url='https://github.com/jakubroztocil/httpie', author=httpie.__author__, author_email='jakub@roztocil.co', @@ -95,7 +91,6 @@ def long_description(): classifiers=[ 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', @@ -103,6 +98,7 @@ def long_description(): 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Environment :: Console', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', diff --git a/tests/test_downloads.py b/tests/test_downloads.py index e14fcef3b1..ac5dbc1aa2 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -1,12 +1,12 @@ import os import tempfile import time +from urllib.request import urlopen import pytest import mock from requests.structures import CaseInsensitiveDict -from httpie.compat import urlopen from httpie.downloads import ( parse_content_range, filename_from_content_disposition, filename_from_url, get_unique_filename, ContentRangeError, Downloader, diff --git a/tests/test_output.py b/tests/test_output.py index 26cbae96c7..8bdfa572a7 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -1,11 +1,11 @@ import os from tempfile import gettempdir +from urllib.request import urlopen import pytest 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 diff --git a/tests/test_ssl.py b/tests/test_ssl.py index d4227d1e0e..607c47264d 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -5,7 +5,6 @@ import requests.exceptions from httpie import ExitStatus -from httpie.compat import is_pypy from httpie.input import SSL_VERSION_ARG_MAPPING from utils import HTTP_OK, TESTS_ROOT, http diff --git a/tests/utils.py b/tests/utils.py index 23bca713aa..d51f8cb9fe 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -9,7 +9,6 @@ from httpie import ExitStatus, EXIT_STATUS_LABELS from httpie.context import Environment from httpie.core import main -from httpie.compat import bytes, str TESTS_ROOT = os.path.abspath(os.path.dirname(__file__)) diff --git a/tox.ini b/tox.ini index 7bbbd0d588..d44bce8fd0 100644 --- a/tox.ini +++ b/tox.ini @@ -4,16 +4,14 @@ [tox] # pypy3 currently fails because of a Flask issue -envlist = py27, py37, pypy +envlist = py37 [testenv] -# pyOpenSSL only needed for Python 2.7 deps = mock pytest pytest-httpbin>=0.0.6 - pyOpenSSL commands = @@ -23,6 +21,3 @@ commands = --verbose \ --doctest-modules \ {posargs:./httpie ./tests} - -[testenv:py27-osx-builtin] -basepython = /usr/bin/python2.7 From 0f439a5dab7a35c72adb678b214aa3e3edad8d9b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 09:01:27 +0200 Subject: [PATCH 0424/1182] Changelog --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 89ef0ca96c..8429c3a017 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,10 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. +`2.0.0-dev`_ (unreleased) +------------------------- +* Removed Python 2.7 support (`EOL Jan 2020 `_). + `1.0.3`_ (2019-08-26) ------------------------- @@ -384,3 +388,4 @@ This project adheres to `Semantic Versioning `_. .. _1.0.1: https://github.com/jakubroztocil/httpie/compare/1.0.0...1.0.1 .. _1.0.2: https://github.com/jakubroztocil/httpie/compare/1.0.1...1.0.2 .. _1.0.3: https://github.com/jakubroztocil/httpie/compare/1.0.2...1.0.3 +.. _2.0.0-dev: https://github.com/jakubroztocil/httpie/compare/1.0.3...master From 65601f09b219f85bf8134f436c24e3260240d246 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 09:28:57 +0200 Subject: [PATCH 0425/1182] pip3 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 33e85b2517..cd0525d005 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,7 +56,7 @@ install: brew upgrade "$BREW_PYTHON_PACKAGE" fi fi - sudo pip2 install tox + pip3 install tox fi script: - | From a969013bdd23cb94705904cd02d4b2fdfa03f5e7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 09:39:19 +0200 Subject: [PATCH 0426/1182] Disable default max headers limit and add --max-headers (closes #802) --- CHANGELOG.rst | 3 +++ README.rst | 13 +++++++++++++ httpie/cli.py | 11 +++++++++++ httpie/client.py | 41 ++++++++++++++++++++++++++++------------- tests/test_errors.py | 12 ++++++++++++ 5 files changed, 67 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8429c3a017..0618c193b0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,9 @@ This project adheres to `Semantic Versioning `_. `2.0.0-dev`_ (unreleased) ------------------------- * Removed Python 2.7 support (`EOL Jan 2020 `_). +* Removed Python’s default limit of 100 response headers. +* Added ``--max-headers`` to allow setting the max header limit. + `1.0.3`_ (2019-08-26) ------------------------- diff --git a/README.rst b/README.rst index 5f7a6da3ed..91bfc343e8 100644 --- a/README.rst +++ b/README.rst @@ -646,6 +646,19 @@ To send a header with an empty value, use ``Header;``: $ http httpbin.org/headers 'Header;' +Limiting response headers +------------------------- + +The ``--max-headers=n`` options allows you to control the number of headers +HTTPie tries reads before giving up (the default 0, i.e., there’s no limit). + + +.. code-block:: bash + + $ http --max-headers=100 httpbin.org/get + + + Cookies ======= diff --git a/httpie/cli.py b/httpie/cli.py index ac2a8dd78d..96a701feef 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -512,6 +512,17 @@ def __iter__(self): """ ) +network.add_argument( + '--max-headers', + type=int, + default=0, + help=""" + The maximum number of response headers to be read before giving up + (default 0, i.e., no limit). + + """ +) + network.add_argument( '--timeout', type=float, diff --git a/httpie/client.py b/httpie/client.py index 91677ea8fe..e8a8d45cc1 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -1,7 +1,9 @@ import json import sys +import http.client import requests +from decorator import contextmanager from requests.adapters import HTTPAdapter from requests.structures import CaseInsensitiveDict @@ -30,6 +32,18 @@ DEFAULT_UA = 'HTTPie/%s' % __version__ +# noinspection PyProtectedMember +@contextmanager +def max_headers(limit): + # + orig = http.client._MAXHEADERS + http.client._MAXHEADERS = limit or float('Inf') + try: + yield + finally: + http.client._MAXHEADERS = orig + + class HTTPieHTTPAdapter(HTTPAdapter): def __init__(self, ssl_version=None, **kwargs): @@ -64,19 +78,20 @@ def get_response(args, config_dir): requests_session = get_requests_session(ssl_version) requests_session.max_redirects = args.max_redirects - if not args.session and not args.session_read_only: - kwargs = get_requests_kwargs(args) - if args.debug: - dump_request(kwargs) - response = requests_session.request(**kwargs) - else: - response = sessions.get_response( - requests_session=requests_session, - args=args, - config_dir=config_dir, - session_name=args.session or args.session_read_only, - read_only=bool(args.session_read_only), - ) + with max_headers(args.max_headers): + if not args.session and not args.session_read_only: + kwargs = get_requests_kwargs(args) + if args.debug: + dump_request(kwargs) + response = requests_session.request(**kwargs) + else: + response = sessions.get_response( + requests_session=requests_session, + args=args, + config_dir=config_dir, + session_name=args.session or args.session_read_only, + read_only=bool(args.session_read_only), + ) return response diff --git a/tests/test_errors.py b/tests/test_errors.py index 0274e01180..c56e773b7d 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -5,6 +5,8 @@ from httpie import ExitStatus from httpie.core import main +from utils import http, HTTP_OK + error_msg = None @@ -47,3 +49,13 @@ def error(msg, *args, **kwargs): ret = main(['--ignore-stdin', 'www.google.com'], custom_log_error=error) assert ret == ExitStatus.ERROR_TIMEOUT assert error_msg == 'Request timed out (30s).' + + +def test_max_headers_limit(httpbin_both): + with raises(ConnectionError) as e: + http('--max-headers=1', httpbin_both + '/get') + assert 'got more than 1 headers' in str(e.value) + + +def test_max_headers_no_limit(httpbin_both): + assert HTTP_OK in http('--max-headers=0', httpbin_both + '/get') From e93de1fbe7cc811735137fab037a52d6761c7f9e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 09:46:17 +0200 Subject: [PATCH 0427/1182] Make `test_binary_suppresses_*` deterministic --- tests/test_binary.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_binary.py b/tests/test_binary.py index 2adc2500be..3cb35b9d66 100644 --- a/tests/test_binary.py +++ b/tests/test_binary.py @@ -34,12 +34,12 @@ def test_binary_file_form(self, httpbin): class TestBinaryResponseData: def test_binary_suppresses_when_terminal(self, httpbin): - r = http('GET', httpbin + '/bytes/1024') + r = http('GET', httpbin + '/bytes/1024?seed=1') assert BINARY_SUPPRESSED_NOTICE.decode() in r def test_binary_suppresses_when_not_terminal_but_pretty(self, httpbin): env = MockEnvironment(stdin_isatty=True, stdout_isatty=False) - r = http('--pretty=all', 'GET', httpbin + '/bytes/1024', env=env) + r = http('--pretty=all', 'GET', httpbin + '/bytes/1024?seed=1', env=env) assert BINARY_SUPPRESSED_NOTICE.decode() in r def test_binary_included_and_correct_when_suitable(self, httpbin): From 05fc9c480ab2f7cd9f205874b7bf0292921d2a5e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 09:57:00 +0200 Subject: [PATCH 0428/1182] Remove the default 30-second connection timeout limit --- CHANGELOG.rst | 1 + README.rst | 4 ++-- httpie/cli.py | 10 +++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0618c193b0..32e175142d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,7 @@ This project adheres to `Semantic Versioning `_. `2.0.0-dev`_ (unreleased) ------------------------- * Removed Python 2.7 support (`EOL Jan 2020 `_). +* Removed the default 30-second connection ``--timeout`` limit. * Removed Python’s default limit of 100 response headers. * Added ``--max-headers`` to allow setting the max header limit. diff --git a/README.rst b/README.rst index 91bfc343e8..32c887e716 100644 --- a/README.rst +++ b/README.rst @@ -1576,8 +1576,8 @@ 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 might be good to override the default ``30`` second ``--timeout`` to -something that suits you. +Also, it might be good to set a connection ``--timeout`` limit to prevent +your program from hanging if the server never responds. diff --git a/httpie/cli.py b/httpie/cli.py index 96a701feef..87035120af 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -526,11 +526,15 @@ def __iter__(self): network.add_argument( '--timeout', type=float, - default=30, + default=0, metavar='SECONDS', help=""" - The connection timeout of the request in seconds. The default value is - 30 seconds. + The connection timeout of the request in seconds. + The default value is 0, i.e., there is no timeout limit. + This is not a time limit on the entire response download; + rather, an error is reported if the server has not issued a response for + timeout seconds (more precisely, if no bytes have been received on + the underlying socket for timeout seconds). """ ) From 82081c889b4ce6bcdf5701a05da6c69fd3faa000 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 10:04:49 +0200 Subject: [PATCH 0429/1182] Fix ``--timeout=0`` --- httpie/client.py | 2 +- tests/test_errors.py | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index e8a8d45cc1..a5ae071139 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -180,7 +180,7 @@ def get_requests_kwargs(args, base_headers=None): 'false': False, }.get(args.verify.lower(), args.verify), 'cert': cert, - 'timeout': args.timeout, + 'timeout': args.timeout or None, 'auth': args.auth, 'proxies': {p.key: p.value for p in args.proxy}, 'files': args.files, diff --git a/tests/test_errors.py b/tests/test_errors.py index c56e773b7d..56e61c39fb 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -37,20 +37,6 @@ def test_error_traceback(get_response): main(['--ignore-stdin', '--traceback', 'www.google.com']) -@mock.patch('httpie.core.get_response') -def test_timeout(get_response): - def error(msg, *args, **kwargs): - global error_msg - error_msg = msg % args - - exc = Timeout('Request timed out') - exc.request = Request(method='GET', url='http://www.google.com') - get_response.side_effect = exc - ret = main(['--ignore-stdin', 'www.google.com'], custom_log_error=error) - assert ret == ExitStatus.ERROR_TIMEOUT - assert error_msg == 'Request timed out (30s).' - - def test_max_headers_limit(httpbin_both): with raises(ConnectionError) as e: http('--max-headers=1', httpbin_both + '/get') From bb4f101c1ec2959c9415e02999abea48d05c1d2e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 10:09:56 +0200 Subject: [PATCH 0430/1182] pep8 --- httpie/cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 87035120af..43b0047727 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -529,12 +529,12 @@ def __iter__(self): default=0, metavar='SECONDS', help=""" - The connection timeout of the request in seconds. + The connection timeout of the request in seconds. The default value is 0, i.e., there is no timeout limit. This is not a time limit on the entire response download; - rather, an error is reported if the server has not issued a response for + rather, an error is reported if the server has not issued a response for timeout seconds (more precisely, if no bytes have been received on - the underlying socket for timeout seconds). + the underlying socket for timeout seconds). """ ) From 2d1649484541695c95c643abb66a24d85177cbb1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 10:16:39 +0200 Subject: [PATCH 0431/1182] README --- README.rst | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/README.rst b/README.rst index 32c887e716..f11e9d4f87 100644 --- a/README.rst +++ b/README.rst @@ -9,24 +9,17 @@ colorized output. HTTPie can be used for testing, debugging, and generally interacting with HTTP servers. -.. class:: no-web - - .. image:: https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.gif - :alt: HTTPie in action - :width: 100% - :align: center - +.. class:: no-web no-pdf - .. image:: https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.png - :alt: HTTPie compared to cURL - :width: 100% - :align: center + |pypi| |unix_build| |coverage| |downloads| |gitter| .. class:: no-web no-pdf -|pypi| |unix_build| |coverage| |downloads| |gitter| - + .. image:: https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.gif + :alt: HTTPie in action + :width: 100% + :align: center .. contents:: @@ -38,6 +31,7 @@ generally interacting with HTTP servers. Main features ============= + * Expressive and intuitive syntax * Formatted and colorized terminal output * Built-in JSON support @@ -53,6 +47,14 @@ Main features * Test coverage +.. class:: no-web + + .. image:: https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.png + :alt: HTTPie compared to cURL + :width: 100% + :align: center + + Installation ============ From 46c4f4e225ee30bb3fd473dc3c971ae458b5320e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 10:20:45 +0200 Subject: [PATCH 0432/1182] README --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f11e9d4f87..892ceeeb3e 100644 --- a/README.rst +++ b/README.rst @@ -652,7 +652,7 @@ Limiting response headers ------------------------- The ``--max-headers=n`` options allows you to control the number of headers -HTTPie tries reads before giving up (the default 0, i.e., there’s no limit). +HTTPie reads before giving up (the default 0, i.e., there’s no limit). .. code-block:: bash From 2deaccf2d1a52eb3c59e0bed589a5a447b340550 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 10:21:13 +0200 Subject: [PATCH 0433/1182] README --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 892ceeeb3e..15972475bf 100644 --- a/README.rst +++ b/README.rst @@ -652,7 +652,7 @@ Limiting response headers ------------------------- The ``--max-headers=n`` options allows you to control the number of headers -HTTPie reads before giving up (the default 0, i.e., there’s no limit). +HTTPie reads before giving up (the default ``0``, i.e., there’s no limit). .. code-block:: bash From 5ec954c03dad287645d52cbb52d16085d0f65eeb Mon Sep 17 00:00:00 2001 From: Aleksandr Vinokurov Date: Thu, 29 Aug 2019 10:44:59 +0200 Subject: [PATCH 0434/1182] Add compressed requests (#739) * Add optional compression of the request's content This option allows compression of the files and/or data during uploading, Examples: http --form --compress POST https://localhost/upload csv@./very-big.csv http -x -x POST https://localhost/upload foo=bar cat /var/log/system.log | http -x POST https://localhost/upload Signed-off-by: Aleksandr Vinokurov * Add tests for compression Signed-off-by: Aleksandr Vinokurov * Fix code style issues Signed-off-by: Aleksandr Vinokurov * Fix zlib compression api missuse in Python3 Signed-off-by: Aleksandr Vinokurov * Remove tracing from compression logic Signed-off-by: Aleksandr Vinokurov --- AUTHORS.rst | 2 ++ httpie/cli.py | 23 +++++++++++++++++++++++ httpie/client.py | 31 +++++++++++++++++++++++++++++-- tests/test_httpie.py | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 2 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index 22bbfa8178..9845e1f3d9 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -36,5 +36,7 @@ Patches and ideas * `Dennis Brakhane `_ * `Matt Layman `_ * `Edward Yang `_ +* `Aleksandr Vinokurov `_ * `Jeff Byrnes `_ + diff --git a/httpie/cli.py b/httpie/cli.py index 43b0047727..2a2decaf28 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -185,6 +185,29 @@ def _split_lines(self, text, width): ) +####################################################################### +# Content processing. +####################################################################### + +content_processing = parser.add_argument_group( + title='Content Processing Options', + description=None +) + +content_processing.add_argument( + '--compress', '-x', + action='count', + help=""" + Content compressed (encoded) with Deflate algorithm. + The Content-Encoding header is set to deflate. + + Compression is skipped if it appears that compression ratio is + negative. Compression can be forced by repeating the argument. + + """ +) + + ####################################################################### # Output processing ####################################################################### diff --git a/httpie/client.py b/httpie/client.py index a5ae071139..999a072279 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -13,6 +13,8 @@ from httpie.plugins import plugin_manager from httpie.utils import repr_dict_nice +import zlib + try: # https://urllib3.readthedocs.io/en/latest/security.html # noinspection PyPackageRequirements @@ -55,12 +57,37 @@ def init_poolmanager(self, *args, **kwargs): super(HTTPieHTTPAdapter, self).init_poolmanager(*args, **kwargs) -def get_requests_session(ssl_version): +class ContentCompressionHttpAdapter(HTTPAdapter): + + def __init__(self, compress, **kwargs): + self.compress = compress + super(ContentCompressionHttpAdapter, self).__init__(**kwargs) + + def send(self, request, **kwargs): + if request.body and self.compress > 0: + deflater = zlib.compressobj() + if isinstance(request.body, bytes): + deflated_data = deflater.compress(request.body) + else: + deflated_data = deflater.compress(request.body.encode()) + deflated_data += deflater.flush() + if len(deflated_data) < len(request.body) or self.compress > 1: + request.body = deflated_data + request.headers['Content-Encoding'] = 'deflate' + request.headers['Content-Length'] = str(len(deflated_data)) + return super(ContentCompressionHttpAdapter, self).send(request, **kwargs) + + +def get_requests_session(ssl_version, compress): requests_session = requests.Session() requests_session.mount( 'https://', HTTPieHTTPAdapter(ssl_version=ssl_version) ) + if compress: + adapter = ContentCompressionHttpAdapter(compress) + for prefix in ['http://', 'https://']: + requests_session.mount(prefix, adapter) for cls in plugin_manager.get_transport_plugins(): transport_plugin = cls() requests_session.mount(prefix=transport_plugin.prefix, @@ -75,7 +102,7 @@ def get_response(args, config_dir): if args.ssl_version: ssl_version = SSL_VERSION_ARG_MAPPING[args.ssl_version] - requests_session = get_requests_session(ssl_version) + requests_session = get_requests_session(ssl_version, args.compress) requests_session.max_redirects = args.max_redirects with max_headers(args.max_headers): diff --git a/tests/test_httpie.py b/tests/test_httpie.py index c6bf00194e..7123d19cb4 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -49,12 +49,28 @@ def test_POST_JSON_data(httpbin_both): assert r.json['json']['foo'] == 'bar' +def test_POST_JSON_data_compressed(httpbin_both): + r = http('--compress', '--compress', 'POST', httpbin_both + '/post', 'foo=bar') + assert HTTP_OK in r + assert r.json['headers']['Content-Encoding'] == 'deflate' + assert r.json['data'].startswith('data:application/octet-stream;') + assert r.json['json'] is None + + def test_POST_form(httpbin_both): r = http('--form', 'POST', httpbin_both + '/post', 'foo=bar') assert HTTP_OK in r assert '"foo": "bar"' in r +def test_POST_form_compressed(httpbin_both): + r = http('--form', '--compress', '--compress', 'POST', httpbin_both + '/post', 'foo=bar') + assert HTTP_OK in r + assert r.json['headers']['Content-Encoding'] == 'deflate' + assert r.json['data'] == "" + assert '"foo": "bar"' not in r + + def test_POST_form_multiple_values(httpbin_both): r = http('--form', 'POST', httpbin_both + '/post', 'foo=bar', 'foo=baz') assert HTTP_OK in r @@ -69,6 +85,31 @@ def test_POST_stdin(httpbin_both): assert FILE_CONTENT in r +def test_POST_stdin_compressed(httpbin_both): + with open(FILE_PATH) as f: + env = MockEnvironment(stdin=f, stdin_isatty=False) + r = http('--form', '--compress', '--compress', 'POST', httpbin_both + '/post', env=env) + assert HTTP_OK in r + assert r.json['headers']['Content-Encoding'] == 'deflate' + assert r.json['data'] == "" + assert FILE_CONTENT not in r + + +def test_POST_file(httpbin_both): + r = http('--form', 'POST', httpbin_both + '/post', 'file@' + FILE_PATH) + assert HTTP_OK in r + assert FILE_CONTENT in r + + +def test_POST_file_compressed(httpbin_both): + r = http('--form', '--compress', '--compress', 'POST', httpbin_both + '/post', 'file@' + FILE_PATH) + assert HTTP_OK in r + assert r.json['headers']['Content-Encoding'] == 'deflate' + assert r.json['headers']['Content-Type'].startswith('multipart/form-data; boundary=') + assert r.json['files'] == {} + assert FILE_CONTENT not in r + + def test_headers(httpbin_both): r = http('GET', httpbin_both + '/headers', 'Foo:bar') assert HTTP_OK in r From a4d8f1f22e53019d8efbc2ed31eb58eb9222e1fa Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 11:46:08 +0200 Subject: [PATCH 0435/1182] Refactor `--compress` tests --- httpie/client.py | 2 +- tests/test_compress.py | 110 +++++++++++++++++++++++++++++++++++++++++ tests/test_httpie.py | 35 ------------- tests/utils.py | 2 +- 4 files changed, 112 insertions(+), 37 deletions(-) create mode 100644 tests/test_compress.py diff --git a/httpie/client.py b/httpie/client.py index 999a072279..899535b4e6 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -3,7 +3,7 @@ import http.client import requests -from decorator import contextmanager +from contextlib import contextmanager from requests.adapters import HTTPAdapter from requests.structures import CaseInsensitiveDict diff --git a/tests/test_compress.py b/tests/test_compress.py new file mode 100644 index 0000000000..089ea619ef --- /dev/null +++ b/tests/test_compress.py @@ -0,0 +1,110 @@ +""" +We test against httpbin which doesn't return the request data in a +consistent way: + +1. Non-form requests: the `data` field contains base64 encoded version of +our zlib-encoded request data. + +2. Form requests: `form` contains a messed up version of the data. + +""" +import base64 +import zlib + +from fixtures import FILE_PATH, FILE_CONTENT +from utils import http, HTTP_OK, MockEnvironment + + +def assert_decompressed_equal(base64_compressed_data, expected_str): + compressed_data = base64.b64decode( + base64_compressed_data.split(',', 1)[1]) + data = zlib.decompress(compressed_data) + actual_str = data.decode() + + # FIXME: contains a trailing linebreak with an uploaded file + actual_str = actual_str.rstrip() + + assert actual_str == expected_str + + +def test_compress_skip_negative_ratio(httpbin_both): + r = http( + '--compress', + httpbin_both + '/post', + 'foo=bar', + ) + assert HTTP_OK in r + assert 'Content-Encoding' not in r.json['headers'] + assert r.json['json'] == {'foo': 'bar'} + + +def test_compress_force_with_negative_ratio(httpbin_both): + r = http( + '--compress', + '--compress', + httpbin_both + '/post', + 'foo=bar', + ) + assert HTTP_OK in r + assert r.json['headers']['Content-Encoding'] == 'deflate' + assert_decompressed_equal(r.json['data'], '{"foo": "bar"}') + + +def test_compress_json(httpbin_both): + r = http( + '--compress', + '--compress', + httpbin_both + '/post', + 'foo=bar', + ) + assert HTTP_OK in r + assert r.json['headers']['Content-Encoding'] == 'deflate' + assert_decompressed_equal(r.json['data'], '{"foo": "bar"}') + assert r.json['json'] is None + + +def test_compress_form(httpbin_both): + r = http( + '--form', + '--compress', + '--compress', + httpbin_both + '/post', + 'foo=bar', + ) + assert HTTP_OK in r + assert r.json['headers']['Content-Encoding'] == 'deflate' + assert r.json['data'] == "" + assert '"foo": "bar"' not in r + + +def test_compress_stdin(httpbin_both): + with open(FILE_PATH) as f: + env = MockEnvironment(stdin=f, stdin_isatty=False) + r = http( + '--compress', + '--compress', + 'PATCH', + httpbin_both + '/patch', + env=env, + ) + assert HTTP_OK in r + assert r.json['headers']['Content-Encoding'] == 'deflate' + assert_decompressed_equal(r.json['data'], FILE_CONTENT.strip()) + assert not r.json['json'] + + +def test_compress_file(httpbin_both): + r = http( + '--form', + '--compress', + '--compress', + 'PUT', + httpbin_both + '/put', + 'file@' + FILE_PATH, + ) + assert HTTP_OK in r + assert r.json['headers']['Content-Encoding'] == 'deflate' + assert r.json['headers']['Content-Type'].startswith( + 'multipart/form-data; boundary=') + assert r.json['files'] == {} + assert FILE_CONTENT not in r diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 7123d19cb4..745e18e23d 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -49,28 +49,12 @@ def test_POST_JSON_data(httpbin_both): assert r.json['json']['foo'] == 'bar' -def test_POST_JSON_data_compressed(httpbin_both): - r = http('--compress', '--compress', 'POST', httpbin_both + '/post', 'foo=bar') - assert HTTP_OK in r - assert r.json['headers']['Content-Encoding'] == 'deflate' - assert r.json['data'].startswith('data:application/octet-stream;') - assert r.json['json'] is None - - def test_POST_form(httpbin_both): r = http('--form', 'POST', httpbin_both + '/post', 'foo=bar') assert HTTP_OK in r assert '"foo": "bar"' in r -def test_POST_form_compressed(httpbin_both): - r = http('--form', '--compress', '--compress', 'POST', httpbin_both + '/post', 'foo=bar') - assert HTTP_OK in r - assert r.json['headers']['Content-Encoding'] == 'deflate' - assert r.json['data'] == "" - assert '"foo": "bar"' not in r - - def test_POST_form_multiple_values(httpbin_both): r = http('--form', 'POST', httpbin_both + '/post', 'foo=bar', 'foo=baz') assert HTTP_OK in r @@ -85,31 +69,12 @@ def test_POST_stdin(httpbin_both): assert FILE_CONTENT in r -def test_POST_stdin_compressed(httpbin_both): - with open(FILE_PATH) as f: - env = MockEnvironment(stdin=f, stdin_isatty=False) - r = http('--form', '--compress', '--compress', 'POST', httpbin_both + '/post', env=env) - assert HTTP_OK in r - assert r.json['headers']['Content-Encoding'] == 'deflate' - assert r.json['data'] == "" - assert FILE_CONTENT not in r - - def test_POST_file(httpbin_both): r = http('--form', 'POST', httpbin_both + '/post', 'file@' + FILE_PATH) assert HTTP_OK in r assert FILE_CONTENT in r -def test_POST_file_compressed(httpbin_both): - r = http('--form', '--compress', '--compress', 'POST', httpbin_both + '/post', 'file@' + FILE_PATH) - assert HTTP_OK in r - assert r.json['headers']['Content-Encoding'] == 'deflate' - assert r.json['headers']['Content-Type'].startswith('multipart/form-data; boundary=') - assert r.json['files'] == {} - assert FILE_CONTENT not in r - - def test_headers(httpbin_both): r = http('GET', httpbin_both + '/headers', 'Foo:bar') assert HTTP_OK in r diff --git a/tests/utils.py b/tests/utils.py index d51f8cb9fe..19939ca39d 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -108,7 +108,7 @@ class StrCLIResponse(str, BaseCLIResponse): def json(self): """ Return deserialized JSON body, if one included in the output - and is parseable. + and is parsable. """ if not hasattr(self, '_json'): From 2da2cec83c47b82e5d108fe8b2a5b1d1dbd3a79f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 11:51:49 +0200 Subject: [PATCH 0436/1182] CHANGELOG --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 32e175142d..0777e3ae7b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,7 @@ This project adheres to `Semantic Versioning `_. * Removed the default 30-second connection ``--timeout`` limit. * Removed Python’s default limit of 100 response headers. * Added ``--max-headers`` to allow setting the max header limit. +* Added ``--compress``. `1.0.3`_ (2019-08-26) From 8512a630f9e6ef4a9cf4d329475a0c2717c04f0d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 12:00:41 +0200 Subject: [PATCH 0437/1182] Use exact text from the three-clause BSD license (close #740) As per https://opensource.org/licenses/BSD-3-Clause --- LICENSE | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/LICENSE b/LICENSE index c145597541..91f8b9510a 100644 --- a/LICENSE +++ b/LICENSE @@ -10,14 +10,14 @@ modification, are permitted provided that the following conditions are met: notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of The author nor the names of its contributors may - be used to endorse or promote products derived from this software + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE FOR +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON From 8e04a24b90475608d65ad13ce66d59a41ed8b457 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 13:08:02 +0200 Subject: [PATCH 0438/1182] Reintroduce `$ https` command alias with `https://` as default scheme Close #608 --- .travis.yml | 3 --- CHANGELOG.rst | 1 + README.rst | 26 +++++++++++++++++++++----- httpie/core.py | 9 +++++++-- httpie/input.py | 14 +++++++++----- setup.py | 6 +----- tests/test_cli.py | 6 +++++- tests/test_errors.py | 4 ++-- tests/utils.py | 7 ++++--- 9 files changed, 50 insertions(+), 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index cd0525d005..3457e4059e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,9 +7,6 @@ env: global: - NEWEST_PYTHON=3.7 python: - # Python 3.4 fails installing packages - # - # - 3.4 - 3.5 - 3.6 # - 3.7 # is done in the matrix below as described in travis-ci/travis-ci#9069 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0777e3ae7b..00a2b08a3c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,6 +13,7 @@ This project adheres to `Semantic Versioning `_. * Removed Python’s default limit of 100 response headers. * Added ``--max-headers`` to allow setting the max header limit. * Added ``--compress``. +* Added ``https`` alias command with ``https://`` as the default scheme. `1.0.3`_ (2019-08-26) diff --git a/README.rst b/README.rst index 15972475bf..0cff7bb6cb 100644 --- a/README.rst +++ b/README.rst @@ -126,7 +126,7 @@ and always provides the latest version) is to use `pip`_: Python version -------------- -Starting with version 2.0.0 (currently under development) Python 3.x is required. +Starting with version 2.0.0 (currently under development) Python 3.5+ is required. Unstable version @@ -351,16 +351,32 @@ If the port is omitted, then port 80 is assumed. Host: localhost -Custom default scheme +Other default schemes --------------------- -You can use the ``--default-scheme `` option to create -shortcuts for other protocols than HTTP: +When HTTPie is invoked as ``https`` then the default scheme is ``https://`` +(``$ https example.org`` will make a request to ``https://example.org``). + +You can also use the ``--default-scheme `` option to create +shortcuts for other protocols than HTTP (possibly supported via plugins). +Example for the `httpie-unixsocket `_ plugin: + +.. code-block:: bash + + # Before + $ http http+unix://%2Fvar%2Frun%2Fdocker.sock/info + .. code-block:: bash - $ alias https='http --default-scheme=https' + # Create an alias + $ alias http-unix='http --default-scheme="http+unix"' + + +.. code-block:: bash + # Now the scheme can be omitted + $ http-unix %2Fvar%2Frun%2Fdocker.sock/info Request items ============= diff --git a/httpie/core.py b/httpie/core.py index fb3d9662dc..f39635c4f9 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -168,7 +168,7 @@ def program(args, env, log_error): args.output_file.close() -def main(args=sys.argv[1:], env=Environment(), custom_log_error=None): +def main(args=sys.argv, env=Environment(), custom_log_error=None): """ The main function. @@ -179,6 +179,7 @@ def main(args=sys.argv[1:], env=Environment(), custom_log_error=None): """ args = decode_args(args, env.stdin_encoding) + program_name, *args = args plugin_manager.load_installed_plugins() def log_error(msg, *args, **kwargs): @@ -206,7 +207,11 @@ def log_error(msg, *args, **kwargs): exit_status = ExitStatus.SUCCESS try: - parsed_args = parser.parse_args(args=args, env=env) + parsed_args = parser.parse_args( + args=args, + program_name=program_name, + env=env, + ) except KeyboardInterrupt: env.stderr.write('\n') if include_traceback: diff --git a/httpie/input.py b/httpie/input.py index 53b9924a6e..2b179daf22 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -132,13 +132,14 @@ class HTTPieArgumentParser(ArgumentParser): def __init__(self, *args, **kwargs): kwargs['add_help'] = False super(HTTPieArgumentParser, self).__init__(*args, **kwargs) + self.env = None + self.args = None # noinspection PyMethodOverriding - def parse_args(self, env, args=None, namespace=None): - + def parse_args(self, env, program_name='http', args=None, namespace=None): self.env = env - self.args, no_options = super(HTTPieArgumentParser, self)\ - .parse_known_args(args, namespace) + self.args, no_options = super( + HTTPieArgumentParser, self).parse_known_args(args, namespace) if self.args.debug: self.args.traceback = True @@ -154,7 +155,10 @@ def parse_args(self, env, args=None, namespace=None): if not self.args.ignore_stdin and not env.stdin_isatty: self._body_from_file(self.env.stdin) if not URL_SCHEME_RE.match(self.args.url): - scheme = self.args.default_scheme + "://" + if os.path.basename(program_name) == 'https': + scheme = 'https://' + else: + scheme = self.args.default_scheme + "://" # See if we're using curl style shorthand for localhost (:3000/foo) shorthand = re.match(r'^:(?!:)(\d*)(/?.*)$', self.args.url) diff --git a/setup.py b/setup.py index 0914da1fe8..eb4649ad41 100644 --- a/setup.py +++ b/setup.py @@ -82,6 +82,7 @@ def long_description(): entry_points={ 'console_scripts': [ 'http = httpie.__main__:main', + 'https = httpie.__main__:main', ], }, extras_require=extras_require, @@ -91,11 +92,6 @@ def long_description(): classifiers=[ 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', - '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', 'Programming Language :: Python :: 3.7', diff --git a/tests/test_cli.py b/tests/test_cli.py index 5daa3bb7af..d4606f527a 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -342,6 +342,10 @@ def test_invalid_scheme_via_via_default_scheme(self): with pytest.raises(InvalidSchema): http('bah', '--default=scheme=foo+bar-BAZ.123') - def test_default_scheme(self, httpbin_secure): + def test_default_scheme_option(self, httpbin_secure): url = '{0}:{1}'.format(httpbin_secure.host, httpbin_secure.port) assert HTTP_OK in http(url, '--default-scheme=https') + + def test_scheme_when_invoked_as_https(self, httpbin_secure): + url = '{0}:{1}'.format(httpbin_secure.host, httpbin_secure.port) + assert HTTP_OK in http(url, program_name='https') diff --git a/tests/test_errors.py b/tests/test_errors.py index 56e61c39fb..596e2f5e49 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -20,7 +20,7 @@ def error(msg, *args, **kwargs): exc = ConnectionError('Connection aborted') exc.request = Request(method='GET', url='http://www.google.com') get_response.side_effect = exc - ret = main(['--ignore-stdin', 'www.google.com'], custom_log_error=error) + ret = main(['http', '--ignore-stdin', 'www.google.com'], custom_log_error=error) assert ret == ExitStatus.ERROR assert error_msg == ( 'ConnectionError: ' @@ -34,7 +34,7 @@ def test_error_traceback(get_response): exc.request = Request(method='GET', url='http://www.google.com') get_response.side_effect = exc with raises(ConnectionError): - main(['--ignore-stdin', '--traceback', 'www.google.com']) + main(['http', '--ignore-stdin', '--traceback', 'www.google.com']) def test_max_headers_limit(httpbin_both): diff --git a/tests/utils.py b/tests/utils.py index 19939ca39d..aa16f9061c 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -140,7 +140,7 @@ class ExitStatusError(Exception): pass -def http(*args, **kwargs): +def http(*args, program_name='http', **kwargs): # noinspection PyUnresolvedReferences """ Run HTTPie and capture stderr/out and exit status. @@ -197,7 +197,8 @@ def http(*args, **kwargs): add_to_args.append('--traceback') if not any('--timeout' in arg for arg in args_with_config_defaults): add_to_args.append('--timeout=3') - args = add_to_args + args + + complete_args = [program_name, *add_to_args, *args] def dump_stderr(): stderr.seek(0) @@ -205,7 +206,7 @@ def dump_stderr(): try: try: - exit_status = main(args=args, **kwargs) + exit_status = main(args=complete_args, **kwargs) if '--download' in args: # Let the progress reporter thread finish. time.sleep(.5) From ced9212c1f0e537bd3baf0471547f5109e87ed71 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 13:39:42 +0200 Subject: [PATCH 0439/1182] Allow stdin to be a closed fd #791 --- .travis.yml | 1 - CHANGELOG.rst | 1 + README.rst | 2 +- httpie/context.py | 5 ++++- httpie/input.py | 1 + tests/test_cli.py | 6 +++++- 6 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3457e4059e..ae55a67263 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,6 @@ env: global: - NEWEST_PYTHON=3.7 python: - - 3.5 - 3.6 # - 3.7 # is done in the matrix below as described in travis-ci/travis-ci#9069 # pypy3 currently fails because of a Flask issue diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 00a2b08a3c..222ec90c98 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,7 @@ This project adheres to `Semantic Versioning `_. * Added ``--max-headers`` to allow setting the max header limit. * Added ``--compress``. * Added ``https`` alias command with ``https://`` as the default scheme. +* Fixed an exception when ``stdin`` was a closed fd. `1.0.3`_ (2019-08-26) diff --git a/README.rst b/README.rst index 0cff7bb6cb..bb72de7b11 100644 --- a/README.rst +++ b/README.rst @@ -126,7 +126,7 @@ and always provides the latest version) is to use `pip`_: Python version -------------- -Starting with version 2.0.0 (currently under development) Python 3.5+ is required. +Starting with version 2.0.0 (currently under development) Python 3.6+ is required. Unstable version diff --git a/httpie/context.py b/httpie/context.py index 3873024de2..621fdfa565 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -1,4 +1,7 @@ import sys +from typing import Union, IO, Optional + + try: import curses except ImportError: @@ -22,7 +25,7 @@ class Environment(object): """ is_windows = is_windows config_dir = DEFAULT_CONFIG_DIR - stdin = sys.stdin + stdin: Optional[IO] = sys.stdin # `None` when closed fd (#791) stdin_isatty = stdin.isatty() if stdin else False stdin_encoding = None stdout = sys.stdout diff --git a/httpie/input.py b/httpie/input.py index a304ee85a8..102612f3cb 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -134,6 +134,7 @@ def __init__(self, *args, **kwargs): super(HTTPieArgumentParser, self).__init__(*args, **kwargs) self.env = None self.args = None + self.has_stdin_data = False # noinspection PyMethodOverriding def parse_args(self, env, program_name='http', args=None, namespace=None): diff --git a/tests/test_cli.py b/tests/test_cli.py index d4606f527a..8f571f0f44 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -310,7 +310,7 @@ def test_invalid_no_options(self, httpbin): assert 'GET /get HTTP/1.1' not in r -class TestIgnoreStdin: +class TestStdin: def test_ignore_stdin(self, httpbin): with open(FILE_PATH) as f: @@ -327,6 +327,10 @@ def test_ignore_stdin_cannot_prompt_password(self, httpbin): assert r.exit_status == ExitStatus.ERROR assert 'because --ignore-stdin' in r.stderr + def test_stdin_closed(self, httpbin): + r = http(httpbin + '/get', env=MockEnvironment(stdin=None)) + assert HTTP_OK in r + class TestSchemes: From 9bd8b4e8f75eb475073358856bb9748dee2bce21 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 29 Aug 2019 14:05:00 +0200 Subject: [PATCH 0440/1182] Don't fail if config dir not writeable (close #738) --- CHANGELOG.rst | 5 +++-- httpie/config.py | 28 ++++++++-------------------- httpie/context.py | 2 +- tests/test_config.py | 26 +++++++++----------------- tests/utils.py | 6 ++++-- 5 files changed, 25 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 222ec90c98..126f412845 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,11 +14,12 @@ This project adheres to `Semantic Versioning `_. * Added ``--max-headers`` to allow setting the max header limit. * Added ``--compress``. * Added ``https`` alias command with ``https://`` as the default scheme. -* Fixed an exception when ``stdin`` was a closed fd. +* Fixed an error when ``stdin`` was a closed fd. +* Fixed an error when the config directory was not writeable. `1.0.3`_ (2019-08-26) -------------------------- +--------------------- * Fixed CVE-2019-10751 — the way the output filename is generated for ``--download`` requests without ``--output`` resulting in a redirect has diff --git a/httpie/config.py b/httpie/config.py index 06ce586b91..57a4f7312a 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -55,7 +55,7 @@ def load(self): if e.errno != errno.ENOENT: raise - def save(self): + def save(self, fail_silently=False): self['__meta__'] = { 'httpie': __version__ } @@ -65,9 +65,13 @@ def save(self): if self.about: self['__meta__']['about'] = self.about - with open(self.path, 'w') as f: - json.dump(self, f, indent=4, sort_keys=True, ensure_ascii=True) - f.write('\n') + try: + with open(self.path, 'w') as f: + json.dump(self, f, indent=4, sort_keys=True, ensure_ascii=True) + f.write('\n') + except IOError: + if not fail_silently: + raise def delete(self): try: @@ -92,21 +96,5 @@ def __init__(self, directory=DEFAULT_CONFIG_DIR): self.update(self.DEFAULTS) self.directory = directory - def load(self): - super(Config, self).load() - self._migrate_implicit_content_type() - def _get_path(self): return os.path.join(self.directory, self.name + '.json') - - def _migrate_implicit_content_type(self): - """Migrate the removed implicit_content_type config option""" - try: - implicit_content_type = self.pop('implicit_content_type') - except KeyError: - self.save() - else: - if implicit_content_type == 'form': - self['default_options'].insert(0, '--form') - self.save() - self.load() diff --git a/httpie/context.py b/httpie/context.py index 621fdfa565..2f2453783f 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -82,7 +82,7 @@ def config(self): if not hasattr(self, '_config'): self._config = Config(directory=self.config_dir) if self._config.is_new(): - self._config.save() + self._config.save(fail_silently=True) else: self._config.load() return self._config diff --git a/tests/test_config.py b/tests/test_config.py index d31ae1f38f..63bb450435 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,5 +1,5 @@ from httpie import __version__ -from utils import MockEnvironment, http +from utils import MockEnvironment, http, HTTP_OK from httpie.context import Environment @@ -11,6 +11,14 @@ def test_default_options(httpbin): assert r.json['form'] == {"foo": "bar"} +def test_config_dir_not_writeable(httpbin): + r = http(httpbin + '/get', env=MockEnvironment( + config_dir='/', + create_temp_config_dir=False, + )) + assert HTTP_OK in r + + def test_default_options_overwrite(httpbin): env = MockEnvironment() env.config['default_options'] = ['--form'] @@ -19,22 +27,6 @@ def test_default_options_overwrite(httpbin): assert r.json['json'] == {"foo": "bar"} -def test_migrate_implicit_content_type(): - config = MockEnvironment().config - - config['implicit_content_type'] = 'json' - config.save() - config.load() - assert 'implicit_content_type' not in config - assert not config['default_options'] - - config['implicit_content_type'] = 'form' - config.save() - 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__ diff --git a/tests/utils.py b/tests/utils.py index aa16f9061c..0412791bd1 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -39,7 +39,8 @@ class MockEnvironment(Environment): stdout_isatty = True is_windows = False - def __init__(self, **kwargs): + def __init__(self, create_temp_config_dir=True, **kwargs): + self.create_temp_config_dir = create_temp_config_dir if 'stdout' not in kwargs: kwargs['stdout'] = tempfile.TemporaryFile( mode='w+b', @@ -55,7 +56,8 @@ def __init__(self, **kwargs): @property def config(self): - if not self.config_dir.startswith(tempfile.gettempdir()): + if (self.create_temp_config_dir + and not self.config_dir.startswith(tempfile.gettempdir())): self.config_dir = mk_config_dir() self._delete_config_dir = True return super(MockEnvironment, self).config From 25798274189de5767a4508fb47414ac93b5a5bc9 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 30 Aug 2019 09:56:50 +0200 Subject: [PATCH 0441/1182] Use set literal --- httpie/sessions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/sessions.py b/httpie/sessions.py index 0971eac076..0ae1dc2772 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -172,5 +172,5 @@ def auth(self): @auth.setter def auth(self, auth): - assert set(['type', 'raw_auth']) == set(auth.keys()) + assert {'type', 'raw_auth'} == auth.keys() self['auth'] = auth From 63df735fef1a100518550f89648c3491e22b745b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 30 Aug 2019 10:07:01 +0200 Subject: [PATCH 0442/1182] Update links to HTTPS --- .editorconfig | 2 +- CHANGELOG.rst | 4 ++-- CONTRIBUTING.rst | 4 ++-- README.rst | 18 +++++++++--------- httpie/downloads.py | 2 +- httpie/input.py | 2 +- httpie/plugins/base.py | 2 +- httpie/sessions.py | 4 ++-- httpie/utils.py | 2 +- setup.py | 2 +- 10 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.editorconfig b/.editorconfig index 532b12b6de..559e66fe3d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,4 @@ -# http://editorconfig.org +# https://editorconfig.org root = true [*] diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 126f412845..54433ad5fc 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Change Log ========== -This document records all notable changes to `HTTPie `_. -This project adheres to `Semantic Versioning `_. +This document records all notable changes to `HTTPie `_. +This project adheres to `Semantic Versioning `_. `2.0.0-dev`_ (unreleased) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 9ae0492a1d..f0126ac9ba 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -112,6 +112,6 @@ Don't forget to add yourself to `AUTHORS`_! .. _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/ +.. _pytest: https://pytest.org/ +.. _Style Guide for Python Code: https://python.org/dev/peps/pep-0008/ .. _test suite: https://github.com/jakubroztocil/httpie/tree/master/tests diff --git a/README.rst b/README.rst index bb72de7b11..06e9830713 100644 --- a/README.rst +++ b/README.rst @@ -63,7 +63,7 @@ macOS ----- -On macOS, HTTPie can be installed via `Homebrew `_ +On macOS, HTTPie can be installed via `Homebrew `_ (recommended): .. code-block:: bash @@ -537,7 +537,7 @@ fields using ``=@`` and ``:=@``: "married": false, "name": "John", "bookmarks": { - "HTTPie": "http://httpie.org", + "HTTPie": "https://httpie.org", } } @@ -610,7 +610,7 @@ To set custom headers you can use the ``Header:Value`` notation: .. code-block:: bash $ http example.org User-Agent:Bacon/1.0 'Cookie:valued-visitor=yes;foo=bar' \ - X-Foo:Bar Referer:http://httpie.org/ + X-Foo:Bar Referer:https://httpie.org/ .. code-block:: http @@ -620,7 +620,7 @@ To set custom headers you can use the ``Header:Value`` notation: Accept-Encoding: gzip, deflate Cookie: valued-visitor=yes;foo=bar Host: example.org - Referer: http://httpie.org/ + Referer: https://httpie.org/ User-Agent: Bacon/1.0 X-Foo: Bar @@ -1659,7 +1659,7 @@ Please use the following support channels: to ask questions, discuss features, and for general discussion. * `StackOverflow `_ to ask questions (please make sure to use the - `httpie `_ tag). + `httpie `_ tag). * Tweet directly to `@clihttp `_. * You can also tweet directly to `@jakubroztocil`_. @@ -1672,9 +1672,9 @@ Dependencies Under the hood, HTTPie uses these two amazing libraries: -* `Requests `_ +* `Requests `_ — Python HTTP library for humans -* `Pygments `_ +* `Pygments `_ — Python syntax highlighter @@ -1735,7 +1735,7 @@ have contributed. .. _pip: https://pip.pypa.io/en/stable/installing/ -.. _Github API: http://developer.github.com/v3/issues/comments/#create-a-comment +.. _Github API: https://developer.github.com/v3/issues/comments/#create-a-comment .. _these fine people: https://github.com/jakubroztocil/httpie/contributors .. _Jakub Roztocil: https://roztocil.co .. _@jakubroztocil: https://twitter.com/jakubroztocil @@ -1750,7 +1750,7 @@ have contributed. :alt: Test coverage .. |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 + :target: https://travis-ci.org/jakubroztocil/httpie :alt: Build status of the master branch on Mac/Linux .. |gitter| image:: https://img.shields.io/gitter/room/jkbrzt/httpie.svg?style=flat-square diff --git a/httpie/downloads.py b/httpie/downloads.py index 839869caea..a9a247c485 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -42,7 +42,7 @@ def parse_content_range(content_range, resumed_from): """ Parse and validate Content-Range header. - + :param content_range: the value of a Content-Range response header eg. "bytes 21010-47021/47022" diff --git a/httpie/input.py b/httpie/input.py index 102612f3cb..50604f462b 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -25,7 +25,7 @@ # ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) -# +# URL_SCHEME_RE = re.compile(r'^[a-z][a-z0-9.+-]*://', re.IGNORECASE) HTTP_POST = 'POST' diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index bbf53663dc..be8dc9f5c3 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -59,7 +59,7 @@ def get_auth(self, username=None, password=None): class TransportPlugin(BasePlugin): """ - http://docs.python-requests.org/en/latest/user/advanced/#transport-adapters + https://2.python-requests.org/en/latest/user/advanced/#transport-adapters """ diff --git a/httpie/sessions.py b/httpie/sessions.py index 0ae1dc2772..3723bfb51c 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -16,7 +16,7 @@ VALID_SESSION_NAME_PATTERN = re.compile('^[a-zA-Z0-9_.-]+$') # Request headers starting with these prefixes won't be stored in sessions. # They are specific to each request. -# http://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requests +# https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requests SESSION_IGNORED_HEADER_PREFIXES = ['Content-', 'If-'] @@ -132,7 +132,7 @@ def cookies(self, jar): """ :type jar: CookieJar """ - # http://docs.python.org/2/library/cookielib.html#cookie-objects + # https://docs.python.org/2/library/cookielib.html#cookie-objects stored_attrs = ['value', 'path', 'secure', 'expires'] self['cookies'] = {} for cookie in jar: diff --git a/httpie/utils.py b/httpie/utils.py index e5d9766d14..9664bd6940 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -26,7 +26,7 @@ def prepare_dict(d): def humanize_bytes(n, precision=2): # Author: Doug Latornell # Licence: MIT - # URL: http://code.activestate.com/recipes/577081/ + # URL: https://code.activestate.com/recipes/577081/ """Return a humanized string representation of a number of bytes. Assumes `from __future__ import division`. diff --git a/setup.py b/setup.py index eb4649ad41..2d18d38519 100644 --- a/setup.py +++ b/setup.py @@ -57,7 +57,7 @@ def run_tests(self): # bdist_wheel extras_require = { - # http://wheel.readthedocs.io/en/latest/#defining-conditional-dependencies + # https://wheel.readthedocs.io/en/latest/#defining-conditional-dependencies 'python_version == "3.0" or python_version == "3.1"': ['argparse>=1.2.1'], ':sys_platform == "win32"': ['colorama>=0.2.4'], } From 0f654388fc49c0ab7af4c45c7b5294117c435074 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 30 Aug 2019 11:32:14 +0200 Subject: [PATCH 0443/1182] Python 3 annotations, super(), pathlib, etc. --- httpie/__init__.py | 12 ++--- httpie/__main__.py | 6 ++- httpie/cli.py | 10 ++-- httpie/client.py | 8 +-- httpie/config.py | 47 +++++++++-------- httpie/context.py | 24 +++++---- httpie/core.py | 39 +++++++++----- httpie/downloads.py | 83 +++++++++++++++++------------- httpie/input.py | 46 ++++++++++------- httpie/models.py | 15 +++--- httpie/output/formatters/colors.py | 2 +- httpie/output/processing.py | 4 +- httpie/output/streams.py | 8 +-- httpie/plugins/base.py | 6 +-- httpie/plugins/manager.py | 2 +- httpie/sessions.py | 48 +++++++++-------- tests/test_cli.py | 2 +- tests/test_config.py | 2 +- tests/test_docs.py | 3 +- tests/test_downloads.py | 2 +- tests/test_httpie.py | 2 +- tests/test_sessions.py | 10 ++-- tests/utils.py | 44 ++++++++-------- 23 files changed, 229 insertions(+), 196 deletions(-) diff --git a/httpie/__init__.py b/httpie/__init__.py index 6b28eeefc1..9929885d94 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -2,12 +2,15 @@ HTTPie - a CLI, cURL-like tool for humans. """ +from enum import Enum + + __version__ = '2.0.0-dev' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' -class ExitStatus: +class ExitStatus(Enum): """Program exit code constants.""" SUCCESS = 0 ERROR = 1 @@ -23,10 +26,3 @@ class ExitStatus: ERROR_HTTP_3XX = 3 ERROR_HTTP_4XX = 4 ERROR_HTTP_5XX = 5 - - -EXIT_STATUS_LABELS = { - value: key - for key, value in ExitStatus.__dict__.items() - if key.isupper() -} diff --git a/httpie/__main__.py b/httpie/__main__.py index 052d0d1d35..08d7a58f97 100644 --- a/httpie/__main__.py +++ b/httpie/__main__.py @@ -8,10 +8,12 @@ def main(): try: from .core import main - sys.exit(main()) + exit_status = main() except KeyboardInterrupt: from . import ExitStatus - sys.exit(ExitStatus.ERROR_CTRL_C) + exit_status = ExitStatus.ERROR_CTRL_C + + sys.exit(exit_status.value) if __name__ == '__main__': diff --git a/httpie/cli.py b/httpie/cli.py index 2a2decaf28..23a13a7d2a 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -1,9 +1,7 @@ -"""CLI arguments definition. - -NOTE: the CLI interface may change before reaching v1.0. +""" +CLI arguments definition. """ -# noinspection PyCompatibility from argparse import ( RawDescriptionHelpFormatter, FileType, OPTIONAL, ZERO_OR_MORE, SUPPRESS @@ -40,7 +38,7 @@ class HTTPieHelpFormatter(RawDescriptionHelpFormatter): def __init__(self, max_help_position=6, *args, **kwargs): # A smaller indent for args help. kwargs['max_help_position'] = max_help_position - super(HTTPieHelpFormatter, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def _split_lines(self, text, width): text = dedent(text).strip() + '\n\n' @@ -457,7 +455,7 @@ def _split_lines(self, text, width): ) -class _AuthTypeLazyChoices(object): +class _AuthTypeLazyChoices: # Needed for plugin testing def __contains__(self, item): diff --git a/httpie/client.py b/httpie/client.py index 899535b4e6..810938ee00 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -50,18 +50,18 @@ class HTTPieHTTPAdapter(HTTPAdapter): def __init__(self, ssl_version=None, **kwargs): self._ssl_version = ssl_version - super(HTTPieHTTPAdapter, self).__init__(**kwargs) + super().__init__(**kwargs) def init_poolmanager(self, *args, **kwargs): kwargs['ssl_version'] = self._ssl_version - super(HTTPieHTTPAdapter, self).init_poolmanager(*args, **kwargs) + super().init_poolmanager(*args, **kwargs) class ContentCompressionHttpAdapter(HTTPAdapter): def __init__(self, compress, **kwargs): self.compress = compress - super(ContentCompressionHttpAdapter, self).__init__(**kwargs) + super().__init__(**kwargs) def send(self, request, **kwargs): if request.body and self.compress > 0: @@ -75,7 +75,7 @@ def send(self, request, **kwargs): request.body = deflated_data request.headers['Content-Encoding'] = 'deflate' request.headers['Content-Length'] = str(len(deflated_data)) - return super(ContentCompressionHttpAdapter, self).send(request, **kwargs) + return super().send(request, **kwargs) def get_requests_session(ssl_version, compress): diff --git a/httpie/config.py b/httpie/config.py index 57a4f7312a..e7991f129f 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -1,12 +1,14 @@ -import os -import json import errno +import json +import os +from pathlib import Path +from typing import Union from httpie import __version__ from httpie.compat import is_windows -DEFAULT_CONFIG_DIR = str(os.environ.get( +DEFAULT_CONFIG_DIR = Path(os.environ.get( 'HTTPIE_CONFIG_DIR', os.path.expanduser('~/.httpie') if not is_windows else os.path.expandvars(r'%APPDATA%\\httpie') @@ -14,41 +16,36 @@ class BaseConfigDict(dict): - name = None helpurl = None about = None - def __getattr__(self, item): - return self[item] - - def _get_path(self): + def _get_path(self) -> Path: """Return the config file path without side-effects.""" raise NotImplementedError() - @property - def path(self): + def path(self) -> Path: """Return the config file path creating basedir, if needed.""" path = self._get_path() try: - os.makedirs(os.path.dirname(path), mode=0o700) + path.parent.mkdir(mode=0o700, parents=True) except OSError as e: if e.errno != errno.EEXIST: raise return path - def is_new(self): - return not os.path.exists(self._get_path()) + def is_new(self) -> bool: + return not self._get_path().exists() def load(self): try: - with open(self.path, 'rt') as f: + with self.path().open('rt') as f: try: data = json.load(f) except ValueError as e: raise ValueError( 'Invalid %s JSON: %s [%s]' % - (type(self).__name__, str(e), self.path) + (type(self).__name__, str(e), self.path()) ) self.update(data) except IOError as e: @@ -66,7 +63,7 @@ def save(self, fail_silently=False): self['__meta__']['about'] = self.about try: - with open(self.path, 'w') as f: + with self.path().open('w') as f: json.dump(self, f, indent=4, sort_keys=True, ensure_ascii=True) f.write('\n') except IOError: @@ -75,26 +72,28 @@ def save(self, fail_silently=False): def delete(self): try: - os.unlink(self.path) + self.path().unlink() except OSError as e: if e.errno != errno.ENOENT: raise class Config(BaseConfigDict): - name = 'config' helpurl = 'https://httpie.org/doc#config' about = 'HTTPie configuration file' - DEFAULTS = { 'default_options': [] } - def __init__(self, directory=DEFAULT_CONFIG_DIR): - super(Config, self).__init__() + def __init__(self, directory: Union[str, Path] = DEFAULT_CONFIG_DIR): + super().__init__() self.update(self.DEFAULTS) - self.directory = directory + self.directory = Path(directory) - def _get_path(self): - return os.path.join(self.directory, self.name + '.json') + def _get_path(self) -> Path: + return self.directory / (self.name + '.json') + + @property + def default_options(self) -> list: + return self['default_options'] diff --git a/httpie/context.py b/httpie/context.py index 2f2453783f..dce4ba7cb9 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -1,4 +1,5 @@ import sys +from pathlib import Path from typing import Union, IO, Optional @@ -13,7 +14,7 @@ from httpie.utils import repr_dict_nice -class Environment(object): +class Environment: """ Information about the execution context (standard streams, config directory, etc). @@ -23,16 +24,16 @@ class Environment(object): is used by the test suite to simulate various scenarios. """ - is_windows = is_windows - config_dir = DEFAULT_CONFIG_DIR + is_windows: bool = is_windows + config_dir: Path = DEFAULT_CONFIG_DIR stdin: Optional[IO] = sys.stdin # `None` when closed fd (#791) - stdin_isatty = stdin.isatty() if stdin else False - stdin_encoding = None - stdout = sys.stdout - stdout_isatty = stdout.isatty() - stdout_encoding = None - stderr = sys.stderr - stderr_isatty = stderr.isatty() + stdin_isatty: bool = stdin.isatty() if stdin else False + stdin_encoding: str = None + stdout: IO = sys.stdout + stdout_isatty: bool = stdout.isatty() + stdout_encoding: str = None + stderr: IO = sys.stderr + stderr_isatty: bool = stderr.isatty() colors = 256 if not is_windows: if curses: @@ -73,12 +74,13 @@ def __init__(self, **kwargs): # noinspection PyUnresolvedReferences from colorama import AnsiToWin32 if isinstance(self.stdout, AnsiToWin32): + # noinspection PyUnresolvedReferences actual_stdout = self.stdout.wrapped self.stdout_encoding = getattr( actual_stdout, 'encoding', None) or 'utf8' @property - def config(self): + def config(self) -> Config: if not hasattr(self, '_config'): self._config = Config(directory=self.config_dir) if self._config.is_new(): diff --git a/httpie/core.py b/httpie/core.py index f39635c4f9..1113b2edea 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -10,27 +10,29 @@ 5. Exit. """ -import sys +import argparse import errno import platform +import sys +from typing import Callable, List, Union import requests -from requests import __version__ as requests_version from pygments import __version__ as pygments_version +from requests import __version__ as requests_version -from httpie import __version__ as httpie_version, ExitStatus +from httpie import ExitStatus, __version__ as httpie_version from httpie.client import get_response -from httpie.downloads import Downloader from httpie.context import Environment -from httpie.plugins import plugin_manager +from httpie.downloads import Downloader from httpie.output.streams import ( build_output_stream, write_stream, - write_stream_with_colors_win_py3 + write_stream_with_colors_win_py3, ) +from httpie.plugins import plugin_manager -def get_exit_status(http_status, follow=False): +def get_exit_status(http_status: int, follow=False) -> ExitStatus: """Translate HTTP status code to exit status code.""" if 300 <= http_status <= 399 and not follow: # Redirect @@ -45,7 +47,7 @@ def get_exit_status(http_status, follow=False): return ExitStatus.SUCCESS -def print_debug_info(env): +def print_debug_info(env: Environment): env.stderr.writelines([ 'HTTPie %s\n' % httpie_version, 'Requests %s\n' % requests_version, @@ -58,7 +60,10 @@ def print_debug_info(env): env.stderr.write('\n') -def decode_args(args, stdin_encoding): +def decode_args( + args: List[Union[str, bytes]], + stdin_encoding: str +) -> List[str]: """ Convert all bytes args to str by decoding them using stdin encoding. @@ -71,7 +76,11 @@ def decode_args(args, stdin_encoding): ] -def program(args, env, log_error): +def program( + args: argparse.Namespace, + env: Environment, + log_error: Callable +) -> ExitStatus: """ The main program without error handling @@ -168,7 +177,11 @@ def program(args, env, log_error): args.output_file.close() -def main(args=sys.argv, env=Environment(), custom_log_error=None): +def main( + args: List[Union[str, bytes]] = sys.argv, + env=Environment(), + custom_log_error: Callable = None +) -> ExitStatus: """ The main function. @@ -218,7 +231,7 @@ def log_error(msg, *args, **kwargs): raise exit_status = ExitStatus.ERROR_CTRL_C except SystemExit as e: - if e.code != ExitStatus.SUCCESS: + if e.code != ExitStatus.SUCCESS.value: env.stderr.write('\n') if include_traceback: raise @@ -236,7 +249,7 @@ def log_error(msg, *args, **kwargs): raise exit_status = ExitStatus.ERROR_CTRL_C except SystemExit as e: - if e.code != ExitStatus.SUCCESS: + if e.code != ExitStatus.SUCCESS.value: env.stderr.write('\n') if include_traceback: raise diff --git a/httpie/downloads.py b/httpie/downloads.py index a9a247c485..b3aaac9002 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -4,24 +4,27 @@ """ from __future__ import division + +import errno +import mimetypes import os import re import sys -import errno -import mimetypes import threading -from time import sleep, time from mailbox import Message +from time import sleep, time +from typing import IO, Optional, Tuple from urllib.parse import urlsplit -from httpie.output.streams import RawStream +import requests + from httpie.models import HTTPResponse +from httpie.output.streams import RawStream from httpie.utils import humanize_bytes PARTIAL_CONTENT = 206 - CLEAR_LINE = '\r\033[K' PROGRESS = ( '{percentage: 6.2f} %' @@ -38,7 +41,7 @@ class ContentRangeError(ValueError): pass -def parse_content_range(content_range, resumed_from): +def parse_content_range(content_range: str, resumed_from: int) -> int: """ Parse and validate Content-Range header. @@ -79,14 +82,14 @@ def parse_content_range(content_range, resumed_from): # 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)): + 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)): + 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)' @@ -97,7 +100,9 @@ def parse_content_range(content_range, resumed_from): return last_byte_pos + 1 -def filename_from_content_disposition(content_disposition): +def filename_from_content_disposition( + content_disposition: str +) -> Optional[str]: """ Extract and validate filename from a Content-Disposition header. @@ -116,7 +121,7 @@ def filename_from_content_disposition(content_disposition): return filename -def filename_from_url(url, content_type): +def filename_from_url(url: str, content_type: str) -> str: fn = urlsplit(url).path.rstrip('/') fn = os.path.basename(fn) if fn else 'index' if '.' not in fn and content_type: @@ -136,7 +141,7 @@ def filename_from_url(url, content_type): return fn -def trim_filename(filename, max_len): +def trim_filename(filename: str, max_len: int) -> str: if len(filename) > max_len: trim_by = len(filename) - max_len name, ext = os.path.splitext(filename) @@ -147,7 +152,7 @@ def trim_filename(filename, max_len): return filename -def get_filename_max_length(directory): +def get_filename_max_length(directory: str) -> int: max_len = 255 try: pathconf = os.pathconf @@ -162,14 +167,14 @@ def get_filename_max_length(directory): return max_len -def trim_filename_if_needed(filename, directory='.', extra=0): +def trim_filename_if_needed(filename: str, directory='.', extra=0) -> str: max_len = get_filename_max_length(directory) - extra if len(filename) > max_len: filename = trim_filename(filename, max_len) return filename -def get_unique_filename(filename, exists=os.path.exists): +def get_unique_filename(filename: str, exists=os.path.exists) -> str: attempt = 0 while True: suffix = '-' + str(attempt) if attempt > 0 else '' @@ -180,10 +185,14 @@ def get_unique_filename(filename, exists=os.path.exists): attempt += 1 -class Downloader(object): +class Downloader: - def __init__(self, output_file=None, - resume=False, progress_file=sys.stderr): + def __init__( + self, + output_file: IO = None, + resume: bool = False, + progress_file: IO = sys.stderr + ): """ :param resume: Should the download resume if partial download already exists. @@ -195,24 +204,21 @@ def __init__(self, output_file=None, :param progress_file: Where to report download progress. """ + self.finished = False + self.status = DownloadStatus() self._output_file = output_file self._resume = resume self._resumed_from = 0 - self.finished = False - - self.status = Status() self._progress_reporter = ProgressReporterThread( status=self.status, output=progress_file ) - def pre_request(self, request_headers): + def pre_request(self, request_headers: dict): """Called just before the HTTP request is sent. Might alter `request_headers`. - :type request_headers: dict - """ # Ask the server not to encode the content so that we can resume, etc. request_headers['Accept-Encoding'] = 'identity' @@ -224,13 +230,12 @@ def pre_request(self, request_headers): request_headers['Range'] = 'bytes=%d-' % bytes_have self._resumed_from = bytes_have - def start(self, final_response): + def start(self, final_response: requests.Response) -> Tuple[RawStream, IO]: """ Initiate and return a stream for `response` body with progress callback attached. Can be called only once. :param final_response: Initiated response object with headers already fetched - :type final_response: requests.models.Response :return: RawStream, output_file @@ -297,14 +302,14 @@ def failed(self): self._progress_reporter.stop() @property - def interrupted(self): + def interrupted(self) -> bool: return ( self.finished and self.status.total_size and self.status.total_size != self.status.downloaded ) - def chunk_downloaded(self, chunk): + def chunk_downloaded(self, chunk: bytes): """ A download progress callback. @@ -316,7 +321,9 @@ def chunk_downloaded(self, chunk): self.status.chunk_downloaded(len(chunk)) @staticmethod - def _get_output_file_from_response(final_response): + def _get_output_file_from_response( + final_response: requests.Response + ) -> IO: # Output file not specified. Pick a name that doesn't exist yet. filename = None if 'Content-Disposition' in final_response.headers: @@ -335,7 +342,7 @@ def _get_output_file_from_response(final_response): return open(unique_filename, mode='a+b') -class Status(object): +class DownloadStatus: """Holds details about the downland status.""" def __init__(self): @@ -372,13 +379,15 @@ class ProgressReporterThread(threading.Thread): Uses threading to periodically update the status (speed, ETA, etc.). """ - def __init__(self, status, output, tick=.1, update_interval=1): - """ - :type status: Status - :type output: file - """ - super(ProgressReporterThread, self).__init__() + def __init__( + self, + status: DownloadStatus, + output: IO, + tick=.1, + update_interval=1 + ): + super().__init__() self.status = status self.output = output self._tick = tick diff --git a/httpie/input.py b/httpie/input.py index 50604f462b..71196089d0 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -9,14 +9,15 @@ import mimetypes import getpass from io import BytesIO -from collections import namedtuple, Iterable, OrderedDict +from collections import namedtuple, OrderedDict # noinspection PyCompatibility -from argparse import ArgumentParser, ArgumentTypeError, ArgumentError +import argparse # TODO: Use MultiDict for headers once added to `requests`. # https://github.com/jakubroztocil/httpie/issues/130 from urllib.parse import urlsplit +from httpie.context import Environment from httpie.plugins import plugin_manager from requests.structures import CaseInsensitiveDict @@ -121,7 +122,7 @@ } -class HTTPieArgumentParser(ArgumentParser): +class HTTPieArgumentParser(argparse.ArgumentParser): """Adds additional logic to `argparse.ArgumentParser`. Handles all input (CLI args, file args, stdin), applies defaults, @@ -131,16 +132,21 @@ class HTTPieArgumentParser(ArgumentParser): def __init__(self, *args, **kwargs): kwargs['add_help'] = False - super(HTTPieArgumentParser, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.env = None self.args = None self.has_stdin_data = False # noinspection PyMethodOverriding - def parse_args(self, env, program_name='http', args=None, namespace=None): + def parse_args( + self, + env: Environment, + program_name='http', + args=None, + namespace=None + ) -> argparse.Namespace: self.env = env - self.args, no_options = super( - HTTPieArgumentParser, self).parse_known_args(args, namespace) + self.args, no_options = super().parse_known_args(args, namespace) if self.args.debug: self.args.traceback = True @@ -193,7 +199,7 @@ def _print_message(self, message, file=None): }.get(file, file) if not hasattr(file, 'buffer') and isinstance(message, str): message = message.encode(self.env.stdout_encoding) - super(HTTPieArgumentParser, self)._print_message(message, file) + super()._print_message(message, file) def _setup_standard_streams(self): """ @@ -342,7 +348,7 @@ def _guess_method(self): self.args.items.insert(0, KeyValueArgType( *SEP_GROUP_ALL_ITEMS).__call__(self.args.url)) - except ArgumentTypeError as e: + except argparse.ArgumentTypeError as e: if self.args.traceback: raise self.error(e.args[0]) @@ -461,7 +467,7 @@ class ParseError(Exception): pass -class KeyValue(object): +class KeyValue: """Base key-value pair parsed from CLI.""" def __init__(self, key, value, sep, orig): @@ -477,7 +483,7 @@ def __repr__(self): return repr(self.__dict__) -class SessionNameValidator(object): +class SessionNameValidator: def __init__(self, error_message): self.error_message = error_message @@ -486,11 +492,11 @@ 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)): - raise ArgumentError(None, self.error_message) + raise argparse.ArgumentError(None, self.error_message) return value -class KeyValueArgType(object): +class KeyValueArgType: """A key-value pair argument type used with `argparse`. Parses a key-value arg and constructs a `KeyValue` instance. @@ -573,7 +579,7 @@ def tokenize(string): break else: - raise ArgumentTypeError( + raise argparse.ArgumentTypeError( u'"%s" is not a valid value' % string) return self.key_value_class( @@ -611,8 +617,8 @@ def __call__(self, string): """ try: - return super(AuthCredentialsArgType, self).__call__(string) - except ArgumentTypeError: + return super().__call__(string) + except argparse.ArgumentTypeError: # No password provided, will prompt for it later. return self.key_value_class( key=string, @@ -639,10 +645,10 @@ def __setitem__(self, key, value): """ assert not isinstance(value, list) if key not in self: - super(RequestItemsDict, self).__setitem__(key, value) + super().__setitem__(key, value) else: if not isinstance(self[key], list): - super(RequestItemsDict, self).__setitem__(key, [self[key]]) + super().__setitem__(key, [self[key]]) self[key].append(value) @@ -653,7 +659,7 @@ class ParamsDict(RequestItemsDict): class DataDict(RequestItemsDict): def items(self): - for key, values in super(RequestItemsDict, self).items(): + for key, values in super().items(): if not isinstance(values, list): values = [values] for value in values: @@ -757,4 +763,4 @@ def readable_file_arg(filename): with open(filename, 'rb'): return filename except IOError as ex: - raise ArgumentTypeError('%s: %s' % (filename, ex.args[1])) + raise argparse.ArgumentTypeError('%s: %s' % (filename, ex.args[1])) diff --git a/httpie/models.py b/httpie/models.py index 52174859ab..17730eaa91 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -1,37 +1,38 @@ +from typing import Iterable, Optional from urllib.parse import urlsplit -class HTTPMessage(object): +class HTTPMessage: """Abstract class for HTTP messages.""" def __init__(self, orig): self._orig = orig - def iter_body(self, chunk_size): + def iter_body(self, chunk_size: int) -> Iterable[bytes]: """Return an iterator over the body.""" raise NotImplementedError() - def iter_lines(self, chunk_size): + def iter_lines(self, chunk_size: int) -> Iterable[bytes]: """Return an iterator over the body yielding (`line`, `line_feed`).""" raise NotImplementedError() @property - def headers(self): + def headers(self) -> str: """Return a `str` with the message's headers.""" raise NotImplementedError() @property - def encoding(self): + def encoding(self) -> Optional[str]: """Return a `str` with the message's encoding, if known.""" raise NotImplementedError() @property - def body(self): + def body(self) -> bytes: """Return a `bytes` with the message's body.""" raise NotImplementedError() @property - def content_type(self): + def content_type(self) -> str: """Return the message content type.""" ct = self._orig.headers.get('Content-Type', '') if not isinstance(ct, str): diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index d8ef808c20..52f5a22a78 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -42,7 +42,7 @@ class ColorFormatter(FormatterPlugin): def __init__(self, env, explicit_json=False, color_scheme=DEFAULT_STYLE, **kwargs): - super(ColorFormatter, self).__init__(**kwargs) + super().__init__(**kwargs) if not env.colors: self.enabled = False diff --git a/httpie/output/processing.py b/httpie/output/processing.py index 4e6e3d7da6..850c6810c5 100644 --- a/httpie/output/processing.py +++ b/httpie/output/processing.py @@ -11,7 +11,7 @@ def is_valid_mime(mime): return mime and MIME_RE.match(mime) -class Conversion(object): +class Conversion: def get_converter(self, mime): if is_valid_mime(mime): @@ -20,7 +20,7 @@ def get_converter(self, mime): return converter_class(mime) -class Formatting(object): +class Formatting: """A delegate class that invokes the actual processors.""" def __init__(self, groups, env=Environment(), **kwargs): diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 6f0d5620b1..a3affdb068 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -124,7 +124,7 @@ def get_stream_type(env, args): return Stream -class BaseStream(object): +class BaseStream: """Base HTTP message output stream class.""" def __init__(self, msg, with_headers=True, with_body=True, @@ -174,7 +174,7 @@ class RawStream(BaseStream): CHUNK_SIZE_BY_LINE = 1 def __init__(self, chunk_size=CHUNK_SIZE, **kwargs): - super(RawStream, self).__init__(**kwargs) + super().__init__(**kwargs) self.chunk_size = chunk_size def iter_body(self): @@ -193,7 +193,7 @@ class EncodedStream(BaseStream): def __init__(self, env=Environment(), **kwargs): - super(EncodedStream, self).__init__(**kwargs) + super().__init__(**kwargs) if env.stdout_isatty: # Use the encoding supported by the terminal. @@ -228,7 +228,7 @@ class PrettyStream(EncodedStream): CHUNK_SIZE = 1 def __init__(self, conversion, formatting, **kwargs): - super(PrettyStream, self).__init__(**kwargs) + super().__init__(**kwargs) self.formatting = formatting self.conversion = conversion self.mime = self.msg.content_type.split(';')[0] diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index be8dc9f5c3..ef1475fd01 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -1,4 +1,4 @@ -class BasePlugin(object): +class BasePlugin: # The name of the plugin, eg. "My auth". name = None @@ -75,7 +75,7 @@ def get_adapter(self): raise NotImplementedError() -class ConverterPlugin(object): +class ConverterPlugin: def __init__(self, mime): self.mime = mime @@ -88,7 +88,7 @@ def supports(cls, mime): raise NotImplementedError -class FormatterPlugin(object): +class FormatterPlugin: def __init__(self, **kwargs): """ diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index c6390f2606..cde0e8ec11 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -12,7 +12,7 @@ ] -class PluginManager(object): +class PluginManager: def __init__(self): self._plugins = [] diff --git a/httpie/sessions.py b/httpie/sessions.py index 3723bfb51c..af2dfc3943 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -3,16 +3,20 @@ """ import re import os +from pathlib import Path +from typing import Optional, Union from urllib.parse import urlsplit +from requests.auth import AuthBase from requests.cookies import RequestsCookieJar, create_cookie +import requests from httpie.config import BaseConfigDict, DEFAULT_CONFIG_DIR from httpie.plugins import plugin_manager SESSIONS_DIR_NAME = 'sessions' -DEFAULT_SESSIONS_DIR = os.path.join(DEFAULT_CONFIG_DIR, SESSIONS_DIR_NAME) +DEFAULT_SESSIONS_DIR = DEFAULT_CONFIG_DIR / SESSIONS_DIR_NAME VALID_SESSION_NAME_PATTERN = re.compile('^[a-zA-Z0-9_.-]+$') # Request headers starting with these prefixes won't be stored in sessions. # They are specific to each request. @@ -20,8 +24,13 @@ SESSION_IGNORED_HEADER_PREFIXES = ['Content-', 'If-'] -def get_response(requests_session, session_name, - config_dir, args, read_only=False): +def get_response( + requests_session: requests.Session, + session_name: str, + config_dir: Path, + args, + read_only=False, +) -> requests.Response: """Like `client.get_responses`, but applies permanent aspects of the session to the request. @@ -38,10 +47,10 @@ def get_response(requests_session, session_name, # host:port => host_port hostname = hostname.replace(':', '_') - path = os.path.join(config_dir, - SESSIONS_DIR_NAME, - hostname, - session_name + '.json') + path = ( + config_dir / SESSIONS_DIR_NAME / hostname / + (session_name + '.json') + ) session = Session(path) session.load() @@ -77,9 +86,9 @@ class Session(BaseConfigDict): helpurl = 'https://httpie.org/doc#sessions' about = 'HTTPie session file' - def __init__(self, path, *args, **kwargs): - super(Session, self).__init__(*args, **kwargs) - self._path = path + def __init__(self, path: Union[str, Path]): + super().__init__() + self._path = Path(path) self['headers'] = {} self['cookies'] = {} self['auth'] = { @@ -88,10 +97,10 @@ def __init__(self, path, *args, **kwargs): 'password': None } - def _get_path(self): + def _get_path(self) -> Path: return self._path - def update_headers(self, request_headers): + def update_headers(self, request_headers: dict): """ Update the session headers with the request ones while ignoring certain name prefixes. @@ -102,7 +111,7 @@ def update_headers(self, request_headers): for name, value in request_headers.items(): if value is None: - continue # Ignore explicitely unset headers + continue # Ignore explicitly unset headers value = value.decode('utf8') if name == 'User-Agent' and value.startswith('HTTPie/'): @@ -115,11 +124,11 @@ def update_headers(self, request_headers): self['headers'][name] = value @property - def headers(self): + def headers(self) -> dict: return self['headers'] @property - def cookies(self): + def cookies(self) -> RequestsCookieJar: jar = RequestsCookieJar() for name, cookie_dict in self['cookies'].items(): jar.set_cookie(create_cookie( @@ -128,10 +137,7 @@ def cookies(self): return jar @cookies.setter - def cookies(self, jar): - """ - :type jar: CookieJar - """ + def cookies(self, jar: RequestsCookieJar): # https://docs.python.org/2/library/cookielib.html#cookie-objects stored_attrs = ['value', 'path', 'secure', 'expires'] self['cookies'] = {} @@ -142,7 +148,7 @@ def cookies(self, jar): } @property - def auth(self): + def auth(self) -> Optional[AuthBase]: auth = self.get('auth', None) if not auth or not auth['type']: return @@ -171,6 +177,6 @@ def auth(self): return plugin.get_auth(**credentials) @auth.setter - def auth(self, auth): + def auth(self, auth: dict): assert {'type', 'raw_auth'} == auth.keys() self['auth'] = auth diff --git a/tests/test_cli.py b/tests/test_cli.py index 8f571f0f44..1571c76c9f 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -305,7 +305,7 @@ def test_valid_no_options(self, httpbin): def test_invalid_no_options(self, httpbin): r = http('--no-war', 'GET', httpbin.url + '/get', error_exit_ok=True) - assert r.exit_status == 1 + assert r.exit_status == ExitStatus.ERROR assert 'unrecognized arguments: --no-war' in r.stderr assert 'GET /get HTTP/1.1' not in r diff --git a/tests/test_config.py b/tests/test_config.py index 63bb450435..08cfe5de68 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -28,5 +28,5 @@ def test_default_options_overwrite(httpbin): def test_current_version(): - version = Environment().config['__meta__']['httpie'] + version = MockEnvironment().config['__meta__']['httpie'] assert version == __version__ diff --git a/tests/test_docs.py b/tests/test_docs.py index 07363535d8..766810afd8 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -9,7 +9,7 @@ def has_docutils(): try: - # noinspection PyUnresolvedReferences + # noinspection PyUnresolvedReferences,PyPackageRequirements import docutils return True except ImportError: @@ -17,6 +17,7 @@ def has_docutils(): def rst_filenames(): + # noinspection PyShadowingNames for root, dirnames, filenames in os.walk(os.path.dirname(TESTS_ROOT)): if '.tox' not in root: for filename in fnmatch.filter(filenames, '*.rst'): diff --git a/tests/test_downloads.py b/tests/test_downloads.py index ac5dbc1aa2..76f04e45a2 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -14,7 +14,7 @@ from utils import http, MockEnvironment -class Response(object): +class Response: # noinspection PyDefaultArgument def __init__(self, url, headers={}, status_code=200): self.url = url diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 745e18e23d..797391a959 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -24,7 +24,7 @@ def test_version(): r = http('--version', error_exit_ok=True) assert r.exit_status == httpie.ExitStatus.SUCCESS # FIXME: py3 has version in stdout, py2 in stderr - assert httpie.__version__ == r.stderr.strip() + r.strip() + assert httpie.__version__ == r.strip() def test_GET(httpbin_both): diff --git a/tests/test_sessions.py b/tests/test_sessions.py index ebaa7a9d73..08a7f0fc71 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -11,7 +11,7 @@ from fixtures import UNICODE -class SessionTestBase(object): +class SessionTestBase: def start_session(self, httpbin): """Create and reuse a unique config dir for each test.""" @@ -44,7 +44,7 @@ def start_session(self, httpbin): authorization, and response cookies. """ - super(TestSessionFlow, self).start_session(httpbin) + super().start_session(httpbin) r1 = http('--follow', '--session=test', '--auth=username:password', 'GET', httpbin.url + '/cookies/set?hello=world', 'Hello:World', @@ -130,12 +130,12 @@ def test_session_ignored_header_prefixes(self, httpbin): def test_session_by_path(self, httpbin): self.start_session(httpbin) - session_path = os.path.join(self.config_dir, 'session-by-path.json') - r1 = http('--session=' + session_path, 'GET', httpbin.url + '/get', + session_path = self.config_dir / 'session-by-path.json' + r1 = http('--session', str(session_path), 'GET', httpbin.url + '/get', 'Foo:Bar', env=self.env()) assert HTTP_OK in r1 - r2 = http('--session=' + session_path, 'GET', httpbin.url + '/get', + r2 = http('--session', str(session_path), 'GET', httpbin.url + '/get', env=self.env()) assert HTTP_OK in r2 assert r2.json['headers']['Foo'] == 'Bar' diff --git a/tests/utils.py b/tests/utils.py index 0412791bd1..141bd765d4 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -5,8 +5,11 @@ import time import json import tempfile +from pathlib import Path +from typing import Optional -from httpie import ExitStatus, EXIT_STATUS_LABELS +from httpie import ExitStatus +from httpie.config import Config from httpie.context import Environment from httpie.core import main @@ -22,9 +25,9 @@ ) -def mk_config_dir(): +def mk_config_dir() -> Path: dirname = tempfile.mkdtemp(prefix='httpie_config_') - return dirname + return Path(dirname) def add_auth(url, auth): @@ -40,7 +43,6 @@ class MockEnvironment(Environment): is_windows = False def __init__(self, create_temp_config_dir=True, **kwargs): - self.create_temp_config_dir = create_temp_config_dir if 'stdout' not in kwargs: kwargs['stdout'] = tempfile.TemporaryFile( mode='w+b', @@ -51,22 +53,24 @@ def __init__(self, create_temp_config_dir=True, **kwargs): mode='w+t', prefix='httpie_stderr' ) - super(MockEnvironment, self).__init__(**kwargs) + super().__init__(**kwargs) + self._create_temp_config_dir = create_temp_config_dir self._delete_config_dir = False + self._temp_dir = Path(tempfile.gettempdir()) @property - def config(self): - if (self.create_temp_config_dir - and not self.config_dir.startswith(tempfile.gettempdir())): + def config(self) -> Config: + if (self._create_temp_config_dir + and self._temp_dir not in self.config_dir.parents): self.config_dir = mk_config_dir() self._delete_config_dir = True - return super(MockEnvironment, self).config + return super().config def cleanup(self): self.stdout.close() self.stderr.close() if self._delete_config_dir: - assert self.config_dir.startswith(tempfile.gettempdir()) + assert self._temp_dir in self.config_dir.parents from shutil import rmtree rmtree(self.config_dir) @@ -77,7 +81,7 @@ def __del__(self): pass -class BaseCLIResponse(object): +class BaseCLIResponse: """ Represents the result of simulated `$ http' invocation via `http()`. @@ -88,9 +92,9 @@ class BaseCLIResponse(object): - exit_status output: print(self.exit_status) """ - stderr = None - json = None - exit_status = None + stderr: str = None + json: dict = None + exit_status: ExitStatus = None class BytesCLIResponse(bytes, BaseCLIResponse): @@ -107,7 +111,7 @@ class BytesCLIResponse(bytes, BaseCLIResponse): class StrCLIResponse(str, BaseCLIResponse): @property - def json(self): + def json(self) -> Optional[dict]: """ Return deserialized JSON body, if one included in the output and is parsable. @@ -132,6 +136,7 @@ def json(self): pass else: try: + # noinspection PyAttributeOutsideInit self._json = json.loads(j) except ValueError: pass @@ -174,7 +179,7 @@ def http(*args, program_name='http', **kwargs): >>> type(r) == StrCLIResponse True >>> r.exit_status - 0 + >>> r.stderr '' >>> 'HTTP/1.1 200 OK' in r @@ -227,10 +232,7 @@ def dump_stderr(): dump_stderr() raise ExitStatusError( 'httpie.core.main() unexpectedly returned' - ' a non-zero exit status: {0} ({1})'.format( - exit_status, - EXIT_STATUS_LABELS[exit_status] - ) + f' a non-zero exit status: {exit_status}' ) stdout.seek(0) @@ -239,10 +241,8 @@ def dump_stderr(): try: output = output.decode('utf8') except UnicodeDecodeError: - # noinspection PyArgumentList r = BytesCLIResponse(output) else: - # noinspection PyArgumentList r = StrCLIResponse(output) r.stderr = stderr.read() r.exit_status = exit_status From a5713f71900a96f04b89bf909bdde50a6c37a32a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 30 Aug 2019 21:26:51 +0200 Subject: [PATCH 0444/1182] pep8 --- httpie/sessions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httpie/sessions.py b/httpie/sessions.py index af2dfc3943..9f11c0b165 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -48,8 +48,8 @@ def get_response( # host:port => host_port hostname = hostname.replace(':', '_') path = ( - config_dir / SESSIONS_DIR_NAME / hostname / - (session_name + '.json') + config_dir / SESSIONS_DIR_NAME / hostname + / (session_name + '.json') ) session = Session(path) From 1dc67a6a385130e8db0d4a7e7b1818d31030be9c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 12:09:17 +0200 Subject: [PATCH 0445/1182] Allow bypassing .netrc with `--ignore-netrc` (close #730) --- CHANGELOG.rst | 3 ++- README.rst | 15 ++++++++++++++- httpie/cli.py | 8 ++++++++ httpie/input.py | 6 +++++- httpie/utils.py | 11 +++++++++++ tests/test_auth.py | 25 +++++++++++++++++++++++++ 6 files changed, 65 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 54433ad5fc..da48f090b5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,7 +12,8 @@ This project adheres to `Semantic Versioning `_. * Removed the default 30-second connection ``--timeout`` limit. * Removed Python’s default limit of 100 response headers. * Added ``--max-headers`` to allow setting the max header limit. -* Added ``--compress``. +* Added ``--compress`` to allow request body compression. +* Added ``--ignore-netrc`` to allow bypassing credentials from ``.netrc``. * Added ``https`` alias command with ``https://`` as the default scheme. * Fixed an error when ``stdin`` was a closed fd. * Fixed an error when the config directory was not writeable. diff --git a/README.rst b/README.rst index 06e9830713..e0f7a3207f 100644 --- a/README.rst +++ b/README.rst @@ -776,7 +776,10 @@ Password prompt ``.netrc`` ---------- -Authentication information from your ``~/.netrc`` file is honored as well: +Authentication information from your ``~/.netrc`` +file is by default honored as well. + +For example: .. code-block:: bash @@ -785,10 +788,20 @@ Authentication information from your ``~/.netrc`` file is honored as well: login httpie password test +.. code-block:: bash + $ http httpbin.org/basic-auth/httpie/test HTTP/1.1 200 OK [...] +This can be disable with the ``--ignore-netrc`` option: + +.. code-block:: bash + + $ http --ignore-netrc httpbin.org/basic-auth/httpie/test + HTTP/1.1 401 UNAUTHORIZED + [...] + Auth plugins ------------ diff --git a/httpie/cli.py b/httpie/cli.py index 23a13a7d2a..5ff0465a9f 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -492,7 +492,15 @@ def __iter__(self): for plugin in _auth_plugins )), ) +auth.add_argument( + '--ignore-netrc', + default=False, + action='store_true', + help=""" + Ignore credentials from .netrc. + """, +) ####################################################################### # Network diff --git a/httpie/input.py b/httpie/input.py index 71196089d0..dae896926a 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -22,7 +22,7 @@ from requests.structures import CaseInsensitiveDict from httpie.sessions import VALID_SESSION_NAME_PATTERN -from httpie.utils import load_json_preserve_order +from httpie.utils import load_json_preserve_order, ExplicitNullAuth # ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) @@ -287,6 +287,10 @@ def _process_auth(self): username=credentials.key, password=credentials.value, ) + if not self.args.auth and self.args.ignore_netrc: + # Set a no-op auth to force requests to ignore .netrc + # + self.args.auth = ExplicitNullAuth() def _apply_no_options(self, no_options): """For every `--no-OPTION` in `no_options`, set `args.OPTION` to diff --git a/httpie/utils.py b/httpie/utils.py index 9664bd6940..453b67a1ed 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -2,6 +2,8 @@ import json from collections import OrderedDict +import requests.auth + def load_json_preserve_order(s): return json.loads(s, object_pairs_hook=OrderedDict) @@ -67,3 +69,12 @@ def humanize_bytes(n, precision=2): # noinspection PyUnboundLocalVariable return '%.*f %s' % (precision, n / factor, suffix) + + +class ExplicitNullAuth(requests.auth.AuthBase): + """Forces requests to ignore the ``.netrc``. + + """ + + def __call__(self, r): + return r diff --git a/tests/test_auth.py b/tests/test_auth.py index 62cceb65bf..a4d95f8007 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -2,6 +2,7 @@ import mock import pytest +from httpie.utils import ExplicitNullAuth from utils import http, add_auth, HTTP_OK, MockEnvironment import httpie.input import httpie.cli @@ -73,3 +74,27 @@ def test_missing_auth(httpbin): ) assert HTTP_OK not in r assert '--auth required' in r.stderr + + +def test_netrc(httpbin_both): + with mock.patch('requests.sessions.get_netrc_auth') as get_netrc_auth: + get_netrc_auth.return_value = ('httpie', 'password') + r = http(httpbin_both + '/basic-auth/httpie/password') + assert get_netrc_auth.call_count == 1 + assert HTTP_OK in r + + +def test_ignore_netrc(httpbin_both): + with mock.patch('requests.sessions.get_netrc_auth') as get_netrc_auth: + get_netrc_auth.return_value = ('httpie', 'password') + r = http('--ignore-netrc', httpbin_both + '/basic-auth/httpie/password') + assert get_netrc_auth.call_count == 0 + assert 'HTTP/1.1 401 UNAUTHORIZED' in r + + +def test_ignore_netrc_null_auth(): + args = httpie.cli.parser.parse_args( + args=['--ignore-netrc', 'example.org'], + env=MockEnvironment(), + ) + assert isinstance(args.auth, ExplicitNullAuth) From 3e24827f4d39d8aa4a685929fb4078eb5e94662b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 12:14:44 +0200 Subject: [PATCH 0446/1182] Test that `--ignore-netrc` doesn't interfere with `--auth` --- tests/test_auth.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_auth.py b/tests/test_auth.py index a4d95f8007..402834c2b1 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -2,6 +2,7 @@ import mock import pytest +from httpie.plugins.builtin import HTTPBasicAuth from httpie.utils import ExplicitNullAuth from utils import http, add_auth, HTTP_OK, MockEnvironment import httpie.input @@ -98,3 +99,11 @@ def test_ignore_netrc_null_auth(): env=MockEnvironment(), ) assert isinstance(args.auth, ExplicitNullAuth) + + +def test_ignore_netrc_together_with_auth(): + args = httpie.cli.parser.parse_args( + args=['--ignore-netrc', '--auth=username:password', 'example.org'], + env=MockEnvironment(), + ) + assert isinstance(args.auth, HTTPBasicAuth) From 3ea75a35770eda2590f9bbc409f9843077919b08 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 12:31:32 +0200 Subject: [PATCH 0447/1182] Document `$ALL_PROXY` support (close #676) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s been supported by python-requests since v2.11.0 (2016-08-08) https://github.com/psf/requests/blob/d79024f246d1037c4196da6027c2c2be08719c8d/HISTORY.md#2110-2016-08-08 --- README.rst | 12 +++++++----- httpie/cli.py | 3 ++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index e0f7a3207f..a9947f01cd 100644 --- a/README.rst +++ b/README.rst @@ -893,10 +893,10 @@ With Basic authentication: Environment variables --------------------- -You can also configure proxies by environment variables ``HTTP_PROXY`` and -``HTTPS_PROXY``, and the underlying Requests library will pick them up as well. -If you want to disable proxies configured through the environment variables for -certain hosts, you can specify them in ``NO_PROXY``. +You can also configure proxies by environment variables ``ALL_PROXY``, +``HTTP_PROXY`` and ``HTTPS_PROXY``, and the underlying Requests library will +pick them up as well. If you want to disable proxies configured through +the environment variables for certain hosts, you can specify them in ``NO_PROXY``. In your ``~/.bash_profile``: @@ -910,7 +910,9 @@ In your ``~/.bash_profile``: SOCKS ----- -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``: +Homebrew-installed HTTPie comes with SOCKS proxy support out of the box. +To enable SOCKS proxy support for non-Homebrew installations, you'll +might need to install ``requests[socks]`` manually using ``pip``: .. code-block:: bash diff --git a/httpie/cli.py b/httpie/cli.py index 5ff0465a9f..43121e2237 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -517,7 +517,8 @@ def __iter__(self): help=""" String mapping protocol to the URL of the proxy (e.g. http:http://foo.bar:3128). You can specify multiple proxies with - different protocols. + different protocols. The environment variables $ALL_PROXY, $HTTP_PROXY, + and $HTTPS_proxy are supported as well. """ ) From 466df77b6b28cf4d42d372d449acdebe51d0425f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 12:32:48 +0200 Subject: [PATCH 0448/1182] CHANGELOG --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index da48f090b5..d75682f076 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,7 @@ This project adheres to `Semantic Versioning `_. * Added ``--compress`` to allow request body compression. * Added ``--ignore-netrc`` to allow bypassing credentials from ``.netrc``. * Added ``https`` alias command with ``https://`` as the default scheme. +* Added ``$ALL_PROXY`` documentation. * Fixed an error when ``stdin`` was a closed fd. * Fixed an error when the config directory was not writeable. From aba3b1ec0108197f747b9266c7a622cb16e34fdc Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 15:17:10 +0200 Subject: [PATCH 0449/1182] Refactoring --- extras/brew-deps.py | 5 +- httpie/cli/__init__.py | 0 httpie/cli/argparser.py | 387 ++++++++++++++ httpie/cli/argtypes.py | 180 +++++++ httpie/cli/constants.py | 102 ++++ httpie/{cli.py => cli/definition.py} | 110 ++-- httpie/cli/dicts.py | 53 ++ httpie/cli/exceptions.py | 2 + httpie/cli/requestitems.py | 162 ++++++ httpie/client.py | 4 +- httpie/context.py | 2 +- httpie/core.py | 2 +- httpie/input.py | 770 --------------------------- httpie/models.py | 6 +- httpie/output/streams.py | 4 +- httpie/sessions.py | 5 +- httpie/utils.py | 16 + tests/test_auth.py | 12 +- tests/test_auth_plugins.py | 8 +- tests/test_cli.py | 159 +++--- tests/test_exit_status.py | 2 +- tests/test_httpie.py | 2 +- tests/test_sessions.py | 4 - tests/test_ssl.py | 2 +- tests/test_uploads.py | 2 +- 25 files changed, 1041 insertions(+), 960 deletions(-) create mode 100644 httpie/cli/__init__.py create mode 100644 httpie/cli/argparser.py create mode 100644 httpie/cli/argtypes.py create mode 100644 httpie/cli/constants.py rename httpie/{cli.py => cli/definition.py} (87%) create mode 100644 httpie/cli/dicts.py create mode 100644 httpie/cli/exceptions.py create mode 100644 httpie/cli/requestitems.py delete mode 100644 httpie/input.py diff --git a/extras/brew-deps.py b/extras/brew-deps.py index c5aeed6d0f..eb541ebd2f 100755 --- a/extras/brew-deps.py +++ b/extras/brew-deps.py @@ -25,7 +25,7 @@ def get_package_meta(package_name): - api_url = 'https://pypi.python.org/pypi/{}/json'.format(package_name) + api_url = f'https://pypi.python.org/pypi/{package_name}/json' resp = requests.get(api_url).json() hasher = hashlib.sha256() for release in resp['urls']: @@ -38,8 +38,7 @@ def get_package_meta(package_name): 'sha256': hasher.hexdigest(), } else: - raise RuntimeError( - '{}: download not found: {}'.format(package_name, resp)) + raise RuntimeError(f'{package_name}: download not found: {resp}') def main(): diff --git a/httpie/cli/__init__.py b/httpie/cli/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py new file mode 100644 index 0000000000..a48c98fd67 --- /dev/null +++ b/httpie/cli/argparser.py @@ -0,0 +1,387 @@ +import argparse +import errno +import os +import re +import sys +from argparse import RawDescriptionHelpFormatter +from textwrap import dedent +from urllib.parse import urlsplit + +from httpie.cli.argtypes import AuthCredentials, KeyValueArgType, parse_auth +from httpie.cli.constants import ( + HTTP_GET, HTTP_POST, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, + OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED, OUT_RESP_BODY, PRETTY_MAP, + PRETTY_STDOUT_TTY_ONLY, SEPARATOR_CREDENTIALS, SEPARATOR_GROUP_ALL_ITEMS, + SEPARATOR_GROUP_DATA_ITEMS, URL_SCHEME_RE, +) +from httpie.cli.exceptions import ParseError +from httpie.cli.requestitems import RequestItems +from httpie.context import Environment +from httpie.plugins import plugin_manager +from httpie.utils import ExplicitNullAuth, get_content_type + + +class HTTPieHelpFormatter(RawDescriptionHelpFormatter): + """A nicer help formatter. + + Help for arguments can be indented and contain new lines. + It will be de-dented and arguments in the help + will be separated by a blank line for better readability. + + + """ + + def __init__(self, max_help_position=6, *args, **kwargs): + # A smaller indent for args help. + kwargs['max_help_position'] = max_help_position + super().__init__(*args, **kwargs) + + def _split_lines(self, text, width): + text = dedent(text).strip() + '\n\n' + return text.splitlines() + + +class HTTPieArgumentParser(argparse.ArgumentParser): + """Adds additional logic to `argparse.ArgumentParser`. + + Handles all input (CLI args, file args, stdin), applies defaults, + and performs extra validation. + + """ + + def __init__(self, *args, formatter_class=HTTPieHelpFormatter, **kwargs): + kwargs['add_help'] = False + super().__init__(*args, formatter_class=formatter_class, **kwargs) + self.env = None + self.args = None + self.has_stdin_data = False + + # noinspection PyMethodOverriding + def parse_args( + self, + env: Environment, + program_name='http', + args=None, + namespace=None + ) -> argparse.Namespace: + self.env = env + self.args, no_options = super().parse_known_args(args, namespace) + + if self.args.debug: + self.args.traceback = True + + self.has_stdin_data = ( + self.env.stdin + and not self.args.ignore_stdin + and not self.env.stdin_isatty + ) + + # Arguments processing and environment setup. + self._apply_no_options(no_options) + self._validate_download_options() + self._setup_standard_streams() + self._process_output_options() + self._process_pretty_options() + self._guess_method() + self._parse_items() + + if self.has_stdin_data: + self._body_from_file(self.env.stdin) + if not URL_SCHEME_RE.match(self.args.url): + if os.path.basename(program_name) == 'https': + scheme = 'https://' + else: + scheme = self.args.default_scheme + "://" + + # See if we're using curl style shorthand for localhost (:3000/foo) + shorthand = re.match(r'^:(?!:)(\d*)(/?.*)$', self.args.url) + if shorthand: + port = shorthand.group(1) + rest = shorthand.group(2) + self.args.url = scheme + 'localhost' + if port: + self.args.url += ':' + port + self.args.url += rest + else: + self.args.url = scheme + self.args.url + self._process_auth() + + return self.args + + # noinspection PyShadowingBuiltins + def _print_message(self, message, file=None): + # Sneak in our stderr/stdout. + file = { + sys.stdout: self.env.stdout, + sys.stderr: self.env.stderr, + None: self.env.stderr + }.get(file, file) + if not hasattr(file, 'buffer') and isinstance(message, str): + message = message.encode(self.env.stdout_encoding) + super()._print_message(message, file) + + def _setup_standard_streams(self): + """ + Modify `env.stdout` and `env.stdout_isatty` based on args, if needed. + + """ + self.args.output_file_specified = bool(self.args.output_file) + if self.args.download: + # FIXME: Come up with a cleaner solution. + if not self.args.output_file and not self.env.stdout_isatty: + # Use stdout as the download output file. + self.args.output_file = self.env.stdout + # With `--download`, we write everything that would normally go to + # `stdout` to `stderr` instead. Let's replace the stream so that + # we don't have to use many `if`s throughout the codebase. + # The response body will be treated separately. + self.env.stdout = self.env.stderr + self.env.stdout_isatty = self.env.stderr_isatty + elif self.args.output_file: + # When not `--download`ing, then `--output` simply replaces + # `stdout`. The file is opened for appending, which isn't what + # we want in this case. + self.args.output_file.seek(0) + try: + self.args.output_file.truncate() + except IOError as e: + if e.errno == errno.EINVAL: + # E.g. /dev/null on Linux. + pass + else: + raise + self.env.stdout = self.args.output_file + self.env.stdout_isatty = False + + def _process_auth(self): + # TODO: refactor + self.args.auth_plugin = None + default_auth_plugin = plugin_manager.get_auth_plugins()[0] + auth_type_set = self.args.auth_type is not None + url = urlsplit(self.args.url) + + if self.args.auth is None and not auth_type_set: + if url.username is not None: + # Handle http://username:password@hostname/ + username = url.username + password = url.password or '' + self.args.auth = AuthCredentials( + key=username, + value=password, + sep=SEPARATOR_CREDENTIALS, + orig=SEPARATOR_CREDENTIALS.join([username, password]) + ) + + if self.args.auth is not None or auth_type_set: + if not self.args.auth_type: + self.args.auth_type = default_auth_plugin.auth_type + plugin = plugin_manager.get_auth_plugin(self.args.auth_type)() + + if plugin.auth_require and self.args.auth is None: + self.error('--auth required') + + plugin.raw_auth = self.args.auth + self.args.auth_plugin = plugin + already_parsed = isinstance(self.args.auth, AuthCredentials) + + if self.args.auth is None or not plugin.auth_parse: + self.args.auth = plugin.get_auth() + else: + if already_parsed: + # from the URL + credentials = self.args.auth + else: + credentials = parse_auth(self.args.auth) + + if (not credentials.has_password() + and plugin.prompt_password): + if self.args.ignore_stdin: + # Non-tty stdin read by now + self.error( + 'Unable to prompt for passwords because' + ' --ignore-stdin is set.' + ) + credentials.prompt_password(url.netloc) + self.args.auth = plugin.get_auth( + username=credentials.key, + password=credentials.value, + ) + if not self.args.auth and self.args.ignore_netrc: + # Set a no-op auth to force requests to ignore .netrc + # + self.args.auth = ExplicitNullAuth() + + def _apply_no_options(self, no_options): + """For every `--no-OPTION` in `no_options`, set `args.OPTION` to + its default value. This allows for un-setting of options, e.g., + specified in config. + + """ + invalid = [] + + for option in no_options: + if not option.startswith('--no-'): + invalid.append(option) + continue + + # --no-option => --option + inverted = '--' + option[5:] + for action in self._actions: + if inverted in action.option_strings: + setattr(self.args, action.dest, action.default) + break + else: + invalid.append(option) + + if invalid: + msg = 'unrecognized arguments: %s' + self.error(msg % ' '.join(invalid)) + + def _body_from_file(self, fd): + """There can only be one source of request data. + + Bytes are always read. + + """ + if self.args.data: + self.error('Request body (from stdin or a file) and request ' + '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): + """Set `args.method` if not specified to either POST or GET + based on whether the request has data or not. + + """ + if self.args.method is None: + # Invoked as `http URL'. + assert not self.args.request_items + if self.has_stdin_data: + self.args.method = HTTP_POST + else: + self.args.method = HTTP_GET + + # FIXME: False positive, e.g., "localhost" matches but is a valid URL. + elif not re.match('^[a-zA-Z]+$', self.args.method): + # Invoked as `http URL item+'. The URL is now in `args.method` + # and the first ITEM is now incorrectly in `args.url`. + try: + # Parse the URL as an ITEM and store it as the first ITEM arg. + self.args.request_items.insert(0, KeyValueArgType( + *SEPARATOR_GROUP_ALL_ITEMS).__call__(self.args.url)) + + except argparse.ArgumentTypeError as e: + if self.args.traceback: + raise + self.error(e.args[0]) + + else: + # Set the URL correctly + self.args.url = self.args.method + # Infer the method + has_data = ( + self.has_stdin_data + or any( + item.sep in SEPARATOR_GROUP_DATA_ITEMS + for item in self.args.request_items) + ) + self.args.method = HTTP_POST if has_data else HTTP_GET + + def _parse_items(self): + """ + Parse `args.request_items` into `args.headers`, `args.data`, + `args.params`, and `args.files`. + + """ + try: + request_items = RequestItems.from_args( + request_item_args=self.args.request_items, + as_form=self.args.form, + ) + except ParseError as e: + if self.args.traceback: + raise + self.error(e.args[0]) + else: + self.args.headers = request_items.headers + self.args.data = request_items.data + self.args.files = request_items.files + self.args.params = request_items.params + + if self.args.files and not self.args.form: + # `http url @/path/to/file` + file_fields = list(self.args.files.keys()) + if file_fields != ['']: + self.error( + 'Invalid file fields (perhaps you meant --form?): %s' + % ','.join(file_fields)) + + fn, fd, ct = self.args.files[''] + self.args.files = {} + + self._body_from_file(fd) + + if 'Content-Type' not in self.args.headers: + content_type = get_content_type(fn) + if content_type: + self.args.headers['Content-Type'] = content_type + + def _process_output_options(self): + """Apply defaults to output options, or validate the provided ones. + + The default output options are stdout-type-sensitive. + + """ + + def check_options(value, option): + unknown = set(value) - OUTPUT_OPTIONS + if unknown: + self.error('Unknown output options: {0}={1}'.format( + option, + ','.join(unknown) + )) + + if self.args.verbose: + self.args.all = True + + if self.args.output_options is None: + if self.args.verbose: + self.args.output_options = ''.join(OUTPUT_OPTIONS) + else: + self.args.output_options = ( + OUTPUT_OPTIONS_DEFAULT + if self.env.stdout_isatty + else OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED + ) + + if self.args.output_options_history is None: + self.args.output_options_history = self.args.output_options + + check_options(self.args.output_options, '--print') + check_options(self.args.output_options_history, '--history-print') + + if self.args.download and OUT_RESP_BODY in self.args.output_options: + # Response body is always downloaded with --download and it goes + # through a different routine, so we remove it. + self.args.output_options = str( + set(self.args.output_options) - set(OUT_RESP_BODY)) + + def _process_pretty_options(self): + 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): + self.error('Only terminal output can be colorized on Windows.') + else: + # noinspection PyTypeChecker + self.args.prettify = PRETTY_MAP[self.args.prettify] + + def _validate_download_options(self): + if not self.args.download: + if self.args.download_resume: + self.error('--continue only works with --download') + if self.args.download_resume and not ( + self.args.download and self.args.output_file): + self.error('--continue requires --output to be specified') diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py new file mode 100644 index 0000000000..803e066cf7 --- /dev/null +++ b/httpie/cli/argtypes.py @@ -0,0 +1,180 @@ +import argparse +import getpass +import os +import sys + +from httpie.cli.constants import SEPARATOR_CREDENTIALS +from httpie.sessions import VALID_SESSION_NAME_PATTERN + + +class KeyValueArg: + """Base key-value pair parsed from CLI.""" + + def __init__(self, key, value, sep, orig): + self.key = key + self.value = value + self.sep = sep + self.orig = orig + + def __eq__(self, other): + return self.__dict__ == other.__dict__ + + def __repr__(self): + return repr(self.__dict__) + + +class SessionNameValidator: + + def __init__(self, error_message): + self.error_message = error_message + + 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)): + raise argparse.ArgumentError(None, self.error_message) + return value + + +class Escaped(str): + """Represents an escaped character.""" + + +class KeyValueArgType: + """A key-value pair argument type used with `argparse`. + + Parses a key-value arg and constructs a `KeyValuArge` instance. + Used for headers, form data, and other key-value pair types. + + """ + + key_value_class = KeyValueArg + + def __init__(self, *separators): + self.separators = separators + self.special_characters = set('\\') + for separator in separators: + self.special_characters.update(separator) + + def __call__(self, string) -> KeyValueArg: + """Parse `string` and return `self.key_value_class()` instance. + + The best of `self.separators` is determined (first found, longest). + Back slash escaped characters aren't considered as separators + (or parts thereof). Literal back slash characters have to be escaped + as well (r'\\'). + + """ + + def tokenize(string): + r"""Tokenize `string`. There are only two token types - strings + and escaped characters: + + tokenize(r'foo\=bar\\baz') + => ['foo', Escaped('='), 'bar', Escaped('\\'), 'baz'] + + """ + tokens = [''] + characters = iter(string) + for char in characters: + if char == '\\': + char = next(characters, '') + if char not in self.special_characters: + tokens[-1] += '\\' + char + else: + tokens.extend([Escaped(char), '']) + else: + tokens[-1] += char + return tokens + + tokens = tokenize(string) + + # Sorting by length ensures that the longest one will be + # chosen as it will overwrite any shorter ones starting + # at the same position in the `found` dictionary. + separators = sorted(self.separators, key=len) + + for i, token in enumerate(tokens): + + if isinstance(token, Escaped): + continue + + found = {} + for sep in separators: + pos = token.find(sep) + if pos != -1: + found[pos] = sep + + if found: + # Starting first, longest separator found. + sep = found[min(found.keys())] + + key, value = token.split(sep, 1) + + # Any preceding tokens are part of the key. + key = ''.join(tokens[:i]) + key + + # Any following tokens are part of the value. + value += ''.join(tokens[i + 1:]) + + break + + else: + raise argparse.ArgumentTypeError( + u'"%s" is not a valid value' % string) + + return self.key_value_class( + key=key, value=value, sep=sep, orig=string) + + +class AuthCredentials(KeyValueArg): + """Represents parsed credentials.""" + + def _getpass(self, prompt): + # To allow mocking. + return getpass.getpass(str(prompt)) + + def has_password(self): + return self.value is not None + + def prompt_password(self, host): + try: + self.value = self._getpass( + 'http: password for %s@%s: ' % (self.key, host)) + except (EOFError, KeyboardInterrupt): + sys.stderr.write('\n') + sys.exit(0) + + +class AuthCredentialsArgType(KeyValueArgType): + """A key-value arg type that parses credentials.""" + + key_value_class = AuthCredentials + + def __call__(self, string): + """Parse credentials from `string`. + + ("username" or "username:password"). + + """ + try: + return super().__call__(string) + except argparse.ArgumentTypeError: + # No password provided, will prompt for it later. + return self.key_value_class( + key=string, + value=None, + sep=SEPARATOR_CREDENTIALS, + orig=string + ) + + +parse_auth = AuthCredentialsArgType(SEPARATOR_CREDENTIALS) + + +def readable_file_arg(filename): + try: + with open(filename, 'rb'): + return filename + except IOError as ex: + raise argparse.ArgumentTypeError('%s: %s' % (filename, ex.args[1])) diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py new file mode 100644 index 0000000000..8c0ad79f0a --- /dev/null +++ b/httpie/cli/constants.py @@ -0,0 +1,102 @@ +"""Parsing and processing of CLI input (args, auth credentials, files, stdin). + +""" +import re +import ssl + + +# TODO: Use MultiDict for headers once added to `requests`. +# https://github.com/jakubroztocil/httpie/issues/130 + + +# ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) +# +URL_SCHEME_RE = re.compile(r'^[a-z][a-z0-9.+-]*://', re.IGNORECASE) + +HTTP_POST = 'POST' +HTTP_GET = 'GET' + +# Various separators used in args +SEPARATOR_HEADER = ':' +SEPARATOR_HEADER_EMPTY = ';' +SEPARATOR_CREDENTIALS = ':' +SEPARATOR_PROXY = ':' +SEPARATOR_DATA_STRING = '=' +SEPARATOR_DATA_RAW_JSON = ':=' +SEPARATOR_FILE_UPLOAD = '@' +SEPARATOR_DATA_EMBED_FILE_CONTENTS = '=@' +SEPARATOR_DATA_EMBED_RAW_JSON_FILE = ':=@' +SEPARATOR_QUERY_PARAM = '==' + +# Separators that become request data +SEPARATOR_GROUP_DATA_ITEMS = frozenset({ + SEPARATOR_DATA_STRING, + SEPARATOR_DATA_RAW_JSON, + SEPARATOR_FILE_UPLOAD, + SEPARATOR_DATA_EMBED_FILE_CONTENTS, + SEPARATOR_DATA_EMBED_RAW_JSON_FILE +}) + +# Separators for items whose value is a filename to be embedded +SEPARATOR_GROUP_DATA_EMBED_ITEMS = frozenset({ + SEPARATOR_DATA_EMBED_FILE_CONTENTS, + SEPARATOR_DATA_EMBED_RAW_JSON_FILE, +}) + +# Separators for raw JSON items +SEPARATOR_GROUP_RAW_JSON_ITEMS = frozenset([ + SEPARATOR_DATA_RAW_JSON, + SEPARATOR_DATA_EMBED_RAW_JSON_FILE, +]) + +# Separators allowed in ITEM arguments +SEPARATOR_GROUP_ALL_ITEMS = frozenset({ + SEPARATOR_HEADER, + SEPARATOR_HEADER_EMPTY, + SEPARATOR_QUERY_PARAM, + SEPARATOR_DATA_STRING, + SEPARATOR_DATA_RAW_JSON, + SEPARATOR_FILE_UPLOAD, + SEPARATOR_DATA_EMBED_FILE_CONTENTS, + SEPARATOR_DATA_EMBED_RAW_JSON_FILE, +}) + +# Output options +OUT_REQ_HEAD = 'H' +OUT_REQ_BODY = 'B' +OUT_RESP_HEAD = 'h' +OUT_RESP_BODY = 'b' + +OUTPUT_OPTIONS = frozenset({ + OUT_REQ_HEAD, + OUT_REQ_BODY, + OUT_RESP_HEAD, + OUT_RESP_BODY +}) + +# Pretty +PRETTY_MAP = { + 'all': ['format', 'colors'], + 'colors': ['colors'], + 'format': ['format'], + 'none': [] +} +PRETTY_STDOUT_TTY_ONLY = object() + +# Defaults +OUTPUT_OPTIONS_DEFAULT = OUT_RESP_HEAD + OUT_RESP_BODY +OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED = OUT_RESP_BODY + +SSL_VERSION_ARG_MAPPING = { + 'ssl2.3': 'PROTOCOL_SSLv23', + 'ssl3': 'PROTOCOL_SSLv3', + 'tls1': 'PROTOCOL_TLSv1', + 'tls1.1': 'PROTOCOL_TLSv1_1', + 'tls1.2': 'PROTOCOL_TLSv1_2', + 'tls1.3': 'PROTOCOL_TLSv1_3', +} +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) +} diff --git a/httpie/cli.py b/httpie/cli/definition.py similarity index 87% rename from httpie/cli.py rename to httpie/cli/definition.py index 43121e2237..5a3fe6abe6 100644 --- a/httpie/cli.py +++ b/httpie/cli/definition.py @@ -2,52 +2,29 @@ CLI arguments definition. """ -from argparse import ( - RawDescriptionHelpFormatter, FileType, - OPTIONAL, ZERO_OR_MORE, SUPPRESS -) +from argparse import (FileType, OPTIONAL, SUPPRESS, ZERO_OR_MORE) from textwrap import dedent, wrap from httpie import __doc__, __version__ -from httpie.input import ( - HTTPieArgumentParser, KeyValueArgType, - SEP_PROXY, SEP_GROUP_ALL_ITEMS, - OUT_REQ_HEAD, OUT_REQ_BODY, OUT_RESP_HEAD, - OUT_RESP_BODY, OUTPUT_OPTIONS, - OUTPUT_OPTIONS_DEFAULT, PRETTY_MAP, - PRETTY_STDOUT_TTY_ONLY, SessionNameValidator, - readable_file_arg, SSL_VERSION_ARG_MAPPING +from httpie.cli.argparser import HTTPieArgumentParser +from httpie.cli.argtypes import ( + KeyValueArgType, SessionNameValidator, readable_file_arg, +) +from httpie.cli.constants import ( + OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, OUT_REQ_BODY, OUT_REQ_HEAD, + OUT_RESP_BODY, OUT_RESP_HEAD, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, + SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY, SSL_VERSION_ARG_MAPPING, ) from httpie.output.formatters.colors import ( - AVAILABLE_STYLES, DEFAULT_STYLE, AUTO_STYLE + AUTO_STYLE, AVAILABLE_STYLES, DEFAULT_STYLE, ) from httpie.plugins import plugin_manager from httpie.plugins.builtin import BuiltinAuthPlugin from httpie.sessions import DEFAULT_SESSIONS_DIR -class HTTPieHelpFormatter(RawDescriptionHelpFormatter): - """A nicer help formatter. - - Help for arguments can be indented and contain new lines. - It will be de-dented and arguments in the help - will be separated by a blank line for better readability. - - - """ - def __init__(self, max_help_position=6, *args, **kwargs): - # A smaller indent for args help. - kwargs['max_help_position'] = max_help_position - super().__init__(*args, **kwargs) - - def _split_lines(self, text, width): - text = dedent(text).strip() + '\n\n' - return text.splitlines() - - parser = HTTPieArgumentParser( prog='http', - formatter_class=HTTPieHelpFormatter, description='%s ' % __doc__.strip(), epilog=dedent(""" For every --OPTION there is also a --no-OPTION that reverts OPTION @@ -60,7 +37,6 @@ def _split_lines(self, text, width): """), ) - ####################################################################### # Positional arguments. ####################################################################### @@ -74,7 +50,7 @@ def _split_lines(self, text, width): """) ) positional.add_argument( - 'method', + dest='method', metavar='METHOD', nargs=OPTIONAL, default=None, @@ -90,7 +66,7 @@ def _split_lines(self, text, width): """ ) positional.add_argument( - 'url', + dest='url', metavar='URL', help=""" The scheme defaults to 'http://' if the URL does not include one. @@ -104,11 +80,11 @@ def _split_lines(self, text, width): """ ) positional.add_argument( - 'items', + dest='request_items', metavar='REQUEST_ITEM', nargs=ZERO_OR_MORE, default=None, - type=KeyValueArgType(*SEP_GROUP_ALL_ITEMS), + type=KeyValueArgType(*SEPARATOR_GROUP_ALL_ITEMS), help=r""" Optional key-value pairs to be included in the request. The separator used determines the type: @@ -149,7 +125,6 @@ def _split_lines(self, text, width): """ ) - ####################################################################### # Content type. ####################################################################### @@ -182,7 +157,6 @@ def _split_lines(self, text, width): """ ) - ####################################################################### # Content processing. ####################################################################### @@ -205,7 +179,6 @@ def _split_lines(self, text, width): """ ) - ####################################################################### # Output processing ####################################################################### @@ -251,7 +224,6 @@ def _split_lines(self, text, width): ) ) - ####################################################################### # Output options ####################################################################### @@ -261,49 +233,40 @@ def _split_lines(self, text, width): '--print', '-p', dest='output_options', metavar='WHAT', - help=""" + help=f""" String specifying what the output should contain: - '{req_head}' request headers - '{req_body}' request body - '{res_head}' response headers - '{res_body}' response body + '{OUT_REQ_HEAD}' request headers + '{OUT_REQ_BODY}' request body + '{OUT_RESP_HEAD}' response headers + '{OUT_RESP_BODY}' response body - The default behaviour is '{default}' (i.e., the response headers and body - is printed), if standard output is not redirected. If the output is piped - to another program or to a file, then only the response body is printed - by default. + The default behaviour is '{OUTPUT_OPTIONS_DEFAULT}' (i.e., the response + headers and body is printed), if standard output is not redirected. + If the output is piped to another program or to a file, then only the + response body is printed by default. """ - .format( - req_head=OUT_REQ_HEAD, - req_body=OUT_REQ_BODY, - res_head=OUT_RESP_HEAD, - res_body=OUT_RESP_BODY, - default=OUTPUT_OPTIONS_DEFAULT, - ) ) output_options.add_argument( '--headers', '-h', dest='output_options', action='store_const', const=OUT_RESP_HEAD, - help=""" - Print only the response headers. Shortcut for --print={0}. + help=f""" + Print only the response headers. Shortcut for --print={OUT_RESP_HEAD}. """ - .format(OUT_RESP_HEAD) ) output_options.add_argument( '--body', '-b', dest='output_options', action='store_const', const=OUT_RESP_BODY, - help=""" - Print only the response body. Shortcut for --print={0}. + help=f""" + Print only the response body. Shortcut for --print={OUT_RESP_BODY}. """ - .format(OUT_RESP_BODY) ) output_options.add_argument( @@ -315,8 +278,7 @@ def _split_lines(self, text, width): any intermediary requests/responses (such as redirects). It's a shortcut for: --all --print={0} - """ - .format(''.join(OUTPUT_OPTIONS)) + """.format(''.join(OUTPUT_OPTIONS)) ) output_options.add_argument( '--all', @@ -398,13 +360,12 @@ def _split_lines(self, text, width): """ ) - ####################################################################### # Sessions ####################################################################### -sessions = parser.add_argument_group(title='Sessions')\ - .add_mutually_exclusive_group(required=False) +sessions = parser.add_argument_group(title='Sessions') \ + .add_mutually_exclusive_group(required=False) session_name_validator = SessionNameValidator( 'Session name contains invalid characters.' @@ -414,17 +375,16 @@ def _split_lines(self, text, width): '--session', metavar='SESSION_NAME_OR_PATH', type=session_name_validator, - help=""" + help=f""" Create, or reuse and update a session. Within a session, custom headers, auth credential, as well as any cookies sent by the server persist between requests. Session files are stored in: - {session_dir}//.json. + {DEFAULT_SESSIONS_DIR}//.json. """ - .format(session_dir=DEFAULT_SESSIONS_DIR) ) sessions.add_argument( '--session-read-only', @@ -475,8 +435,7 @@ def __iter__(self): {types} - """ - .format(default=_auth_plugins[0].auth_type, types='\n '.join( + """.format(default=_auth_plugins[0].auth_type, types='\n '.join( '"{type}": {name}{package}{description}'.format( type=plugin.auth_type, name=plugin.name, @@ -513,7 +472,7 @@ def __iter__(self): default=[], action='append', metavar='PROTOCOL:PROXY_URL', - type=KeyValueArgType(SEP_PROXY), + type=KeyValueArgType(SEPARATOR_PROXY), help=""" String mapping protocol to the URL of the proxy (e.g. http:http://foo.bar:3128). You can specify multiple proxies with @@ -585,7 +544,6 @@ def __iter__(self): """ ) - ####################################################################### # SSL ####################################################################### diff --git a/httpie/cli/dicts.py b/httpie/cli/dicts.py new file mode 100644 index 0000000000..9ce7475a80 --- /dev/null +++ b/httpie/cli/dicts.py @@ -0,0 +1,53 @@ +from collections import OrderedDict + +from requests.structures import CaseInsensitiveDict + + +class RequestHeadersDict(CaseInsensitiveDict): + """ + Headers are case-insensitive and multiple values are currently not supported. + + """ + + +class RequestJSONDataDict(OrderedDict): + pass + + +class MultiValueOrderedDict(OrderedDict): + """Multi-value dict for URL parameters and form data.""" + + def __setitem__(self, key, value): + """ + If `key` is assigned more than once, `self[key]` holds a + `list` of all the values. + + This allows having multiple fields with the same name in form + data and URL params. + + """ + assert not isinstance(value, list) + if key not in self: + super().__setitem__(key, value) + else: + if not isinstance(self[key], list): + super().__setitem__(key, [self[key]]) + self[key].append(value) + + +class RequestQueryParamsDict(MultiValueOrderedDict): + pass + + +class RequestDataDict(MultiValueOrderedDict): + + def items(self): + for key, values in super(MultiValueOrderedDict, self).items(): + if not isinstance(values, list): + values = [values] + for value in values: + yield key, value + + +class RequestFilesDict(RequestDataDict): + pass diff --git a/httpie/cli/exceptions.py b/httpie/cli/exceptions.py new file mode 100644 index 0000000000..831cca9f04 --- /dev/null +++ b/httpie/cli/exceptions.py @@ -0,0 +1,2 @@ +class ParseError(Exception): + pass diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py new file mode 100644 index 0000000000..7fb7887a92 --- /dev/null +++ b/httpie/cli/requestitems.py @@ -0,0 +1,162 @@ +import os +from io import BytesIO +from typing import Callable, Dict, IO, List, Optional, Tuple, Union + +from httpie.cli.argtypes import KeyValueArg +from httpie.cli.constants import ( + SEPARATOR_DATA_EMBED_FILE_CONTENTS, SEPARATOR_DATA_EMBED_RAW_JSON_FILE, + SEPARATOR_DATA_RAW_JSON, + SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD, SEPARATOR_HEADER, + SEPARATOR_HEADER_EMPTY, + SEPARATOR_QUERY_PARAM, +) +from httpie.cli.dicts import ( + RequestDataDict, RequestFilesDict, RequestHeadersDict, RequestJSONDataDict, + RequestQueryParamsDict, +) +from httpie.cli.exceptions import ParseError +from httpie.utils import (get_content_type, load_json_preserve_order) + + +class RequestItems: + + def __init__(self, as_form=False, chunked=False): + self.headers = RequestHeadersDict() + self.data = RequestDataDict() if as_form else RequestJSONDataDict() + self.files = RequestFilesDict() + self.params = RequestQueryParamsDict() + self.chunked = chunked + + @classmethod + def from_args( + cls, + request_item_args: List[KeyValueArg], + as_form=False, + chunked=False + ) -> 'RequestItems': + instance = RequestItems(as_form=as_form, chunked=chunked) + rules: Dict[str, Tuple[Callable, dict]] = { + SEPARATOR_HEADER: ( + process_header_arg, + instance.headers, + ), + SEPARATOR_HEADER_EMPTY: ( + process_empty_header_arg, + instance.headers, + ), + SEPARATOR_QUERY_PARAM: ( + process_query_param_arg, + instance.params, + ), + SEPARATOR_FILE_UPLOAD: ( + process_file_upload_arg, + instance.files, + ), + SEPARATOR_DATA_STRING: ( + process_data_item_arg, + instance.data, + ), + SEPARATOR_DATA_EMBED_FILE_CONTENTS: ( + process_data_embed_file_contents_arg, + instance.data, + ), + SEPARATOR_DATA_RAW_JSON: ( + process_data_raw_json_embed_arg, + instance.data, + ), + SEPARATOR_DATA_EMBED_RAW_JSON_FILE: ( + process_data_embed_raw_json_file_arg, + instance.data, + ), + } + + for arg in request_item_args: + processor_func, target_dict = rules[arg.sep] + target_dict[arg.key] = processor_func(arg) + + return instance + + +JSONType = Union[str, bool, int, list, dict] + + +def process_header_arg(arg: KeyValueArg) -> Optional[str]: + return arg.value or None + + +def process_empty_header_arg(arg: KeyValueArg) -> str: + if arg.value: + raise ParseError( + 'Invalid item "%s" ' + '(to specify an empty header use `Header;`)' + % arg.orig + ) + return arg.value + + +def process_query_param_arg(arg: KeyValueArg) -> str: + return arg.value + + +def process_file_upload_arg(arg: KeyValueArg) -> Tuple[str, IO, str]: + filename = arg.value + try: + with open(os.path.expanduser(filename), 'rb') as f: + contents = f.read() + except IOError as e: + raise ParseError('"%s": %s' % (arg.orig, e)) + return ( + os.path.basename(filename), + BytesIO(contents), + get_content_type(filename), + ) + + +def parse_file_item_chunked(arg: KeyValueArg): + fn = arg.value + try: + f = open(os.path.expanduser(fn), 'rb') + except IOError as e: + raise ParseError('"%s": %s' % (arg.orig, e)) + return os.path.basename(fn), f, get_content_type(fn) + + +def process_data_item_arg(arg: KeyValueArg) -> str: + return arg.value + + +def process_data_embed_file_contents_arg(arg: KeyValueArg) -> str: + return load_text_file(arg) + + +def process_data_embed_raw_json_file_arg(arg: KeyValueArg) -> JSONType: + contents = load_text_file(arg) + value = load_json(arg, contents) + return value + + +def process_data_raw_json_embed_arg(arg: KeyValueArg) -> JSONType: + value = load_json(arg, arg.value) + return value + + +def load_text_file(item) -> str: + path = item.value + try: + with open(os.path.expanduser(path), 'rb') as f: + return f.read().decode('utf8') + except IOError as e: + raise ParseError('"%s": %s' % (item.orig, e)) + except UnicodeDecodeError: + raise ParseError( + '"%s": cannot embed the content of "%s",' + ' not a UTF8 or ASCII-encoded text file' + % (item.orig, item.value) + ) + + +def load_json(arg: KeyValueArg, contents: str) -> JSONType: + try: + return load_json_preserve_order(contents) + except ValueError as e: + raise ParseError('"%s": %s' % (arg.orig, e)) diff --git a/httpie/client.py b/httpie/client.py index 810938ee00..b79cb1be71 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -9,7 +9,7 @@ from httpie import sessions from httpie import __version__ -from httpie.input import SSL_VERSION_ARG_MAPPING +from httpie.cli.constants import SSL_VERSION_ARG_MAPPING from httpie.plugins import plugin_manager from httpie.utils import repr_dict_nice @@ -30,7 +30,7 @@ FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8' JSON_CONTENT_TYPE = 'application/json' -JSON_ACCEPT = '{0}, */*'.format(JSON_CONTENT_TYPE) +JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*' DEFAULT_UA = 'HTTPie/%s' % __version__ diff --git a/httpie/context.py b/httpie/context.py index dce4ba7cb9..7dc18a1524 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -101,4 +101,4 @@ def __str__(self): ) def __repr__(self): - return '<{0} {1}>'.format(type(self).__name__, str(self)) + return f'<{type(self).__name__} {self}>' diff --git a/httpie/core.py b/httpie/core.py index 1113b2edea..7ed5341ecf 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -201,7 +201,7 @@ def log_error(msg, *args, **kwargs): assert level in ['error', 'warning'] env.stderr.write('\nhttp: %s: %s\n' % (level, msg)) - from httpie.cli import parser + from httpie.cli.definition import parser if env.config.default_options: args = env.config.default_options + args diff --git a/httpie/input.py b/httpie/input.py deleted file mode 100644 index dae896926a..0000000000 --- a/httpie/input.py +++ /dev/null @@ -1,770 +0,0 @@ -"""Parsing and processing of CLI input (args, auth credentials, files, stdin). - -""" -import os -import ssl -import sys -import re -import errno -import mimetypes -import getpass -from io import BytesIO -from collections import namedtuple, OrderedDict -# noinspection PyCompatibility -import argparse - -# TODO: Use MultiDict for headers once added to `requests`. -# https://github.com/jakubroztocil/httpie/issues/130 -from urllib.parse import urlsplit - -from httpie.context import Environment -from httpie.plugins import plugin_manager -from requests.structures import CaseInsensitiveDict - -from httpie.sessions import VALID_SESSION_NAME_PATTERN -from httpie.utils import load_json_preserve_order, ExplicitNullAuth - - -# ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) -# -URL_SCHEME_RE = re.compile(r'^[a-z][a-z0-9.+-]*://', re.IGNORECASE) - -HTTP_POST = 'POST' -HTTP_GET = 'GET' - - -# Various separators used in args -SEP_HEADERS = ':' -SEP_HEADERS_EMPTY = ';' -SEP_CREDENTIALS = ':' -SEP_PROXY = ':' -SEP_DATA = '=' -SEP_DATA_RAW_JSON = ':=' -SEP_FILES = '@' -SEP_DATA_EMBED_FILE = '=@' -SEP_DATA_EMBED_RAW_JSON_FILE = ':=@' -SEP_QUERY = '==' - -# Separators that become request data -SEP_GROUP_DATA_ITEMS = frozenset([ - SEP_DATA, - SEP_DATA_RAW_JSON, - SEP_FILES, - SEP_DATA_EMBED_FILE, - SEP_DATA_EMBED_RAW_JSON_FILE -]) - -# Separators for items whose value is a filename to be embedded -SEP_GROUP_DATA_EMBED_ITEMS = frozenset([ - SEP_DATA_EMBED_FILE, - SEP_DATA_EMBED_RAW_JSON_FILE, -]) - -# Separators for raw JSON items -SEP_GROUP_RAW_JSON_ITEMS = frozenset([ - SEP_DATA_RAW_JSON, - SEP_DATA_EMBED_RAW_JSON_FILE, -]) - -# Separators allowed in ITEM arguments -SEP_GROUP_ALL_ITEMS = frozenset([ - SEP_HEADERS, - SEP_HEADERS_EMPTY, - SEP_QUERY, - SEP_DATA, - SEP_DATA_RAW_JSON, - SEP_FILES, - SEP_DATA_EMBED_FILE, - SEP_DATA_EMBED_RAW_JSON_FILE, -]) - - -# Output options -OUT_REQ_HEAD = 'H' -OUT_REQ_BODY = 'B' -OUT_RESP_HEAD = 'h' -OUT_RESP_BODY = 'b' - -OUTPUT_OPTIONS = frozenset([ - OUT_REQ_HEAD, - OUT_REQ_BODY, - OUT_RESP_HEAD, - OUT_RESP_BODY -]) - -# Pretty -PRETTY_MAP = { - 'all': ['format', 'colors'], - 'colors': ['colors'], - 'format': ['format'], - 'none': [] -} -PRETTY_STDOUT_TTY_ONLY = object() - - -# Defaults -OUTPUT_OPTIONS_DEFAULT = OUT_RESP_HEAD + OUT_RESP_BODY -OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED = OUT_RESP_BODY - - -SSL_VERSION_ARG_MAPPING = { - 'ssl2.3': 'PROTOCOL_SSLv23', - 'ssl3': 'PROTOCOL_SSLv3', - 'tls1': 'PROTOCOL_TLSv1', - 'tls1.1': 'PROTOCOL_TLSv1_1', - 'tls1.2': 'PROTOCOL_TLSv1_2', - 'tls1.3': 'PROTOCOL_TLSv1_3', -} -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(argparse.ArgumentParser): - """Adds additional logic to `argparse.ArgumentParser`. - - Handles all input (CLI args, file args, stdin), applies defaults, - and performs extra validation. - - """ - - def __init__(self, *args, **kwargs): - kwargs['add_help'] = False - super().__init__(*args, **kwargs) - self.env = None - self.args = None - self.has_stdin_data = False - - # noinspection PyMethodOverriding - def parse_args( - self, - env: Environment, - program_name='http', - args=None, - namespace=None - ) -> argparse.Namespace: - self.env = env - self.args, no_options = super().parse_known_args(args, namespace) - - if self.args.debug: - self.args.traceback = True - - self.has_stdin_data = ( - self.env.stdin - and not self.args.ignore_stdin - and not self.env.stdin_isatty - ) - - # Arguments processing and environment setup. - self._apply_no_options(no_options) - self._validate_download_options() - self._setup_standard_streams() - self._process_output_options() - self._process_pretty_options() - self._guess_method() - self._parse_items() - - if self.has_stdin_data: - self._body_from_file(self.env.stdin) - if not URL_SCHEME_RE.match(self.args.url): - if os.path.basename(program_name) == 'https': - scheme = 'https://' - else: - scheme = self.args.default_scheme + "://" - - # See if we're using curl style shorthand for localhost (:3000/foo) - shorthand = re.match(r'^:(?!:)(\d*)(/?.*)$', self.args.url) - if shorthand: - port = shorthand.group(1) - rest = shorthand.group(2) - self.args.url = scheme + 'localhost' - if port: - self.args.url += ':' + port - self.args.url += rest - else: - self.args.url = scheme + self.args.url - self._process_auth() - - return self.args - - # noinspection PyShadowingBuiltins - def _print_message(self, message, file=None): - # Sneak in our stderr/stdout. - file = { - sys.stdout: self.env.stdout, - sys.stderr: self.env.stderr, - None: self.env.stderr - }.get(file, file) - if not hasattr(file, 'buffer') and isinstance(message, str): - message = message.encode(self.env.stdout_encoding) - super()._print_message(message, file) - - def _setup_standard_streams(self): - """ - Modify `env.stdout` and `env.stdout_isatty` based on args, if needed. - - """ - self.args.output_file_specified = bool(self.args.output_file) - if self.args.download: - # FIXME: Come up with a cleaner solution. - if not self.args.output_file and not self.env.stdout_isatty: - # Use stdout as the download output file. - self.args.output_file = self.env.stdout - # With `--download`, we write everything that would normally go to - # `stdout` to `stderr` instead. Let's replace the stream so that - # we don't have to use many `if`s throughout the codebase. - # The response body will be treated separately. - self.env.stdout = self.env.stderr - self.env.stdout_isatty = self.env.stderr_isatty - elif self.args.output_file: - # When not `--download`ing, then `--output` simply replaces - # `stdout`. The file is opened for appending, which isn't what - # we want in this case. - self.args.output_file.seek(0) - try: - self.args.output_file.truncate() - except IOError as e: - if e.errno == errno.EINVAL: - # E.g. /dev/null on Linux. - pass - else: - raise - self.env.stdout = self.args.output_file - self.env.stdout_isatty = False - - def _process_auth(self): - # TODO: refactor - self.args.auth_plugin = None - default_auth_plugin = plugin_manager.get_auth_plugins()[0] - auth_type_set = self.args.auth_type is not None - url = urlsplit(self.args.url) - - if self.args.auth is None and not auth_type_set: - if url.username is not None: - # Handle http://username:password@hostname/ - username = url.username - password = url.password or '' - self.args.auth = AuthCredentials( - key=username, - value=password, - sep=SEP_CREDENTIALS, - orig=SEP_CREDENTIALS.join([username, password]) - ) - - if self.args.auth is not None or auth_type_set: - if not self.args.auth_type: - self.args.auth_type = default_auth_plugin.auth_type - plugin = plugin_manager.get_auth_plugin(self.args.auth_type)() - - if plugin.auth_require and self.args.auth is None: - self.error('--auth required') - - plugin.raw_auth = self.args.auth - self.args.auth_plugin = plugin - already_parsed = isinstance(self.args.auth, AuthCredentials) - - if self.args.auth is None or not plugin.auth_parse: - self.args.auth = plugin.get_auth() - else: - if already_parsed: - # from the URL - credentials = self.args.auth - else: - credentials = parse_auth(self.args.auth) - - if (not credentials.has_password() - and plugin.prompt_password): - if self.args.ignore_stdin: - # Non-tty stdin read by now - self.error( - 'Unable to prompt for passwords because' - ' --ignore-stdin is set.' - ) - credentials.prompt_password(url.netloc) - self.args.auth = plugin.get_auth( - username=credentials.key, - password=credentials.value, - ) - if not self.args.auth and self.args.ignore_netrc: - # Set a no-op auth to force requests to ignore .netrc - # - self.args.auth = ExplicitNullAuth() - - def _apply_no_options(self, no_options): - """For every `--no-OPTION` in `no_options`, set `args.OPTION` to - its default value. This allows for un-setting of options, e.g., - specified in config. - - """ - invalid = [] - - for option in no_options: - if not option.startswith('--no-'): - invalid.append(option) - continue - - # --no-option => --option - inverted = '--' + option[5:] - for action in self._actions: - if inverted in action.option_strings: - setattr(self.args, action.dest, action.default) - break - else: - invalid.append(option) - - if invalid: - msg = 'unrecognized arguments: %s' - self.error(msg % ' '.join(invalid)) - - def _body_from_file(self, fd): - """There can only be one source of request data. - - Bytes are always read. - - """ - if self.args.data: - self.error('Request body (from stdin or a file) and request ' - '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): - """Set `args.method` if not specified to either POST or GET - based on whether the request has data or not. - - """ - if self.args.method is None: - # Invoked as `http URL'. - assert not self.args.items - if self.has_stdin_data: - self.args.method = HTTP_POST - else: - self.args.method = HTTP_GET - - # FIXME: False positive, e.g., "localhost" matches but is a valid URL. - elif not re.match('^[a-zA-Z]+$', self.args.method): - # Invoked as `http URL item+'. The URL is now in `args.method` - # and the first ITEM is now incorrectly in `args.url`. - try: - # Parse the URL as an ITEM and store it as the first ITEM arg. - self.args.items.insert(0, KeyValueArgType( - *SEP_GROUP_ALL_ITEMS).__call__(self.args.url)) - - except argparse.ArgumentTypeError as e: - if self.args.traceback: - raise - self.error(e.args[0]) - - else: - # Set the URL correctly - self.args.url = self.args.method - # Infer the method - has_data = ( - self.has_stdin_data - 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 - - def _parse_items(self): - """Parse `args.items` into `args.headers`, `args.data`, `args.params`, - and `args.files`. - - """ - try: - items = parse_items( - items=self.args.items, - data_class=ParamsDict if self.args.form else OrderedDict - ) - except ParseError as e: - if self.args.traceback: - raise - self.error(e.args[0]) - else: - self.args.headers = items.headers - self.args.data = items.data - self.args.files = items.files - self.args.params = items.params - - if self.args.files and not self.args.form: - # `http url @/path/to/file` - file_fields = list(self.args.files.keys()) - if file_fields != ['']: - self.error( - 'Invalid file fields (perhaps you meant --form?): %s' - % ','.join(file_fields)) - - fn, fd, ct = self.args.files[''] - self.args.files = {} - - self._body_from_file(fd) - - if 'Content-Type' not in self.args.headers: - content_type = get_content_type(fn) - if content_type: - self.args.headers['Content-Type'] = content_type - - def _process_output_options(self): - """Apply defaults to output options, or validate the provided ones. - - The default output options are stdout-type-sensitive. - - """ - def check_options(value, option): - unknown = set(value) - OUTPUT_OPTIONS - if unknown: - self.error('Unknown output options: {0}={1}'.format( - option, - ','.join(unknown) - )) - - if self.args.verbose: - self.args.all = True - - if self.args.output_options is None: - if self.args.verbose: - self.args.output_options = ''.join(OUTPUT_OPTIONS) - else: - self.args.output_options = ( - OUTPUT_OPTIONS_DEFAULT - if self.env.stdout_isatty - else OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED - ) - - if self.args.output_options_history is None: - self.args.output_options_history = self.args.output_options - - check_options(self.args.output_options, '--print') - check_options(self.args.output_options_history, '--history-print') - - if self.args.download and OUT_RESP_BODY in self.args.output_options: - # Response body is always downloaded with --download and it goes - # through a different routine, so we remove it. - self.args.output_options = str( - set(self.args.output_options) - set(OUT_RESP_BODY)) - - def _process_pretty_options(self): - 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): - self.error('Only terminal output can be colorized on Windows.') - else: - # noinspection PyTypeChecker - self.args.prettify = PRETTY_MAP[self.args.prettify] - - def _validate_download_options(self): - if not self.args.download: - if self.args.download_resume: - self.error('--continue only works with --download') - if self.args.download_resume and not ( - self.args.download and self.args.output_file): - self.error('--continue requires --output to be specified') - - -class ParseError(Exception): - pass - - -class KeyValue: - """Base key-value pair parsed from CLI.""" - - def __init__(self, key, value, sep, orig): - self.key = key - self.value = value - self.sep = sep - self.orig = orig - - def __eq__(self, other): - return self.__dict__ == other.__dict__ - - def __repr__(self): - return repr(self.__dict__) - - -class SessionNameValidator: - - def __init__(self, error_message): - self.error_message = error_message - - 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)): - raise argparse.ArgumentError(None, self.error_message) - return value - - -class KeyValueArgType: - """A key-value pair argument type used with `argparse`. - - Parses a key-value arg and constructs a `KeyValue` instance. - Used for headers, form data, and other key-value pair types. - - """ - - key_value_class = KeyValue - - def __init__(self, *separators): - self.separators = separators - self.special_characters = set('\\') - for separator in separators: - self.special_characters.update(separator) - - def __call__(self, string): - """Parse `string` and return `self.key_value_class()` instance. - - The best of `self.separators` is determined (first found, longest). - Back slash escaped characters aren't considered as separators - (or parts thereof). Literal back slash characters have to be escaped - as well (r'\\'). - - """ - - class Escaped(str): - """Represents an escaped character.""" - - def tokenize(string): - r"""Tokenize `string`. There are only two token types - strings - and escaped characters: - - tokenize(r'foo\=bar\\baz') - => ['foo', Escaped('='), 'bar', Escaped('\\'), 'baz'] - - """ - tokens = [''] - characters = iter(string) - for char in characters: - if char == '\\': - char = next(characters, '') - if char not in self.special_characters: - tokens[-1] += '\\' + char - else: - tokens.extend([Escaped(char), '']) - else: - tokens[-1] += char - return tokens - - tokens = tokenize(string) - - # Sorting by length ensures that the longest one will be - # chosen as it will overwrite any shorter ones starting - # at the same position in the `found` dictionary. - separators = sorted(self.separators, key=len) - - for i, token in enumerate(tokens): - - if isinstance(token, Escaped): - continue - - found = {} - for sep in separators: - pos = token.find(sep) - if pos != -1: - found[pos] = sep - - if found: - # Starting first, longest separator found. - sep = found[min(found.keys())] - - key, value = token.split(sep, 1) - - # Any preceding tokens are part of the key. - key = ''.join(tokens[:i]) + key - - # Any following tokens are part of the value. - value += ''.join(tokens[i + 1:]) - - break - - else: - raise argparse.ArgumentTypeError( - u'"%s" is not a valid value' % string) - - return self.key_value_class( - key=key, value=value, sep=sep, orig=string) - - -class AuthCredentials(KeyValue): - """Represents parsed credentials.""" - - def _getpass(self, prompt): - # To allow mocking. - return getpass.getpass(str(prompt)) - - def has_password(self): - return self.value is not None - - def prompt_password(self, host): - try: - self.value = self._getpass( - 'http: password for %s@%s: ' % (self.key, host)) - except (EOFError, KeyboardInterrupt): - sys.stderr.write('\n') - sys.exit(0) - - -class AuthCredentialsArgType(KeyValueArgType): - """A key-value arg type that parses credentials.""" - - key_value_class = AuthCredentials - - def __call__(self, string): - """Parse credentials from `string`. - - ("username" or "username:password"). - - """ - try: - return super().__call__(string) - except argparse.ArgumentTypeError: - # No password provided, will prompt for it later. - return self.key_value_class( - key=string, - value=None, - sep=SEP_CREDENTIALS, - orig=string - ) - - -parse_auth = AuthCredentialsArgType(SEP_CREDENTIALS) - - -class RequestItemsDict(OrderedDict): - """Multi-value dict for URL parameters and form data.""" - - # noinspection PyMethodOverriding - def __setitem__(self, key, value): - """ If `key` is assigned more than once, `self[key]` holds a - `list` of all the values. - - This allows having multiple fields with the same name in form - data and URL params. - - """ - assert not isinstance(value, list) - if key not in self: - super().__setitem__(key, value) - else: - if not isinstance(self[key], list): - super().__setitem__(key, [self[key]]) - self[key].append(value) - - -class ParamsDict(RequestItemsDict): - pass - - -class DataDict(RequestItemsDict): - - def items(self): - for key, values in super().items(): - if not isinstance(values, list): - values = [values] - for value in values: - yield key, value - - -RequestItems = namedtuple('RequestItems', - ['headers', 'data', 'files', 'params']) - - -def get_content_type(filename): - """ - Return the content type for ``filename`` in format appropriate - for Content-Type headers, or ``None`` if the file type is unknown - to ``mimetypes``. - - """ - mime, encoding = mimetypes.guess_type(filename, strict=False) - if mime: - content_type = mime - if encoding: - content_type = '%s; charset=%s' % (mime, encoding) - return content_type - - -def parse_items(items, - headers_class=CaseInsensitiveDict, - data_class=OrderedDict, - files_class=DataDict, - params_class=ParamsDict): - """Parse `KeyValue` `items` into `data`, `headers`, `files`, - and `params`. - - """ - headers = [] - data = [] - files = [] - params = [] - for item in items: - value = item.value - if item.sep == SEP_HEADERS: - if value == '': - # No value => unset the header - value = None - target = headers - elif item.sep == SEP_HEADERS_EMPTY: - if item.value: - raise ParseError( - 'Invalid item "%s" ' - '(to specify an empty header use `Header;`)' - % item.orig - ) - target = headers - elif item.sep == SEP_QUERY: - target = params - elif item.sep == SEP_FILES: - try: - with open(os.path.expanduser(value), 'rb') as f: - value = (os.path.basename(value), - BytesIO(f.read()), - get_content_type(value)) - except IOError as e: - raise ParseError('"%s": %s' % (item.orig, e)) - target = files - - elif item.sep in SEP_GROUP_DATA_ITEMS: - - if item.sep in SEP_GROUP_DATA_EMBED_ITEMS: - try: - with open(os.path.expanduser(value), 'rb') as f: - value = f.read().decode('utf8') - except IOError as e: - raise ParseError('"%s": %s' % (item.orig, e)) - except UnicodeDecodeError: - raise ParseError( - '"%s": cannot embed the content of "%s",' - ' not a UTF8 or ASCII-encoded text file' - % (item.orig, item.value) - ) - - if item.sep in SEP_GROUP_RAW_JSON_ITEMS: - try: - value = load_json_preserve_order(value) - except ValueError as e: - raise ParseError('"%s": %s' % (item.orig, e)) - target = data - - else: - raise TypeError(item) - - target.append((item.key, value)) - - return RequestItems(headers_class(headers), - data_class(data), - files_class(files), - params_class(params)) - - -def readable_file_arg(filename): - try: - with open(filename, 'rb'): - return filename - except IOError as ex: - raise argparse.ArgumentTypeError('%s: %s' % (filename, ex.args[1])) diff --git a/httpie/models.py b/httpie/models.py index 17730eaa91..ab45ed6c70 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -61,11 +61,7 @@ def headers(self): 20: '2', }[original.version] - status_line = 'HTTP/{version} {status} {reason}'.format( - version=version, - status=original.status, - reason=original.reason - ) + status_line = f'HTTP/{version} {original.status} {original.reason}' headers = [status_line] try: # `original.msg` is a `http.client.HTTPMessage` on Python 3 diff --git a/httpie/output/streams.py b/httpie/output/streams.py index a3affdb068..0b27adc471 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -3,8 +3,8 @@ from httpie.context import Environment from httpie.models import HTTPRequest, HTTPResponse -from httpie.input import (OUT_REQ_BODY, OUT_REQ_HEAD, - OUT_RESP_HEAD, OUT_RESP_BODY) +from httpie.cli.constants import ( + OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_HEAD, OUT_RESP_BODY) from httpie.output.processing import Formatting, Conversion diff --git a/httpie/sessions.py b/httpie/sessions.py index 9f11c0b165..59ae734391 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -1,6 +1,7 @@ """Persistent, JSON-serialized sessions. """ +import argparse import re import os from pathlib import Path @@ -28,7 +29,7 @@ def get_response( requests_session: requests.Session, session_name: str, config_dir: Path, - args, + args: argparse.Namespace, read_only=False, ) -> requests.Response: """Like `client.get_responses`, but applies permanent @@ -167,7 +168,7 @@ def auth(self) -> Optional[AuthBase]: } else: if plugin.auth_parse: - from httpie.input import parse_auth + from httpie.cli.argtypes import parse_auth parsed = parse_auth(plugin.raw_auth) credentials = { 'username': parsed.key, diff --git a/httpie/utils.py b/httpie/utils.py index 453b67a1ed..39658fccfa 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -1,5 +1,6 @@ from __future__ import division import json +import mimetypes from collections import OrderedDict import requests.auth @@ -78,3 +79,18 @@ class ExplicitNullAuth(requests.auth.AuthBase): def __call__(self, r): return r + + +def get_content_type(filename): + """ + Return the content type for ``filename`` in format appropriate + for Content-Type headers, or ``None`` if the file type is unknown + to ``mimetypes``. + + """ + mime, encoding = mimetypes.guess_type(filename, strict=False) + if mime: + content_type = mime + if encoding: + content_type = '%s; charset=%s' % (mime, encoding) + return content_type diff --git a/tests/test_auth.py b/tests/test_auth.py index 402834c2b1..b555cd6ef0 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -5,8 +5,8 @@ from httpie.plugins.builtin import HTTPBasicAuth from httpie.utils import ExplicitNullAuth from utils import http, add_auth, HTTP_OK, MockEnvironment -import httpie.input -import httpie.cli +import httpie.cli.constants +import httpie.cli.definition def test_basic_auth(httpbin_both): @@ -24,7 +24,7 @@ def test_digest_auth(httpbin_both, argument_name): assert r.json == {'authenticated': True, 'user': 'user'} -@mock.patch('httpie.input.AuthCredentials._getpass', +@mock.patch('httpie.cli.argtypes.AuthCredentials._getpass', new=lambda self, prompt: 'password') def test_password_prompt(httpbin): r = http('--auth', 'user', @@ -60,7 +60,7 @@ def test_only_username_in_url(url): https://github.com/jakubroztocil/httpie/issues/242 """ - args = httpie.cli.parser.parse_args(args=[url], env=MockEnvironment()) + args = httpie.cli.definition.parser.parse_args(args=[url], env=MockEnvironment()) assert args.auth assert args.auth.username == 'username' assert args.auth.password == '' @@ -94,7 +94,7 @@ def test_ignore_netrc(httpbin_both): def test_ignore_netrc_null_auth(): - args = httpie.cli.parser.parse_args( + args = httpie.cli.definition.parser.parse_args( args=['--ignore-netrc', 'example.org'], env=MockEnvironment(), ) @@ -102,7 +102,7 @@ def test_ignore_netrc_null_auth(): def test_ignore_netrc_together_with_auth(): - args = httpie.cli.parser.parse_args( + args = httpie.cli.definition.parser.parse_args( args=['--ignore-netrc', '--auth=username:password', 'example.org'], env=MockEnvironment(), ) diff --git a/tests/test_auth_plugins.py b/tests/test_auth_plugins.py index 0d0fa26dbc..434d7024b7 100644 --- a/tests/test_auth_plugins.py +++ b/tests/test_auth_plugins.py @@ -1,6 +1,6 @@ from mock import mock -from httpie.input import SEP_CREDENTIALS +from httpie.cli.constants import SEPARATOR_CREDENTIALS from httpie.plugins import AuthPlugin, plugin_manager from utils import http, HTTP_OK @@ -83,7 +83,7 @@ class Plugin(AuthPlugin): auth_require = False def get_auth(self, username=None, password=None): - assert self.raw_auth == USERNAME + SEP_CREDENTIALS + PASSWORD + assert self.raw_auth == USERNAME + SEPARATOR_CREDENTIALS + PASSWORD assert username == USERNAME assert password == PASSWORD return basic_auth() @@ -95,7 +95,7 @@ def get_auth(self, username=None, password=None): '--auth-type', Plugin.auth_type, '--auth', - USERNAME + SEP_CREDENTIALS + PASSWORD, + USERNAME + SEPARATOR_CREDENTIALS + PASSWORD, ) assert HTTP_OK in r assert r.json == AUTH_OK @@ -103,7 +103,7 @@ def get_auth(self, username=None, password=None): plugin_manager.unregister(Plugin) -@mock.patch('httpie.input.AuthCredentials._getpass', +@mock.patch('httpie.cli.argtypes.AuthCredentials._getpass', new=lambda self, prompt: 'UNEXPECTED_PROMPT_RESPONSE') def test_auth_plugin_prompt_password_false(httpbin): diff --git a/tests/test_cli.py b/tests/test_cli.py index 1571c76c9f..2f428cb257 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,42 +1,42 @@ """CLI argument parsing related tests.""" -import json -# noinspection PyCompatibility import argparse +import json import pytest from requests.exceptions import InvalidSchema -from httpie import input -from httpie.input import KeyValue, KeyValueArgType, DataDict -from httpie import ExitStatus -from httpie.cli import parser -from utils import MockEnvironment, http, HTTP_OK +import httpie.cli.argparser from fixtures import ( - FILE_PATH_ARG, JSON_FILE_PATH_ARG, - JSON_FILE_CONTENT, FILE_CONTENT, FILE_PATH + FILE_CONTENT, FILE_PATH, FILE_PATH_ARG, JSON_FILE_CONTENT, + JSON_FILE_PATH_ARG, ) +from httpie import ExitStatus +from httpie.cli import constants +from httpie.cli.definition import parser +from httpie.cli.argtypes import KeyValueArg, KeyValueArgType +from httpie.cli.requestitems import RequestItems +from utils import HTTP_OK, MockEnvironment, http class TestItemParsing: - - key_value = KeyValueArgType(*input.SEP_GROUP_ALL_ITEMS) + key_value_arg = KeyValueArgType(*constants.SEPARATOR_GROUP_ALL_ITEMS) def test_invalid_items(self): items = ['no-separator'] for item in items: - pytest.raises(argparse.ArgumentTypeError, self.key_value, item) + pytest.raises(argparse.ArgumentTypeError, self.key_value_arg, item) def test_escape_separator(self): - items = input.parse_items([ + items = RequestItems.from_args([ # headers - self.key_value(r'foo\:bar:baz'), - self.key_value(r'jack\@jill:hill'), + self.key_value_arg(r'foo\:bar:baz'), + self.key_value_arg(r'jack\@jill:hill'), # data - self.key_value(r'baz\=bar=foo'), + self.key_value_arg(r'baz\=bar=foo'), # files - self.key_value(r'bar\@baz@%s' % FILE_PATH_ARG), + self.key_value_arg(r'bar\@baz@%s' % FILE_PATH_ARG), ]) # `requests.structures.CaseInsensitiveDict` => `dict` headers = dict(items.headers._store.values()) @@ -45,7 +45,9 @@ def test_escape_separator(self): 'foo:bar': 'baz', 'jack@jill': 'hill', } - assert items.data == {'baz=bar': 'foo'} + assert items.data == { + 'baz=bar': 'foo' + } assert 'bar@baz' in items.files @pytest.mark.parametrize(('string', 'key', 'sep', 'value'), [ @@ -54,31 +56,34 @@ def test_escape_separator(self): ('path\\==c:\\windows', 'path=', '=', 'c:\\windows'), ]) def test_backslash_before_non_special_character_does_not_escape( - self, string, key, sep, value): - expected = KeyValue(orig=string, key=key, sep=sep, value=value) - actual = self.key_value(string) + self, string, key, sep, value + ): + expected = KeyValueArg(orig=string, key=key, sep=sep, value=value) + actual = self.key_value_arg(string) assert actual == expected def test_escape_longsep(self): - items = input.parse_items([ - self.key_value(r'bob\:==foo'), + items = RequestItems.from_args([ + self.key_value_arg(r'bob\:==foo'), ]) - assert items.params == {'bob:': 'foo'} + assert items.params == { + 'bob:': 'foo' + } def test_valid_items(self): - items = input.parse_items([ - self.key_value('string=value'), - self.key_value('Header:value'), - self.key_value('Unset-Header:'), - self.key_value('Empty-Header;'), - self.key_value('list:=["a", 1, {}, false]'), - self.key_value('obj:={"a": "b"}'), - self.key_value('ed='), - self.key_value('bool:=true'), - self.key_value('file@' + FILE_PATH_ARG), - self.key_value('query==value'), - self.key_value('string-embed=@' + FILE_PATH_ARG), - self.key_value('raw-json-embed:=@' + JSON_FILE_PATH_ARG), + items = RequestItems.from_args([ + self.key_value_arg('string=value'), + self.key_value_arg('Header:value'), + self.key_value_arg('Unset-Header:'), + self.key_value_arg('Empty-Header;'), + self.key_value_arg('list:=["a", 1, {}, false]'), + self.key_value_arg('obj:={"a": "b"}'), + self.key_value_arg('ed='), + self.key_value_arg('bool:=true'), + self.key_value_arg('file@' + FILE_PATH_ARG), + self.key_value_arg('query==value'), + self.key_value_arg('string-embed=@' + FILE_PATH_ARG), + self.key_value_arg('raw-json-embed:=@' + JSON_FILE_PATH_ARG), ]) # Parsed headers @@ -99,12 +104,16 @@ def test_valid_items(self): "string": "value", "bool": True, "list": ["a", 1, {}, False], - "obj": {"a": "b"}, + "obj": { + "a": "b" + }, "string-embed": FILE_CONTENT, } # Parsed query string parameters - assert items.params == {'query': 'value'} + assert items.params == { + 'query': 'value' + } # Parsed file fields assert 'file' in items.files @@ -112,17 +121,19 @@ def test_valid_items(self): decode('utf8') == FILE_CONTENT) def test_multiple_file_fields_with_same_field_name(self): - items = input.parse_items([ - self.key_value('file_field@' + FILE_PATH_ARG), - self.key_value('file_field@' + FILE_PATH_ARG), + items = RequestItems.from_args([ + self.key_value_arg('file_field@' + FILE_PATH_ARG), + self.key_value_arg('file_field@' + FILE_PATH_ARG), ]) assert len(items.files['file_field']) == 2 def test_multiple_text_fields_with_same_field_name(self): - items = input.parse_items( - [self.key_value('text_field=a'), - self.key_value('text_field=b')], - data_class=DataDict + items = RequestItems.from_args( + request_item_args=[ + self.key_value_arg('text_field=a'), + self.key_value_arg('text_field=b') + ], + as_form=True, ) assert items.data['text_field'] == ['a', 'b'] assert list(items.data.items()) == [ @@ -206,92 +217,80 @@ def test_dont_expand_full_ipv6_as_shorthand(self): class TestArgumentParser: def setup_method(self, method): - self.parser = input.HTTPieArgumentParser() + self.parser = httpie.cli.argparser.HTTPieArgumentParser() def test_guess_when_method_set_and_valid(self): self.parser.args = argparse.Namespace() self.parser.args.method = 'GET' self.parser.args.url = 'http://example.com/' - self.parser.args.items = [] + self.parser.args.request_items = [] self.parser.args.ignore_stdin = False - self.parser.env = MockEnvironment() - self.parser._guess_method() - assert self.parser.args.method == 'GET' assert self.parser.args.url == 'http://example.com/' - assert self.parser.args.items == [] + assert self.parser.args.request_items == [] def test_guess_when_method_not_set(self): self.parser.args = argparse.Namespace() self.parser.args.method = None self.parser.args.url = 'http://example.com/' - self.parser.args.items = [] + self.parser.args.request_items = [] self.parser.args.ignore_stdin = False self.parser.env = MockEnvironment() - self.parser._guess_method() - assert self.parser.args.method == 'GET' assert self.parser.args.url == 'http://example.com/' - assert self.parser.args.items == [] + assert self.parser.args.request_items == [] def test_guess_when_method_set_but_invalid_and_data_field(self): self.parser.args = argparse.Namespace() self.parser.args.method = 'http://example.com/' self.parser.args.url = 'data=field' - self.parser.args.items = [] + self.parser.args.request_items = [] self.parser.args.ignore_stdin = False self.parser.env = MockEnvironment() self.parser._guess_method() - assert self.parser.args.method == 'POST' assert self.parser.args.url == 'http://example.com/' - assert self.parser.args.items == [ - KeyValue(key='data', - value='field', - sep='=', - orig='data=field') + assert self.parser.args.request_items == [ + KeyValueArg(key='data', + value='field', + sep='=', + orig='data=field') ] def test_guess_when_method_set_but_invalid_and_header_field(self): self.parser.args = argparse.Namespace() self.parser.args.method = 'http://example.com/' self.parser.args.url = 'test:header' - self.parser.args.items = [] + self.parser.args.request_items = [] self.parser.args.ignore_stdin = False - self.parser.env = MockEnvironment() - self.parser._guess_method() - assert self.parser.args.method == 'GET' assert self.parser.args.url == 'http://example.com/' - assert self.parser.args.items, [ - KeyValue(key='test', - value='header', - sep=':', - orig='test:header') + assert self.parser.args.request_items, [ + KeyValueArg(key='test', + value='header', + sep=':', + orig='test:header') ] def test_guess_when_method_set_but_invalid_and_item_exists(self): self.parser.args = argparse.Namespace() self.parser.args.method = 'http://example.com/' self.parser.args.url = 'new_item=a' - self.parser.args.items = [ - KeyValue( + self.parser.args.request_items = [ + KeyValueArg( key='old_item', value='b', sep='=', orig='old_item=b') ] self.parser.args.ignore_stdin = False - self.parser.env = MockEnvironment() - self.parser._guess_method() - - assert self.parser.args.items, [ - KeyValue(key='new_item', value='a', sep='=', orig='new_item=a'), - KeyValue( + assert self.parser.args.request_items, [ + KeyValueArg(key='new_item', value='a', sep='=', orig='new_item=a'), + KeyValueArg( key='old_item', value='b', sep='=', orig='old_item=b'), ] diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index 02e9bd73c9..77878222f6 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -5,7 +5,7 @@ def test_keyboard_interrupt_during_arg_parsing_exit_status(httpbin): - with mock.patch('httpie.cli.parser.parse_args', + with mock.patch('httpie.cli.definition.parser.parse_args', side_effect=KeyboardInterrupt()): r = http('GET', httpbin.url + '/get', error_exit_ok=True) assert r.exit_status == ExitStatus.ERROR_CTRL_C diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 797391a959..d17e7c735b 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -1,7 +1,7 @@ """High-level tests.""" import pytest -from httpie.input import ParseError +from httpie.cli.exceptions import ParseError from utils import MockEnvironment, http, HTTP_OK from fixtures import FILE_PATH, FILE_CONTENT diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 08a7f0fc71..765ca7b298 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -140,10 +140,6 @@ def test_session_by_path(self, httpbin): assert HTTP_OK in r2 assert r2.json['headers']['Foo'] == 'Bar' - @pytest.mark.skipif( - sys.version_info >= (3,), - reason="This test fails intermittently on Python 3 - " - "see https://github.com/jakubroztocil/httpie/issues/282") def test_session_unicode(self, httpbin): self.start_session(httpbin) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 607c47264d..3437d6eb2a 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -5,7 +5,7 @@ import requests.exceptions from httpie import ExitStatus -from httpie.input import SSL_VERSION_ARG_MAPPING +from httpie.cli.constants import SSL_VERSION_ARG_MAPPING from utils import HTTP_OK, TESTS_ROOT, http diff --git a/tests/test_uploads.py b/tests/test_uploads.py index e65fde0e04..ba881014bc 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -2,7 +2,7 @@ import pytest -from httpie.input import ParseError +from httpie.cli.exceptions import ParseError from utils import MockEnvironment, http, HTTP_OK from fixtures import FILE_PATH_ARG, FILE_PATH, FILE_CONTENT From 224519e0e251cee5ecefeebff0b593363137accf Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 17:52:56 +0200 Subject: [PATCH 0450/1182] Fix --ssl with --compress; refactor client --- httpie/client.py | 87 +++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index b79cb1be71..bb5410de10 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -1,19 +1,20 @@ +import argparse +import http.client import json import sys +import zlib +from contextlib import contextmanager +from pathlib import Path -import http.client import requests -from contextlib import contextmanager from requests.adapters import HTTPAdapter -from requests.structures import CaseInsensitiveDict -from httpie import sessions -from httpie import __version__ +from httpie import __version__, sessions from httpie.cli.constants import SSL_VERSION_ARG_MAPPING +from httpie.cli.dicts import RequestHeadersDict from httpie.plugins import plugin_manager from httpie.utils import repr_dict_nice -import zlib try: # https://urllib3.readthedocs.io/en/latest/security.html @@ -31,7 +32,7 @@ FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8' JSON_CONTENT_TYPE = 'application/json' JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*' -DEFAULT_UA = 'HTTPie/%s' % __version__ +DEFAULT_UA = f'HTTPie/{__version__}' # noinspection PyProtectedMember @@ -48,46 +49,40 @@ def max_headers(limit): class HTTPieHTTPAdapter(HTTPAdapter): - def __init__(self, ssl_version=None, **kwargs): + def __init__(self, ssl_version=None, compress=0, **kwargs): self._ssl_version = ssl_version + self._compress = compress super().__init__(**kwargs) def init_poolmanager(self, *args, **kwargs): kwargs['ssl_version'] = self._ssl_version super().init_poolmanager(*args, **kwargs) - -class ContentCompressionHttpAdapter(HTTPAdapter): - - def __init__(self, compress, **kwargs): - self.compress = compress - super().__init__(**kwargs) - - def send(self, request, **kwargs): - if request.body and self.compress > 0: - deflater = zlib.compressobj() - if isinstance(request.body, bytes): - deflated_data = deflater.compress(request.body) - else: - deflated_data = deflater.compress(request.body.encode()) - deflated_data += deflater.flush() - if len(deflated_data) < len(request.body) or self.compress > 1: - request.body = deflated_data - request.headers['Content-Encoding'] = 'deflate' - request.headers['Content-Length'] = str(len(deflated_data)) + def send(self, request: requests.PreparedRequest, **kwargs): + if self._compress and request.body: + self._compress_body(request, self._compress) return super().send(request, **kwargs) + @staticmethod + def _compress_body(request: requests.PreparedRequest, compress: int): + deflater = zlib.compressobj() + if isinstance(request.body, bytes): + deflated_data = deflater.compress(request.body) + else: + deflated_data = deflater.compress(request.body.encode()) + deflated_data += deflater.flush() + if len(deflated_data) < len(request.body) or compress > 1: + request.body = deflated_data + request.headers['Content-Encoding'] = 'deflate' + request.headers['Content-Length'] = str(len(deflated_data)) + -def get_requests_session(ssl_version, compress): +def get_requests_session(ssl_version: str, compress: int) -> requests.Session: requests_session = requests.Session() - requests_session.mount( - 'https://', - HTTPieHTTPAdapter(ssl_version=ssl_version) - ) - if compress: - adapter = ContentCompressionHttpAdapter(compress) - for prefix in ['http://', 'https://']: - requests_session.mount(prefix, adapter) + adapter = HTTPieHTTPAdapter(ssl_version=ssl_version, compress=compress) + for prefix in ['http://', 'https://']: + requests_session.mount(prefix, adapter) + for cls in plugin_manager.get_transport_plugins(): transport_plugin = cls() requests_session.mount(prefix=transport_plugin.prefix, @@ -95,7 +90,10 @@ def get_requests_session(ssl_version, compress): return requests_session -def get_response(args, config_dir): +def get_response( + args: argparse.Namespace, + config_dir: Path +) -> requests.Response: """Send the request and return a `request.Response`.""" ssl_version = None @@ -123,32 +121,29 @@ def get_response(args, config_dir): return response -def dump_request(kwargs): +def dump_request(kwargs: dict): sys.stderr.write('\n>>> requests.request(**%s)\n\n' % repr_dict_nice(kwargs)) -def finalize_headers(headers): - final_headers = {} +def finalize_headers(headers: RequestHeadersDict) -> RequestHeadersDict: + final_headers = RequestHeadersDict() for name, value in headers.items(): if value is not None: - # >leading or trailing LWS MAY be removed without # >changing the semantics of the field value" # -https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html # Also, requests raises `InvalidHeader` for leading spaces. value = value.strip() - if isinstance(value, str): # See: https://github.com/jakubroztocil/httpie/issues/212 value = value.encode('utf8') - final_headers[name] = value return final_headers -def get_default_headers(args): - default_headers = CaseInsensitiveDict({ +def get_default_headers(args: argparse.Namespace) -> RequestHeadersDict: + default_headers = RequestHeadersDict({ 'User-Agent': DEFAULT_UA }) @@ -165,7 +160,7 @@ def get_default_headers(args): return default_headers -def get_requests_kwargs(args, base_headers=None): +def get_requests_kwargs(args: argparse.Namespace, base_headers=None) -> dict: """ Translate our `args` into `requests.request` keyword arguments. From 9da5c41704fbdfcb9eb626441d328d62ce19a3fa Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 18:00:03 +0200 Subject: [PATCH 0451/1182] Improve --debug output formatting --- httpie/client.py | 6 +++--- httpie/context.py | 10 +++++----- httpie/utils.py | 17 +++-------------- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index bb5410de10..49d0406392 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -13,7 +13,7 @@ from httpie.cli.constants import SSL_VERSION_ARG_MAPPING from httpie.cli.dicts import RequestHeadersDict from httpie.plugins import plugin_manager -from httpie.utils import repr_dict_nice +from httpie.utils import repr_dict try: @@ -122,8 +122,8 @@ def get_response( def dump_request(kwargs: dict): - sys.stderr.write('\n>>> requests.request(**%s)\n\n' - % repr_dict_nice(kwargs)) + sys.stderr.write( + f'\n>>> requests.request(**{repr_dict(kwargs)})\n\n') def finalize_headers(headers: RequestHeadersDict) -> RequestHeadersDict: diff --git a/httpie/context.py b/httpie/context.py index 7dc18a1524..4c19fc2f3b 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -11,7 +11,7 @@ from httpie.compat import is_windows from httpie.config import DEFAULT_CONFIG_DIR, Config -from httpie.utils import repr_dict_nice +from httpie.utils import repr_dict class Environment: @@ -94,11 +94,11 @@ def __str__(self): actual = dict(defaults) actual.update(self.__dict__) actual['config'] = self.config - return repr_dict_nice(dict( - (key, value) + return repr_dict({ + key: value for key, value in actual.items() - if not key.startswith('_')) - ) + if not key.startswith('_') + }) def __repr__(self): return f'<{type(self).__name__} {self}>' diff --git a/httpie/utils.py b/httpie/utils.py index 39658fccfa..c5b60216b2 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -2,6 +2,7 @@ import json import mimetypes from collections import OrderedDict +from pprint import pformat import requests.auth @@ -10,20 +11,8 @@ def load_json_preserve_order(s): return json.loads(s, object_pairs_hook=OrderedDict) -def repr_dict_nice(d): - def prepare_dict(d): - for k, v in d.items(): - if isinstance(v, dict): - v = dict(prepare_dict(v)) - elif isinstance(v, bytes): - v = v.decode('utf8') - elif not isinstance(v, (int, str)): - v = repr(v) - yield k, v - return json.dumps( - dict(prepare_dict(d)), - indent=4, sort_keys=True, - ) +def repr_dict(d: dict) -> str: + return pformat(d) def humanize_bytes(n, precision=2): From 82a224a65897086efcdb8923c7a4788906897da9 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 18:00:34 +0200 Subject: [PATCH 0452/1182] CHANGELOG --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d75682f076..76f6f15219 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,6 +16,7 @@ This project adheres to `Semantic Versioning `_. * Added ``--ignore-netrc`` to allow bypassing credentials from ``.netrc``. * Added ``https`` alias command with ``https://`` as the default scheme. * Added ``$ALL_PROXY`` documentation. +* Improved ``--debug`` output formatting. * Fixed an error when ``stdin`` was a closed fd. * Fixed an error when the config directory was not writeable. From e8ef5a783f2541c3fec3a45c80083a99a2fd6af4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 18:21:10 +0200 Subject: [PATCH 0453/1182] Annotate and refactor streams.py --- CHANGELOG.rst | 2 +- httpie/cli/requestitems.py | 2 +- httpie/output/streams.py | 143 +++++++++++++++++++++++-------------- 3 files changed, 91 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 76f6f15219..282d64daef 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,9 +16,9 @@ This project adheres to `Semantic Versioning `_. * Added ``--ignore-netrc`` to allow bypassing credentials from ``.netrc``. * Added ``https`` alias command with ``https://`` as the default scheme. * Added ``$ALL_PROXY`` documentation. -* Improved ``--debug`` output formatting. * Fixed an error when ``stdin`` was a closed fd. * Fixed an error when the config directory was not writeable. +* Improved ``--debug`` output formatting. `1.0.3`_ (2019-08-26) diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index 7fb7887a92..c0293bf90b 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -144,7 +144,7 @@ def load_text_file(item) -> str: path = item.value try: with open(os.path.expanduser(path), 'rb') as f: - return f.read().decode('utf8') + return f.read().decode() except IOError as e: raise ParseError('"%s": %s' % (item.orig, e)) except UnicodeDecodeError: diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 0b27adc471..6da36e14db 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -1,11 +1,15 @@ +import argparse from itertools import chain -from functools import partial +from typing import Callable, IO, Iterable, TextIO, Tuple, Type, Union + +import requests -from httpie.context import Environment -from httpie.models import HTTPRequest, HTTPResponse from httpie.cli.constants import ( - OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_HEAD, OUT_RESP_BODY) -from httpie.output.processing import Formatting, Conversion + OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_BODY, OUT_RESP_HEAD, +) +from httpie.context import Environment +from httpie.models import HTTPMessage, HTTPRequest, HTTPResponse +from httpie.output.processing import Conversion, Formatting BINARY_SUPPRESSED_NOTICE = ( @@ -23,7 +27,11 @@ class BinarySuppressedError(Exception): message = BINARY_SUPPRESSED_NOTICE -def write_stream(stream, outfile, flush): +def write_stream( + stream: 'BaseStream', + outfile: Union[IO, TextIO], + flush: bool +): """Write the output stream.""" try: # Writing bytes so we use the buffer interface (Python 3). @@ -37,7 +45,11 @@ def write_stream(stream, outfile, flush): outfile.flush() -def write_stream_with_colors_win_py3(stream, outfile, flush): +def write_stream_with_colors_win_py3( + stream: 'BaseStream', + outfile: TextIO, + flush: bool +): """Like `write`, but colorized chunks are written as text directly to `outfile` to ensure it gets processed by colorama. Applies only to Windows with Python 3 and colorized terminal output. @@ -54,7 +66,13 @@ def write_stream_with_colors_win_py3(stream, outfile, flush): outfile.flush() -def build_output_stream(args, env, request, response, output_options): +def build_output_stream( + args: argparse.Namespace, + env: Environment, + request: requests.Request, + response: requests.Response, + output_options: str +) -> Iterable[bytes]: """Build and return a chain of iterators over the `request`-`response` exchange each of which yields `bytes` chunks. @@ -67,23 +85,32 @@ def build_output_stream(args, env, request, response, output_options): resp = resp_h or resp_b output = [] - Stream = get_stream_type(env, args) + stream_class, stream_kwargs = get_stream_type_and_kwargs( + env=env, args=args) if req: - output.append(Stream( - msg=HTTPRequest(request), - with_headers=req_h, - with_body=req_b)) + output.append( + stream_class( + msg=HTTPRequest(request), + with_headers=req_h, + with_body=req_b, + **stream_kwargs, + ) + ) if req_b and resp: # Request/Response separator. output.append([b'\n\n']) if resp: - output.append(Stream( - msg=HTTPResponse(response), - with_headers=resp_h, - with_body=resp_b)) + output.append( + stream_class( + msg=HTTPResponse(response), + with_headers=resp_h, + with_body=resp_b, + **stream_kwargs, + ) + ) if env.stdout_isatty and resp_b: # Ensure a blank line after the response body. @@ -93,42 +120,52 @@ def build_output_stream(args, env, request, response, output_options): return chain(*output) -def get_stream_type(env, args): - """Pick the right stream type based on `env` and `args`. - Wrap it in a partial with the type-specific args so that - we don't need to think what stream we are dealing with. +def get_stream_type_and_kwargs( + env: Environment, + args: argparse.Namespace +) -> Tuple[Type['BaseStream'], dict]: + """Pick the right stream type and kwargs for it based on `env` and `args`. """ if not env.stdout_isatty and not args.prettify: - Stream = partial( - RawStream, - chunk_size=RawStream.CHUNK_SIZE_BY_LINE - if args.stream - else RawStream.CHUNK_SIZE - ) + stream_class = RawStream + stream_kwargs = { + 'chunk_size': ( + RawStream.CHUNK_SIZE_BY_LINE + if args.stream + else RawStream.CHUNK_SIZE + ) + } elif args.prettify: - Stream = partial( - PrettyStream if args.stream else BufferedPrettyStream, - env=env, - conversion=Conversion(), - formatting=Formatting( + stream_class = PrettyStream if args.stream else BufferedPrettyStream + stream_kwargs = { + 'env': env, + 'conversion': Conversion(), + 'formatting': Formatting( env=env, groups=args.prettify, color_scheme=args.style, explicit_json=args.json, - ), - ) + ) + } else: - Stream = partial(EncodedStream, env=env) + stream_class = EncodedStream + stream_kwargs = { + 'env': env + } - return Stream + return stream_class, stream_kwargs class BaseStream: """Base HTTP message output stream class.""" - def __init__(self, msg, with_headers=True, with_body=True, - on_body_chunk_downloaded=None): + def __init__( + self, + msg: HTTPMessage, + with_headers=True, with_body=True, + on_body_chunk_downloaded: Callable[[bytes], None] = None + ): """ :param msg: a :class:`models.HTTPMessage` subclass :param with_headers: if `True`, headers will be included @@ -141,15 +178,15 @@ def __init__(self, msg, with_headers=True, with_body=True, self.with_body = with_body self.on_body_chunk_downloaded = on_body_chunk_downloaded - def get_headers(self): + def get_headers(self) -> bytes: """Return the headers' bytes.""" return self.msg.headers.encode('utf8') - def iter_body(self): + def iter_body(self) -> Iterable[bytes]: """Return an iterator over the message body.""" raise NotImplementedError() - def __iter__(self): + def __iter__(self) -> Iterable[bytes]: """Return an iterator over `self.msg`.""" if self.with_headers: yield self.get_headers() @@ -177,7 +214,7 @@ def __init__(self, chunk_size=CHUNK_SIZE, **kwargs): super().__init__(**kwargs) self.chunk_size = chunk_size - def iter_body(self): + def iter_body(self) -> Iterable[bytes]: return self.msg.iter_body(self.chunk_size) @@ -192,26 +229,20 @@ class EncodedStream(BaseStream): CHUNK_SIZE = 1 def __init__(self, env=Environment(), **kwargs): - super().__init__(**kwargs) - if env.stdout_isatty: # Use the encoding supported by the terminal. output_encoding = env.stdout_encoding else: # Preserve the message encoding. output_encoding = self.msg.encoding - # Default to utf8 when unsure. self.output_encoding = output_encoding or 'utf8' - def iter_body(self): - + def iter_body(self) -> Iterable[bytes]: for line, lf in self.msg.iter_lines(self.CHUNK_SIZE): - if b'\0' in line: raise BinarySuppressedError() - yield line.decode(self.msg.encoding) \ .encode(self.output_encoding, 'replace') + lf @@ -227,17 +258,21 @@ class PrettyStream(EncodedStream): CHUNK_SIZE = 1 - def __init__(self, conversion, formatting, **kwargs): + def __init__( + self, conversion: Conversion, + formatting: Formatting, + **kwargs, + ): super().__init__(**kwargs) self.formatting = formatting self.conversion = conversion self.mime = self.msg.content_type.split(';')[0] - def get_headers(self): + def get_headers(self) -> bytes: return self.formatting.format_headers( self.msg.headers).encode(self.output_encoding) - def iter_body(self): + def iter_body(self) -> Iterable[bytes]: first_chunk = True iter_lines = self.msg.iter_lines(self.CHUNK_SIZE) for line, lf in iter_lines: @@ -258,7 +293,7 @@ def iter_body(self): yield self.process_body(line) + lf first_chunk = False - def process_body(self, chunk): + def process_body(self, chunk: Union[str, bytes]) -> bytes: if not isinstance(chunk, str): # Text when a converter has been used, # otherwise it will always be bytes. @@ -277,7 +312,7 @@ class BufferedPrettyStream(PrettyStream): CHUNK_SIZE = 1024 * 10 - def iter_body(self): + def iter_body(self) -> Iterable[bytes]: # Read the whole body before prettifying it, # but bail out immediately if the body is binary. converter = None From b947d4826a3ee7a39992c9f88a433156c154507b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 18:33:54 +0200 Subject: [PATCH 0454/1182] Annotate plugins --- httpie/output/processing.py | 8 ++++--- httpie/plugins/__init__.py | 14 +++++++----- httpie/plugins/base.py | 8 +++---- httpie/plugins/builtin.py | 21 +++++++++++------- httpie/plugins/manager.py | 44 +++++++++++++++++++++++-------------- 5 files changed, 57 insertions(+), 38 deletions(-) diff --git a/httpie/output/processing.py b/httpie/output/processing.py index 850c6810c5..98270985c5 100644 --- a/httpie/output/processing.py +++ b/httpie/output/processing.py @@ -1,6 +1,7 @@ import re +from typing import Optional, List -from httpie.plugins import plugin_manager +from httpie.plugins import plugin_manager, ConverterPlugin from httpie.context import Environment @@ -13,7 +14,8 @@ def is_valid_mime(mime): class Conversion: - def get_converter(self, mime): + @staticmethod + def get_converter(mime: str) -> Optional[ConverterPlugin]: if is_valid_mime(mime): for converter_class in plugin_manager.get_converters(): if converter_class.supports(mime): @@ -23,7 +25,7 @@ def get_converter(self, mime): class Formatting: """A delegate class that invokes the actual processors.""" - def __init__(self, groups, env=Environment(), **kwargs): + def __init__(self, groups: List[str], env=Environment(), **kwargs): """ :param groups: names of processor groups to be applied :param env: Environment diff --git a/httpie/plugins/__init__.py b/httpie/plugins/__init__.py index 13b8565006..38c2a66ccc 100644 --- a/httpie/plugins/__init__.py +++ b/httpie/plugins/__init__.py @@ -1,6 +1,6 @@ """ WARNING: The plugin API is still work in progress and will - probably be completely reworked by v1.0.0. + probably be completely reworked in the future. """ from httpie.plugins.base import ( @@ -15,8 +15,10 @@ plugin_manager = PluginManager() -plugin_manager.register(BasicAuthPlugin, - DigestAuthPlugin) -plugin_manager.register(HeadersFormatter, - JSONFormatter, - ColorFormatter) +plugin_manager.register( + BasicAuthPlugin, + DigestAuthPlugin, + HeadersFormatter, + JSONFormatter, + ColorFormatter, +) diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index ef1475fd01..5dc3bf1f7e 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -75,7 +75,7 @@ def get_adapter(self): raise NotImplementedError() -class ConverterPlugin: +class ConverterPlugin(BasePlugin): def __init__(self, mime): self.mime = mime @@ -88,7 +88,7 @@ def supports(cls, mime): raise NotImplementedError -class FormatterPlugin: +class FormatterPlugin(BasePlugin): def __init__(self, **kwargs): """ @@ -100,7 +100,7 @@ def __init__(self, **kwargs): self.enabled = True self.kwargs = kwargs - def format_headers(self, headers): + def format_headers(self, headers: str) -> str: """Return processed `headers` :param headers: The headers as text. @@ -108,7 +108,7 @@ def format_headers(self, headers): """ return headers - def format_body(self, content, mime): + def format_body(self, content: str, mime: str) -> str: """Return processed `content`. :param mime: E.g., 'application/atom+xml'. diff --git a/httpie/plugins/builtin.py b/httpie/plugins/builtin.py index eb7b9fc0ff..1a01c902fb 100644 --- a/httpie/plugins/builtin.py +++ b/httpie/plugins/builtin.py @@ -7,37 +7,38 @@ # noinspection PyAbstractClass class BuiltinAuthPlugin(AuthPlugin): - package_name = '(builtin)' class HTTPBasicAuth(requests.auth.HTTPBasicAuth): - def __call__(self, r): + def __call__( + self, + request: requests.PreparedRequest + ) -> requests.PreparedRequest: """ Override username/password serialization to allow unicode. See https://github.com/jakubroztocil/httpie/issues/212 """ - r.headers['Authorization'] = type(self).make_header( + request.headers['Authorization'] = type(self).make_header( self.username, self.password).encode('latin1') - return r + return request @staticmethod - def make_header(username, password): + def make_header(username: str, password: str) -> str: credentials = u'%s:%s' % (username, password) token = b64encode(credentials.encode('utf8')).strip().decode('latin1') return 'Basic %s' % token class BasicAuthPlugin(BuiltinAuthPlugin): - name = 'Basic HTTP auth' auth_type = 'basic' # noinspection PyMethodOverriding - def get_auth(self, username, password): + def get_auth(self, username: str, password: str) -> HTTPBasicAuth: return HTTPBasicAuth(username, password) @@ -47,5 +48,9 @@ class DigestAuthPlugin(BuiltinAuthPlugin): auth_type = 'digest' # noinspection PyMethodOverriding - def get_auth(self, username, password): + def get_auth( + self, + username: str, + password: str + ) -> requests.auth.HTTPDigestAuth: return requests.auth.HTTPDigestAuth(username, password) diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index cde0e8ec11..8d9bab47f8 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -1,7 +1,9 @@ from itertools import groupby +from typing import Type, Iterable, List, Dict + from pkg_resources import iter_entry_points from httpie.plugins import AuthPlugin, FormatterPlugin, ConverterPlugin -from httpie.plugins.base import TransportPlugin +from httpie.plugins.base import TransportPlugin, BasePlugin ENTRY_POINT_NAMES = [ @@ -20,11 +22,11 @@ def __init__(self): def __iter__(self): return iter(self._plugins) - def register(self, *plugins): + def register(self, *plugins: Type[BasePlugin]): for plugin in plugins: self._plugins.append(plugin) - def unregister(self, plugin): + def unregister(self, plugin: BasePlugin): self._plugins.remove(plugin) def load_installed_plugins(self): @@ -35,21 +37,25 @@ def load_installed_plugins(self): self.register(entry_point.load()) # Auth - def get_auth_plugins(self): + def get_auth_plugins(self) -> List[Type[AuthPlugin]]: return [plugin for plugin in self if issubclass(plugin, AuthPlugin)] - def get_auth_plugin_mapping(self): - return {plugin.auth_type: plugin for plugin in self.get_auth_plugins()} + def get_auth_plugin_mapping(self) -> Dict[str, Type[AuthPlugin]]: + return { + plugin.auth_type: plugin for plugin in self.get_auth_plugins() + } - def get_auth_plugin(self, auth_type): + def get_auth_plugin(self, auth_type: str) -> Type[AuthPlugin]: return self.get_auth_plugin_mapping()[auth_type] # Output processing - def get_formatters(self): - return [plugin for plugin in self - if issubclass(plugin, FormatterPlugin)] + def get_formatters(self) -> List[Type[FormatterPlugin]]: + return [ + plugin for plugin in self + if issubclass(plugin, FormatterPlugin) + ] - def get_formatters_grouped(self): + def get_formatters_grouped(self) -> Dict[str, List[Type[FormatterPlugin]]]: groups = {} for group_name, group in groupby( self.get_formatters(), @@ -57,11 +63,15 @@ def get_formatters_grouped(self): groups[group_name] = list(group) return groups - def get_converters(self): - return [plugin for plugin in self - if issubclass(plugin, ConverterPlugin)] + def get_converters(self) -> List[Type[ConverterPlugin]]: + return [ + plugin for plugin in self + if issubclass(plugin, ConverterPlugin) + ] # Adapters - def get_transport_plugins(self): - return [plugin for plugin in self - if issubclass(plugin, TransportPlugin)] + def get_transport_plugins(self) -> List[Type[TransportPlugin]]: + return [ + plugin for plugin in self + if issubclass(plugin, TransportPlugin) + ] From 09cd85918e38c9d50d056f4ad2d468d605adabd1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 18:35:18 +0200 Subject: [PATCH 0455/1182] CHANGELOG --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 282d64daef..9ba2e419d2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,6 +16,7 @@ This project adheres to `Semantic Versioning `_. * Added ``--ignore-netrc`` to allow bypassing credentials from ``.netrc``. * Added ``https`` alias command with ``https://`` as the default scheme. * Added ``$ALL_PROXY`` documentation. +* Added type annotations throughout the codebase. * Fixed an error when ``stdin`` was a closed fd. * Fixed an error when the config directory was not writeable. * Improved ``--debug`` output formatting. From d603502960dc2725bfb472c516eb0741f00dc54f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 18:35:24 +0200 Subject: [PATCH 0456/1182] Fix unregister annotation --- httpie/plugins/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index 8d9bab47f8..d199ec6092 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -26,7 +26,7 @@ def register(self, *plugins: Type[BasePlugin]): for plugin in plugins: self._plugins.append(plugin) - def unregister(self, plugin: BasePlugin): + def unregister(self, plugin: Type[BasePlugin]): self._plugins.remove(plugin) def load_installed_plugins(self): From 30624e66ec06e19687e83350687945d34af3215c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 31 Aug 2019 19:11:46 +0200 Subject: [PATCH 0457/1182] Annotate formatters and processing --- httpie/output/formatters/colors.py | 29 ++++++++++++++++++++++------- httpie/output/formatters/headers.py | 2 +- httpie/output/formatters/json.py | 2 +- httpie/output/processing.py | 4 ++-- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 52f5a22a78..cf4c8e26de 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -1,5 +1,6 @@ from __future__ import absolute_import import json +from typing import Type import pygments.lexer import pygments.token @@ -13,6 +14,7 @@ from pygments.util import ClassNotFound from httpie.compat import is_windows +from httpie.context import Environment from httpie.plugins import FormatterPlugin @@ -40,8 +42,13 @@ class ColorFormatter(FormatterPlugin): """ group_name = 'colors' - def __init__(self, env, explicit_json=False, - color_scheme=DEFAULT_STYLE, **kwargs): + def __init__( + self, + env: Environment, + explicit_json=False, + color_scheme=DEFAULT_STYLE, + **kwargs + ): super().__init__(**kwargs) if not env.colors: @@ -63,14 +70,14 @@ def __init__(self, env, explicit_json=False, self.formatter = formatter self.http_lexer = http_lexer - def format_headers(self, headers): + def format_headers(self, headers: str) -> str: return pygments.highlight( code=headers, lexer=self.http_lexer, formatter=self.formatter, ).strip() - def format_body(self, body, mime): + def format_body(self, body: str, mime: str) -> str: lexer = self.get_lexer_for_body(mime, body) if lexer: body = pygments.highlight( @@ -80,21 +87,29 @@ def format_body(self, body, mime): ) return body.strip() - def get_lexer_for_body(self, mime, body): + def get_lexer_for_body( + self, mime: str, + body: str + ) -> Type[pygments.lexer.Lexer]: return get_lexer( mime=mime, explicit_json=self.explicit_json, body=body, ) - def get_style_class(self, color_scheme): + @staticmethod + def get_style_class(color_scheme: str) -> Type[pygments.style.Style]: try: return pygments.styles.get_style_by_name(color_scheme) except ClassNotFound: return Solarized256Style -def get_lexer(mime, explicit_json=False, body=''): +def get_lexer( + mime: str, + explicit_json=False, + body='' +) -> Type[pygments.lexer.Lexer]: # Build candidate mime type and lexer names. mime_types, lexer_names = [mime], [] diff --git a/httpie/output/formatters/headers.py b/httpie/output/formatters/headers.py index 146dea3c20..486f09f6e2 100644 --- a/httpie/output/formatters/headers.py +++ b/httpie/output/formatters/headers.py @@ -3,7 +3,7 @@ class HeadersFormatter(FormatterPlugin): - def format_headers(self, headers): + def format_headers(self, headers: str) -> str: """ Sorts headers by name while retaining relative order of multiple headers with the same name. diff --git a/httpie/output/formatters/json.py b/httpie/output/formatters/json.py index 9af5db1ae2..d2eb52d362 100644 --- a/httpie/output/formatters/json.py +++ b/httpie/output/formatters/json.py @@ -9,7 +9,7 @@ class JSONFormatter(FormatterPlugin): - def format_body(self, body, mime): + def format_body(self, body: str, mime: str) -> str: maybe_json = [ 'json', 'javascript', diff --git a/httpie/output/processing.py b/httpie/output/processing.py index 98270985c5..9bee26217a 100644 --- a/httpie/output/processing.py +++ b/httpie/output/processing.py @@ -40,12 +40,12 @@ def __init__(self, groups: List[str], env=Environment(), **kwargs): if p.enabled: self.enabled_plugins.append(p) - def format_headers(self, headers): + def format_headers(self, headers: str) -> str: for p in self.enabled_plugins: headers = p.format_headers(headers) return headers - def format_body(self, content, mime): + def format_body(self, content: str, mime: str) -> str: if is_valid_mime(mime): for p in self.enabled_plugins: content = p.format_body(content, mime) From a34b3d9d87fdfdf5695d8e4278277fd74374abcf Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 1 Sep 2019 11:13:45 +0200 Subject: [PATCH 0458/1182] Refactor `PluginManager` --- httpie/plugins/manager.py | 46 ++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index d199ec6092..45b210ff39 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -1,9 +1,10 @@ from itertools import groupby -from typing import Type, Iterable, List, Dict +from typing import Dict, List, Type from pkg_resources import iter_entry_points -from httpie.plugins import AuthPlugin, FormatterPlugin, ConverterPlugin -from httpie.plugins.base import TransportPlugin, BasePlugin + +from httpie.plugins import AuthPlugin, ConverterPlugin, FormatterPlugin +from httpie.plugins.base import BasePlugin, TransportPlugin ENTRY_POINT_NAMES = [ @@ -14,20 +15,17 @@ ] -class PluginManager: - - def __init__(self): - self._plugins = [] - - def __iter__(self): - return iter(self._plugins) +class PluginManager(list): def register(self, *plugins: Type[BasePlugin]): for plugin in plugins: - self._plugins.append(plugin) + self.append(plugin) def unregister(self, plugin: Type[BasePlugin]): - self._plugins.remove(plugin) + self.remove(plugin) + + def filter(self, by_type=Type[BasePlugin]): + return [plugin for plugin in self if issubclass(plugin, by_type)] def load_installed_plugins(self): for entry_point_name in ENTRY_POINT_NAMES: @@ -38,7 +36,7 @@ def load_installed_plugins(self): # Auth def get_auth_plugins(self) -> List[Type[AuthPlugin]]: - return [plugin for plugin in self if issubclass(plugin, AuthPlugin)] + return self.filter(AuthPlugin) def get_auth_plugin_mapping(self) -> Dict[str, Type[AuthPlugin]]: return { @@ -50,28 +48,22 @@ def get_auth_plugin(self, auth_type: str) -> Type[AuthPlugin]: # Output processing def get_formatters(self) -> List[Type[FormatterPlugin]]: - return [ - plugin for plugin in self - if issubclass(plugin, FormatterPlugin) - ] + return self.filter(FormatterPlugin) def get_formatters_grouped(self) -> Dict[str, List[Type[FormatterPlugin]]]: groups = {} for group_name, group in groupby( - self.get_formatters(), - key=lambda p: getattr(p, 'group_name', 'format')): + self.get_formatters(), + key=lambda p: getattr(p, 'group_name', 'format')): groups[group_name] = list(group) return groups def get_converters(self) -> List[Type[ConverterPlugin]]: - return [ - plugin for plugin in self - if issubclass(plugin, ConverterPlugin) - ] + return self.filter(ConverterPlugin) # Adapters def get_transport_plugins(self) -> List[Type[TransportPlugin]]: - return [ - plugin for plugin in self - if issubclass(plugin, TransportPlugin) - ] + return self.filter(TransportPlugin) + + def __repr__(self): + return f'' From 4dffac7a25e9c1098df553138114319a9fbf0531 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 1 Sep 2019 11:38:14 +0200 Subject: [PATCH 0459/1182] Refactor client --- httpie/cli/definition.py | 1 + httpie/client.py | 81 +++++++++++++++++++++++++--------------- httpie/sessions.py | 4 +- 3 files changed, 54 insertions(+), 32 deletions(-) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 5a3fe6abe6..201d9f7f50 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -169,6 +169,7 @@ content_processing.add_argument( '--compress', '-x', action='count', + default=0, help=""" Content compressed (encoded) with Deflate algorithm. The Content-Encoding header is set to deflate. diff --git a/httpie/client.py b/httpie/client.py index 49d0406392..fb81667fe8 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -17,18 +17,13 @@ try: - # https://urllib3.readthedocs.io/en/latest/security.html # noinspection PyPackageRequirements import urllib3 + # urllib3.disable_warnings() 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. - # They may get some noisy output but execution shouldn't die. Move on. pass - FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8' JSON_CONTENT_TYPE = 'application/json' JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*' @@ -49,9 +44,16 @@ def max_headers(limit): class HTTPieHTTPAdapter(HTTPAdapter): - def __init__(self, ssl_version=None, compress=0, **kwargs): + def __init__( + self, + ssl_version=None, + compression_enabled=False, + compress_always=False, + **kwargs, + ): self._ssl_version = ssl_version - self._compress = compress + self._compression_enabled = compression_enabled + self._compress_always = compress_always super().__init__(**kwargs) def init_poolmanager(self, *args, **kwargs): @@ -59,34 +61,50 @@ def init_poolmanager(self, *args, **kwargs): super().init_poolmanager(*args, **kwargs) def send(self, request: requests.PreparedRequest, **kwargs): - if self._compress and request.body: - self._compress_body(request, self._compress) + if request.body and self._compression_enabled: + self._compress_body(request, always=self._compress_always) return super().send(request, **kwargs) @staticmethod - def _compress_body(request: requests.PreparedRequest, compress: int): + def _compress_body(request: requests.PreparedRequest, always: bool): deflater = zlib.compressobj() - if isinstance(request.body, bytes): - deflated_data = deflater.compress(request.body) - else: - deflated_data = deflater.compress(request.body.encode()) + body_bytes = ( + request.body + if isinstance(request.body, bytes) + else request.body.encode() + ) + deflated_data = deflater.compress(body_bytes) deflated_data += deflater.flush() - if len(deflated_data) < len(request.body) or compress > 1: + is_economical = len(deflated_data) < len(body_bytes) + if is_economical or always: request.body = deflated_data request.headers['Content-Encoding'] = 'deflate' request.headers['Content-Length'] = str(len(deflated_data)) -def get_requests_session(ssl_version: str, compress: int) -> requests.Session: +def build_requests_session( + ssl_version: str, + compress_arg: int, +) -> requests.Session: requests_session = requests.Session() - adapter = HTTPieHTTPAdapter(ssl_version=ssl_version, compress=compress) - for prefix in ['http://', 'https://']: - requests_session.mount(prefix, adapter) - - for cls in plugin_manager.get_transport_plugins(): - transport_plugin = cls() - requests_session.mount(prefix=transport_plugin.prefix, - adapter=transport_plugin.get_adapter()) + + # Install our adapter. + adapter = HTTPieHTTPAdapter( + ssl_version=ssl_version, + compression_enabled=compress_arg > 0, + compress_always=compress_arg > 1, + ) + requests_session.mount('http://', adapter) + requests_session.mount('https://', adapter) + + # Install adapters from plugins. + for plugin_cls in plugin_manager.get_transport_plugins(): + transport_plugin = plugin_cls() + requests_session.mount( + prefix=transport_plugin.prefix, + adapter=transport_plugin.get_adapter(), + ) + return requests_session @@ -100,12 +118,15 @@ def get_response( if args.ssl_version: ssl_version = SSL_VERSION_ARG_MAPPING[args.ssl_version] - requests_session = get_requests_session(ssl_version, args.compress) + requests_session = build_requests_session( + ssl_version=ssl_version, + compress_arg=args.compress + ) requests_session.max_redirects = args.max_redirects with max_headers(args.max_headers): if not args.session and not args.session_read_only: - kwargs = get_requests_kwargs(args) + kwargs = make_requests_kwargs(args) if args.debug: dump_request(kwargs) response = requests_session.request(**kwargs) @@ -142,7 +163,7 @@ def finalize_headers(headers: RequestHeadersDict) -> RequestHeadersDict: return final_headers -def get_default_headers(args: argparse.Namespace) -> RequestHeadersDict: +def make_default_headers(args: argparse.Namespace) -> RequestHeadersDict: default_headers = RequestHeadersDict({ 'User-Agent': DEFAULT_UA }) @@ -160,7 +181,7 @@ def get_default_headers(args: argparse.Namespace) -> RequestHeadersDict: return default_headers -def get_requests_kwargs(args: argparse.Namespace, base_headers=None) -> dict: +def make_requests_kwargs(args: argparse.Namespace, base_headers=None) -> dict: """ Translate our `args` into `requests.request` keyword arguments. @@ -177,7 +198,7 @@ def get_requests_kwargs(args: argparse.Namespace, base_headers=None) -> dict: data = '' # Finalize headers. - headers = get_default_headers(args) + headers = make_default_headers(args) if base_headers: headers.update(base_headers) headers.update(args.headers) diff --git a/httpie/sessions.py b/httpie/sessions.py index 59ae734391..69289647f3 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -36,7 +36,7 @@ def get_response( aspects of the session to the request. """ - from .client import get_requests_kwargs, dump_request + from .client import make_requests_kwargs, dump_request if os.path.sep in session_name: path = os.path.expanduser(session_name) else: @@ -56,7 +56,7 @@ def get_response( session = Session(path) session.load() - kwargs = get_requests_kwargs(args, base_headers=session.headers) + kwargs = make_requests_kwargs(args, base_headers=session.headers) if args.debug: dump_request(kwargs) session.update_headers(kwargs['headers']) From bd3208cf248a587fe3af6f485310383a76ef37a4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 1 Sep 2019 11:45:47 +0200 Subject: [PATCH 0460/1182] Refactor get_formatters_grouped --- httpie/plugins/base.py | 1 + httpie/plugins/manager.py | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index 5dc3bf1f7e..ff8dda0995 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -89,6 +89,7 @@ def supports(cls, mime): class FormatterPlugin(BasePlugin): + group_name = 'format' def __init__(self, **kwargs): """ diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index 45b210ff39..cd9d85e138 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -1,4 +1,5 @@ from itertools import groupby +from operator import attrgetter from typing import Dict, List, Type from pkg_resources import iter_entry_points @@ -51,12 +52,11 @@ def get_formatters(self) -> List[Type[FormatterPlugin]]: return self.filter(FormatterPlugin) def get_formatters_grouped(self) -> Dict[str, List[Type[FormatterPlugin]]]: - groups = {} - for group_name, group in groupby( - self.get_formatters(), - key=lambda p: getattr(p, 'group_name', 'format')): - groups[group_name] = list(group) - return groups + return { + group_name: list(group) + for group_name, group + in groupby(self.get_formatters(), key=attrgetter('group_name')) + } def get_converters(self) -> List[Type[ConverterPlugin]]: return self.filter(ConverterPlugin) From 45e8e4e4ea001d80d76c202ccfa1aec06e71b809 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 1 Sep 2019 21:15:39 +0200 Subject: [PATCH 0461/1182] Sessions --- httpie/client.py | 7 ++++++- httpie/sessions.py | 14 ++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index fb81667fe8..c0f7a50d08 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -19,6 +19,8 @@ try: # noinspection PyPackageRequirements import urllib3 + + # urllib3.disable_warnings() except (ImportError, AttributeError): @@ -181,7 +183,10 @@ def make_default_headers(args: argparse.Namespace) -> RequestHeadersDict: return default_headers -def make_requests_kwargs(args: argparse.Namespace, base_headers=None) -> dict: +def make_requests_kwargs( + args: argparse.Namespace, + base_headers: RequestHeadersDict = None +) -> dict: """ Translate our `args` into `requests.request` keyword arguments. diff --git a/httpie/sessions.py b/httpie/sessions.py index 69289647f3..4f80cc30cd 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -12,6 +12,7 @@ from requests.cookies import RequestsCookieJar, create_cookie import requests +from httpie.cli.dicts import RequestHeadersDict from httpie.config import BaseConfigDict, DEFAULT_CONFIG_DIR from httpie.plugins import plugin_manager @@ -101,14 +102,13 @@ def __init__(self, path: Union[str, Path]): def _get_path(self) -> Path: return self._path - def update_headers(self, request_headers: dict): + def update_headers(self, request_headers: RequestHeadersDict): """ Update the session headers with the request ones while ignoring certain name prefixes. - :type request_headers: dict - """ + headers = self.headers for name, value in request_headers.items(): if value is None: @@ -122,11 +122,13 @@ def update_headers(self, request_headers: dict): if name.lower().startswith(prefix.lower()): break else: - self['headers'][name] = value + headers[name] = value + + self['headers'] = dict(headers) @property - def headers(self) -> dict: - return self['headers'] + def headers(self) -> RequestHeadersDict: + return RequestHeadersDict(self['headers']) @property def cookies(self) -> RequestsCookieJar: From c946b3d34fcd0b0931ac6d172d38b648fa4dc14e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 2 Sep 2019 14:38:23 +0200 Subject: [PATCH 0462/1182] Cleanup --- httpie/client.py | 8 +++----- httpie/output/formatters/colors.py | 14 +++++++------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index c0f7a50d08..8c4f89d5bf 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -19,8 +19,6 @@ try: # noinspection PyPackageRequirements import urllib3 - - # urllib3.disable_warnings() except (ImportError, AttributeError): @@ -128,10 +126,10 @@ def get_response( with max_headers(args.max_headers): if not args.session and not args.session_read_only: - kwargs = make_requests_kwargs(args) + requests_kwargs = make_requests_kwargs(args) if args.debug: - dump_request(kwargs) - response = requests_session.request(**kwargs) + dump_request(requests_kwargs) + response = requests_session.request(**requests_kwargs) else: response = sessions.get_response( requests_session=requests_session, diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index cf4c8e26de..9416dea5b2 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -1,14 +1,16 @@ from __future__ import absolute_import + import json -from typing import Type +from typing import Optional, Type import pygments.lexer -import pygments.token -import pygments.styles import pygments.lexers import pygments.style +import pygments.styles +import pygments.token from pygments.formatters.terminal import TerminalFormatter from pygments.formatters.terminal256 import Terminal256Formatter +from pygments.lexer import Lexer from pygments.lexers.special import TextLexer from pygments.lexers.text import HttpLexer as PygmentsHttpLexer from pygments.util import ClassNotFound @@ -26,7 +28,6 @@ # great and fruity seems to give the best result there. DEFAULT_STYLE = 'fruity' - AVAILABLE_STYLES = set(pygments.styles.get_all_styles()) AVAILABLE_STYLES.add(SOLARIZED_STYLE) AVAILABLE_STYLES.add(AUTO_STYLE) @@ -90,7 +91,7 @@ def format_body(self, body: str, mime: str) -> str: def get_lexer_for_body( self, mime: str, body: str - ) -> Type[pygments.lexer.Lexer]: + ) -> Optional[Type[Lexer]]: return get_lexer( mime=mime, explicit_json=self.explicit_json, @@ -109,8 +110,7 @@ def get_lexer( mime: str, explicit_json=False, body='' -) -> Type[pygments.lexer.Lexer]: - +) -> Optional[Type[Lexer]]: # Build candidate mime type and lexer names. mime_types, lexer_names = [mime], [] type_, subtype = mime.split('/', 1) From bece3c77bb51ecc55dcc4008375dc29ccd91575c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 3 Sep 2019 17:14:39 +0200 Subject: [PATCH 0463/1182] Add one-by-one processing of each HTTP request or response and --offline --- CHANGELOG.rst | 6 + httpie/cli/argparser.py | 11 +- httpie/cli/constants.py | 1 + httpie/cli/definition.py | 8 + httpie/client.py | 171 ++++++++++++++------- httpie/core.py | 310 +++++++++++++++++--------------------- httpie/downloads.py | 22 +-- httpie/output/streams.py | 143 +----------------- httpie/output/writer.py | 163 ++++++++++++++++++++ httpie/sessions.py | 54 ++----- tests/test_auth.py | 2 +- tests/test_cli.py | 4 +- tests/test_downloads.py | 27 ++-- tests/test_errors.py | 10 +- tests/test_exit_status.py | 14 +- tests/test_httpie.py | 4 +- tests/test_redirects.py | 31 ++-- tests/test_sessions.py | 13 +- tests/test_ssl.py | 2 +- tests/test_uploads.py | 11 +- tests/test_windows.py | 2 +- tests/utils.py | 10 +- 22 files changed, 536 insertions(+), 483 deletions(-) create mode 100644 httpie/output/writer.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9ba2e419d2..18db9e91fc 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,12 @@ This project adheres to `Semantic Versioning `_. * Removed Python 2.7 support (`EOL Jan 2020 `_). * Removed the default 30-second connection ``--timeout`` limit. * Removed Python’s default limit of 100 response headers. +* Replaced the old collect-all-then-process handling of HTTP communication + with one-by-one processing of each HTTP request or response as they become + available. This means that you can see headers immediately, + see what is being send even when the request fails, etc. +* Added ``--offline`` to allow building an HTTP request and printing it but not + actually sending it over the network. * Added ``--max-headers`` to allow setting the max header limit. * Added ``--compress`` to allow request body compression. * Added ``--ignore-netrc`` to allow bypassing credentials from ``.netrc``. diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index a48c98fd67..fb7d567b4e 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -13,6 +13,7 @@ OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED, OUT_RESP_BODY, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, SEPARATOR_CREDENTIALS, SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_GROUP_DATA_ITEMS, URL_SCHEME_RE, + OUTPUT_OPTIONS_DEFAULT_OFFLINE, ) from httpie.cli.exceptions import ParseError from httpie.cli.requestitems import RequestItems @@ -348,12 +349,12 @@ def check_options(value, option): if self.args.output_options is None: if self.args.verbose: self.args.output_options = ''.join(OUTPUT_OPTIONS) + elif self.args.offline: + self.args.output_options = OUTPUT_OPTIONS_DEFAULT_OFFLINE + elif not self.env.stdout_isatty: + self.args.output_options = OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED else: - self.args.output_options = ( - OUTPUT_OPTIONS_DEFAULT - if self.env.stdout_isatty - else OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED - ) + self.args.output_options = OUTPUT_OPTIONS_DEFAULT if self.args.output_options_history is None: self.args.output_options_history = self.args.output_options diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index 8c0ad79f0a..2b22fbe033 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -86,6 +86,7 @@ # Defaults OUTPUT_OPTIONS_DEFAULT = OUT_RESP_HEAD + OUT_RESP_BODY OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED = OUT_RESP_BODY +OUTPUT_OPTIONS_DEFAULT_OFFLINE = OUT_REQ_HEAD + OUT_REQ_BODY SSL_VERSION_ARG_MAPPING = { 'ssl2.3': 'PROTOCOL_SSLv23', diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 201d9f7f50..c770e5db7e 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -468,6 +468,14 @@ def __iter__(self): network = parser.add_argument_group(title='Network') +network.add_argument( + '--offline', + default=False, + action='store_true', + help=""" + Build the request and print it but don’t actually send it. + """ +) network.add_argument( '--proxy', default=[], diff --git a/httpie/client.py b/httpie/client.py index 8c4f89d5bf..278b85f444 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -5,14 +5,16 @@ import zlib from contextlib import contextmanager from pathlib import Path +from typing import Iterable, Union import requests from requests.adapters import HTTPAdapter -from httpie import __version__, sessions +from httpie import __version__ from httpie.cli.constants import SSL_VERSION_ARG_MAPPING from httpie.cli.dicts import RequestHeadersDict from httpie.plugins import plugin_manager +from httpie.sessions import get_httpie_session from httpie.utils import repr_dict @@ -24,12 +26,90 @@ except (ImportError, AttributeError): pass + FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8' JSON_CONTENT_TYPE = 'application/json' JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*' DEFAULT_UA = f'HTTPie/{__version__}' +def collect_messages( + args: argparse.Namespace, + config_dir: Path +) -> Iterable[Union[requests.PreparedRequest, requests.Response]]: + httpie_session = None + httpie_session_headers = None + if args.session or args.session_read_only: + httpie_session = get_httpie_session( + config_dir=config_dir, + session_name=args.session or args.session_read_only, + host=args.headers.get('Host'), + url=args.url, + ) + httpie_session_headers = httpie_session.headers + + request_kwargs = make_request_kwargs( + args=args, + base_headers=httpie_session_headers, + ) + send_kwargs = make_send_kwargs(args) + send_kwargs_mergeable_from_env = make_send_kwargs_mergeable_from_env(args) + requests_session = build_requests_session( + ssl_version=args.ssl_version, + compress_arg=args.compress, + ) + + if httpie_session: + httpie_session.update_headers(request_kwargs['headers']) + requests_session.cookies = httpie_session.cookies + if args.auth_plugin: + # Save auth from CLI to HTTPie session. + httpie_session.auth = { + 'type': args.auth_plugin.auth_type, + 'raw_auth': args.auth_plugin.raw_auth, + } + elif httpie_session.auth: + # Apply auth from HTTPie session + request_kwargs['auth'] = httpie_session.auth + + if args.debug: + # TODO: reflect the split between request and send kwargs. + dump_request(request_kwargs) + + request = requests.Request(**request_kwargs) + prepared_request = requests_session.prepare_request(request) + response_count = 0 + while prepared_request: + yield prepared_request + if not args.offline: + send_kwargs_merged = requests_session.merge_environment_settings( + url=prepared_request.url, + **send_kwargs_mergeable_from_env, + ) + with max_headers(args.max_headers): + response = requests_session.send( + request=prepared_request, + **send_kwargs_merged, + **send_kwargs, + ) + response_count += 1 + if response.next: + if args.max_redirects and response_count == args.max_redirects: + raise requests.TooManyRedirects + if args.follow: + prepared_request = response.next + if args.all: + yield response + continue + yield response + break + + if httpie_session: + if httpie_session.is_new() or not args.session_read_only: + httpie_session.cookies = requests_session.cookies + httpie_session.save() + + # noinspection PyProtectedMember @contextmanager def max_headers(limit): @@ -83,14 +163,14 @@ def _compress_body(request: requests.PreparedRequest, always: bool): def build_requests_session( - ssl_version: str, compress_arg: int, + ssl_version: str = None, ) -> requests.Session: requests_session = requests.Session() # Install our adapter. adapter = HTTPieHTTPAdapter( - ssl_version=ssl_version, + ssl_version=SSL_VERSION_ARG_MAPPING[ssl_version] if ssl_version else None, compression_enabled=compress_arg > 0, compress_always=compress_arg > 1, ) @@ -108,40 +188,6 @@ def build_requests_session( return requests_session -def get_response( - args: argparse.Namespace, - config_dir: Path -) -> requests.Response: - """Send the request and return a `request.Response`.""" - - ssl_version = None - if args.ssl_version: - ssl_version = SSL_VERSION_ARG_MAPPING[args.ssl_version] - - requests_session = build_requests_session( - ssl_version=ssl_version, - compress_arg=args.compress - ) - requests_session.max_redirects = args.max_redirects - - with max_headers(args.max_headers): - if not args.session and not args.session_read_only: - requests_kwargs = make_requests_kwargs(args) - if args.debug: - dump_request(requests_kwargs) - response = requests_session.request(**requests_kwargs) - else: - response = sessions.get_response( - requests_session=requests_session, - args=args, - config_dir=config_dir, - session_name=args.session or args.session_read_only, - read_only=bool(args.session_read_only), - ) - - return response - - def dump_request(kwargs: dict): sys.stderr.write( f'\n>>> requests.request(**{repr_dict(kwargs)})\n\n') @@ -181,12 +227,40 @@ def make_default_headers(args: argparse.Namespace) -> RequestHeadersDict: return default_headers -def make_requests_kwargs( +def make_send_kwargs(args: argparse.Namespace) -> dict: + kwargs = { + 'timeout': args.timeout or None, + 'allow_redirects': False, + } + return kwargs + + +def make_send_kwargs_mergeable_from_env(args: argparse.Namespace) -> dict: + cert = None + if args.cert: + cert = args.cert + if args.cert_key: + cert = cert, args.cert_key + kwargs = { + 'proxies': {p.key: p.value for p in args.proxy}, + 'stream': True, + 'verify': { + 'yes': True, + 'true': True, + 'no': False, + 'false': False, + }.get(args.verify.lower(), args.verify), + 'cert': cert, + } + return kwargs + + +def make_request_kwargs( args: argparse.Namespace, base_headers: RequestHeadersDict = None ) -> dict: """ - Translate our `args` into `requests.request` keyword arguments. + Translate our `args` into `requests.Request` keyword arguments. """ # Serialize JSON data, if needed. @@ -207,31 +281,14 @@ def make_requests_kwargs( headers.update(args.headers) headers = finalize_headers(headers) - cert = None - if args.cert: - cert = args.cert - if args.cert_key: - cert = cert, args.cert_key - kwargs = { - 'stream': True, 'method': args.method.lower(), 'url': args.url, 'headers': headers, 'data': data, - 'verify': { - 'yes': True, - 'true': True, - 'no': False, - 'false': False, - }.get(args.verify.lower(), args.verify), - 'cert': cert, - 'timeout': args.timeout or None, 'auth': args.auth, - 'proxies': {p.key: p.value for p in args.proxy}, - 'files': args.files, - 'allow_redirects': args.follow, 'params': args.params, + 'files': args.files, } return kwargs diff --git a/httpie/core.py b/httpie/core.py index 7ed5341ecf..69266f3135 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -1,17 +1,4 @@ -"""This module provides the main functionality of HTTPie. - -Invocation flow: - - 1. Read, validate and process the input (args, `stdin`). - 2. Create and send a request. - 3. Stream, and possibly process and format, the parts - of the request-response exchange selected by output options. - 4. Simultaneously write to `stdout` - 5. Exit. - -""" import argparse -import errno import platform import sys from typing import Callable, List, Union @@ -21,162 +8,13 @@ from requests import __version__ as requests_version from httpie import ExitStatus, __version__ as httpie_version -from httpie.client import get_response +from httpie.client import collect_messages from httpie.context import Environment from httpie.downloads import Downloader -from httpie.output.streams import ( - build_output_stream, - write_stream, - write_stream_with_colors_win_py3, -) +from httpie.output.writer import write_message, write_stream from httpie.plugins import plugin_manager -def get_exit_status(http_status: int, follow=False) -> ExitStatus: - """Translate HTTP status code to exit status code.""" - if 300 <= http_status <= 399 and not follow: - # Redirect - return ExitStatus.ERROR_HTTP_3XX - elif 400 <= http_status <= 499: - # Client Error - return ExitStatus.ERROR_HTTP_4XX - elif 500 <= http_status <= 599: - # Server Error - return ExitStatus.ERROR_HTTP_5XX - else: - return ExitStatus.SUCCESS - - -def print_debug_info(env: Environment): - env.stderr.writelines([ - 'HTTPie %s\n' % httpie_version, - 'Requests %s\n' % requests_version, - 'Pygments %s\n' % pygments_version, - 'Python %s\n%s\n' % (sys.version, sys.executable), - '%s %s' % (platform.system(), platform.release()), - ]) - env.stderr.write('\n\n') - env.stderr.write(repr(env)) - env.stderr.write('\n') - - -def decode_args( - args: List[Union[str, bytes]], - stdin_encoding: str -) -> List[str]: - """ - Convert all bytes args to str - by decoding them using stdin encoding. - - """ - return [ - arg.decode(stdin_encoding) - if type(arg) == bytes else arg - for arg in args - ] - - -def program( - args: argparse.Namespace, - env: Environment, - log_error: Callable -) -> ExitStatus: - """ - The main program without error handling - - :param args: parsed args (argparse.Namespace) - :type env: Environment - :param log_error: error log function - :return: status code - - """ - exit_status = ExitStatus.SUCCESS - downloader = None - show_traceback = args.debug or args.traceback - - try: - if args.download: - args.follow = True # --download implies --follow. - downloader = Downloader( - output_file=args.output_file, - progress_file=env.stderr, - resume=args.download_resume - ) - downloader.pre_request(args.headers) - - final_response = get_response(args, config_dir=env.config.directory) - if args.all: - responses = final_response.history + [final_response] - else: - responses = [final_response] - - for response in responses: - - if args.check_status or downloader: - exit_status = get_exit_status( - http_status=response.status_code, - follow=args.follow - ) - if not env.stdout_isatty and exit_status != ExitStatus.SUCCESS: - log_error( - 'HTTP %s %s', response.raw.status, response.raw.reason, - level='warning' - ) - - write_stream_kwargs = { - 'stream': build_output_stream( - args=args, - env=env, - request=response.request, - response=response, - output_options=( - args.output_options - if response is final_response - else args.output_options_history - ) - ), - # NOTE: `env.stdout` will in fact be `stderr` with `--download` - 'outfile': env.stdout, - 'flush': env.stdout_isatty or args.stream - } - try: - if env.is_windows and 'colors' in args.prettify: - write_stream_with_colors_win_py3(**write_stream_kwargs) - else: - write_stream(**write_stream_kwargs) - except IOError as e: - if not show_traceback and e.errno == errno.EPIPE: - # Ignore broken pipes unless --traceback. - env.stderr.write('\n') - else: - raise - - if downloader and exit_status == ExitStatus.SUCCESS: - # Last response body download. - download_stream, download_to = downloader.start(final_response) - write_stream( - stream=download_stream, - outfile=download_to, - flush=False, - ) - downloader.finish() - if downloader.interrupted: - exit_status = ExitStatus.ERROR - log_error('Incomplete download: size=%d; downloaded=%d' % ( - downloader.status.total_size, - downloader.status.downloaded - )) - return exit_status - - finally: - if downloader and not downloader.finished: - downloader.failed() - - if (not isinstance(args, list) and args.output_file - and args.output_file_specified): - args.output_file.close() - - def main( args: List[Union[str, bytes]] = sys.argv, env=Environment(), @@ -191,15 +29,13 @@ def main( Return exit status code. """ - args = decode_args(args, env.stdin_encoding) + args = decode_raw_args(args, env.stdin_encoding) program_name, *args = args plugin_manager.load_installed_plugins() - def log_error(msg, *args, **kwargs): - msg = msg % args - level = kwargs.get('level', 'error') + def log_error(msg, level='error'): assert level in ['error', 'warning'] - env.stderr.write('\nhttp: %s: %s\n' % (level, msg)) + env.stderr.write(f'\n{program_name}: {level}: {msg}\n') from httpie.cli.definition import parser @@ -256,22 +92,146 @@ def log_error(msg, *args, **kwargs): exit_status = ExitStatus.ERROR except requests.Timeout: exit_status = ExitStatus.ERROR_TIMEOUT - log_error('Request timed out (%ss).', parsed_args.timeout) + log_error(f'Request timed out ({parsed_args.timeout}s).') except requests.TooManyRedirects: exit_status = ExitStatus.ERROR_TOO_MANY_REDIRECTS - log_error('Too many redirects (--max-redirects=%s).', - parsed_args.max_redirects) + log_error( + f'Too many redirects' + f' (--max-redirects=parsed_args.max_redirects).' + ) except Exception as e: # TODO: Further distinction between expected and unexpected errors. msg = str(e) if hasattr(e, 'request'): request = e.request if hasattr(request, 'url'): - msg += ' while doing %s request to URL: %s' % ( - request.method, request.url) - log_error('%s: %s', type(e).__name__, msg) + msg = ( + f'{msg} while doing a {request.method}' + f' request to URL: {request.url}' + ) + log_error(f'{type(e).__name__}: {msg}') if include_traceback: raise exit_status = ExitStatus.ERROR return exit_status + + +def program( + args: argparse.Namespace, + env: Environment, + log_error: Callable +) -> ExitStatus: + """ + The main program without error handling. + + """ + exit_status = ExitStatus.SUCCESS + downloader = None + + try: + if args.download: + args.follow = True # --download implies --follow. + downloader = Downloader( + output_file=args.output_file, + progress_file=env.stderr, + resume=args.download_resume + ) + downloader.pre_request(args.headers) + + initial_request = None + final_response = None + + for message in collect_messages(args, env.config.directory): + write_message( + requests_message=message, + env=env, + args=args, + ) + if isinstance(message, requests.PreparedRequest): + if not initial_request: + initial_request = message + else: + final_response = message + if args.check_status or downloader: + exit_status = get_exit_status( + http_status=message.status_code, + follow=args.follow + ) + if not env.stdout_isatty and exit_status != ExitStatus.SUCCESS: + log_error( + f'HTTP {message.raw.status} {message.raw.reason}', + level='warning' + ) + + if downloader and exit_status == ExitStatus.SUCCESS: + # Last response body download. + download_stream, download_to = downloader.start( + initial_url=initial_request.url, + final_response=final_response, + ) + write_stream( + stream=download_stream, + outfile=download_to, + flush=False, + ) + downloader.finish() + if downloader.interrupted: + exit_status = ExitStatus.ERROR + log_error('Incomplete download: size=%d; downloaded=%d' % ( + downloader.status.total_size, + downloader.status.downloaded + )) + return exit_status + + finally: + if downloader and not downloader.finished: + downloader.failed() + + if (not isinstance(args, list) and args.output_file + and args.output_file_specified): + args.output_file.close() + + +def get_exit_status(http_status: int, follow=False) -> ExitStatus: + """Translate HTTP status code to exit status code.""" + if 300 <= http_status <= 399 and not follow: + # Redirect + return ExitStatus.ERROR_HTTP_3XX + elif 400 <= http_status <= 499: + # Client Error + return ExitStatus.ERROR_HTTP_4XX + elif 500 <= http_status <= 599: + # Server Error + return ExitStatus.ERROR_HTTP_5XX + else: + return ExitStatus.SUCCESS + + +def print_debug_info(env: Environment): + env.stderr.writelines([ + 'HTTPie %s\n' % httpie_version, + 'Requests %s\n' % requests_version, + 'Pygments %s\n' % pygments_version, + 'Python %s\n%s\n' % (sys.version, sys.executable), + '%s %s' % (platform.system(), platform.release()), + ]) + env.stderr.write('\n\n') + env.stderr.write(repr(env)) + env.stderr.write('\n') + + +def decode_raw_args( + args: List[Union[str, bytes]], + stdin_encoding: str +) -> List[str]: + """ + Convert all bytes args to str + by decoding them using stdin encoding. + + """ + return [ + arg.decode(stdin_encoding) + if type(arg) == bytes else arg + for arg in args + ] diff --git a/httpie/downloads.py b/httpie/downloads.py index b3aaac9002..78e1eb209f 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -121,7 +121,7 @@ def filename_from_content_disposition( return filename -def filename_from_url(url: str, content_type: str) -> str: +def filename_from_url(url: str, content_type: Optional[str]) -> str: fn = urlsplit(url).path.rstrip('/') fn = os.path.basename(fn) if fn else 'index' if '.' not in fn and content_type: @@ -230,11 +230,16 @@ def pre_request(self, request_headers: dict): request_headers['Range'] = 'bytes=%d-' % bytes_have self._resumed_from = bytes_have - def start(self, final_response: requests.Response) -> Tuple[RawStream, IO]: + def start( + self, + initial_url: str, + final_response: requests.Response + ) -> Tuple[RawStream, IO]: """ Initiate and return a stream for `response` body with progress callback attached. Can be called only once. + :param initial_url: The original requested URL :param final_response: Initiated response object with headers already fetched :return: RawStream, output_file @@ -251,7 +256,9 @@ def start(self, final_response: requests.Response) -> Tuple[RawStream, IO]: if not self._output_file: self._output_file = self._get_output_file_from_response( - final_response) + initial_url=initial_url, + final_response=final_response, + ) else: # `--output, -o` provided if self._resume and final_response.status_code == PARTIAL_CONTENT: @@ -322,7 +329,8 @@ def chunk_downloaded(self, chunk: bytes): @staticmethod def _get_output_file_from_response( - final_response: requests.Response + initial_url: str, + final_response: requests.Response, ) -> IO: # Output file not specified. Pick a name that doesn't exist yet. filename = None @@ -330,12 +338,8 @@ def _get_output_file_from_response( filename = filename_from_content_disposition( final_response.headers['Content-Disposition']) if not filename: - initial_response = ( - final_response.history[0] if final_response.history - else final_response - ) filename = filename_from_url( - url=initial_response.url, + url=initial_url, content_type=final_response.headers.get('Content-Type'), ) unique_filename = get_unique_filename(filename) diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 6da36e14db..b1f810b691 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -1,14 +1,8 @@ -import argparse from itertools import chain -from typing import Callable, IO, Iterable, TextIO, Tuple, Type, Union +from typing import Callable, Iterable, Union -import requests - -from httpie.cli.constants import ( - OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_BODY, OUT_RESP_HEAD, -) from httpie.context import Environment -from httpie.models import HTTPMessage, HTTPRequest, HTTPResponse +from httpie.models import HTTPMessage from httpie.output.processing import Conversion, Formatting @@ -27,143 +21,14 @@ class BinarySuppressedError(Exception): message = BINARY_SUPPRESSED_NOTICE -def write_stream( - stream: 'BaseStream', - outfile: Union[IO, TextIO], - flush: bool -): - """Write the output stream.""" - try: - # Writing bytes so we use the buffer interface (Python 3). - buf = outfile.buffer - except AttributeError: - buf = outfile - - for chunk in stream: - buf.write(chunk) - if flush: - outfile.flush() - - -def write_stream_with_colors_win_py3( - stream: 'BaseStream', - outfile: TextIO, - flush: bool -): - """Like `write`, but colorized chunks are written as text - directly to `outfile` to ensure it gets processed by colorama. - Applies only to Windows with Python 3 and colorized terminal output. - - """ - color = b'\x1b[' - encoding = outfile.encoding - for chunk in stream: - if color in chunk: - outfile.write(chunk.decode(encoding)) - else: - outfile.buffer.write(chunk) - if flush: - outfile.flush() - - -def build_output_stream( - args: argparse.Namespace, - env: Environment, - request: requests.Request, - response: requests.Response, - output_options: str -) -> Iterable[bytes]: - """Build and return a chain of iterators over the `request`-`response` - exchange each of which yields `bytes` chunks. - - """ - req_h = OUT_REQ_HEAD in output_options - req_b = OUT_REQ_BODY in output_options - resp_h = OUT_RESP_HEAD in output_options - resp_b = OUT_RESP_BODY in output_options - req = req_h or req_b - resp = resp_h or resp_b - - output = [] - stream_class, stream_kwargs = get_stream_type_and_kwargs( - env=env, args=args) - - if req: - output.append( - stream_class( - msg=HTTPRequest(request), - with_headers=req_h, - with_body=req_b, - **stream_kwargs, - ) - ) - - if req_b and resp: - # Request/Response separator. - output.append([b'\n\n']) - - if resp: - output.append( - stream_class( - msg=HTTPResponse(response), - with_headers=resp_h, - with_body=resp_b, - **stream_kwargs, - ) - ) - - if env.stdout_isatty and resp_b: - # Ensure a blank line after the response body. - # For terminal output only. - output.append([b'\n\n']) - - return chain(*output) - - -def get_stream_type_and_kwargs( - env: Environment, - args: argparse.Namespace -) -> Tuple[Type['BaseStream'], dict]: - """Pick the right stream type and kwargs for it based on `env` and `args`. - - """ - if not env.stdout_isatty and not args.prettify: - stream_class = RawStream - stream_kwargs = { - 'chunk_size': ( - RawStream.CHUNK_SIZE_BY_LINE - if args.stream - else RawStream.CHUNK_SIZE - ) - } - elif args.prettify: - stream_class = PrettyStream if args.stream else BufferedPrettyStream - stream_kwargs = { - 'env': env, - 'conversion': Conversion(), - 'formatting': Formatting( - env=env, - groups=args.prettify, - color_scheme=args.style, - explicit_json=args.json, - ) - } - else: - stream_class = EncodedStream - stream_kwargs = { - 'env': env - } - - return stream_class, stream_kwargs - - class BaseStream: """Base HTTP message output stream class.""" def __init__( self, msg: HTTPMessage, - with_headers=True, with_body=True, + with_headers=True, + with_body=True, on_body_chunk_downloaded: Callable[[bytes], None] = None ): """ diff --git a/httpie/output/writer.py b/httpie/output/writer.py new file mode 100644 index 0000000000..b9e219f97a --- /dev/null +++ b/httpie/output/writer.py @@ -0,0 +1,163 @@ +import argparse +import errno +from typing import Union, IO, TextIO, Tuple, Type + +import requests + +from httpie.context import Environment +from httpie.models import HTTPRequest, HTTPResponse +from httpie.output.processing import Conversion, Formatting +from httpie.output.streams import ( + RawStream, PrettyStream, + BufferedPrettyStream, EncodedStream, + BaseStream, +) +from httpie.cli.constants import ( + OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_BODY, OUT_RESP_HEAD, +) + + +def write_message( + requests_message: Union[requests.PreparedRequest, requests.Response], + env: Environment, + args: argparse.Namespace, +): + output_options_by_message_type = { + requests.PreparedRequest: { + 'with_headers': OUT_REQ_HEAD in args.output_options, + 'with_body': OUT_REQ_BODY in args.output_options, + }, + requests.Response: { + 'with_headers': OUT_RESP_HEAD in args.output_options, + 'with_body': OUT_RESP_BODY in args.output_options, + }, + } + output_options = output_options_by_message_type[type(requests_message)] + if not any(output_options.values()): + return + write_stream_kwargs = { + 'stream': build_output_stream_for_message( + args=args, + env=env, + requests_message=requests_message, + **output_options, + ), + # NOTE: `env.stdout` will in fact be `stderr` with `--download` + 'outfile': env.stdout, + 'flush': env.stdout_isatty or args.stream + } + try: + if env.is_windows and 'colors' in args.prettify: + write_stream_with_colors_win_py3(**write_stream_kwargs) + else: + write_stream(**write_stream_kwargs) + except IOError as e: + show_traceback = args.debug or args.traceback + if not show_traceback and e.errno == errno.EPIPE: + # Ignore broken pipes unless --traceback. + env.stderr.write('\n') + else: + raise + + +def write_stream( + stream: BaseStream, + outfile: Union[IO, TextIO], + flush: bool +): + """Write the output stream.""" + try: + # Writing bytes so we use the buffer interface (Python 3). + buf = outfile.buffer + except AttributeError: + buf = outfile + + for chunk in stream: + buf.write(chunk) + if flush: + outfile.flush() + + +def write_stream_with_colors_win_py3( + stream: 'BaseStream', + outfile: TextIO, + flush: bool +): + """Like `write`, but colorized chunks are written as text + directly to `outfile` to ensure it gets processed by colorama. + Applies only to Windows with Python 3 and colorized terminal output. + + """ + color = b'\x1b[' + encoding = outfile.encoding + for chunk in stream: + if color in chunk: + outfile.write(chunk.decode(encoding)) + else: + outfile.buffer.write(chunk) + if flush: + outfile.flush() + + +def build_output_stream_for_message( + args: argparse.Namespace, + env: Environment, + requests_message: Union[requests.PreparedRequest, requests.Response], + with_headers: bool, + with_body: bool, +): + stream_class, stream_kwargs = get_stream_type_and_kwargs( + env=env, + args=args, + ) + message_class = { + requests.PreparedRequest: HTTPRequest, + requests.Response: HTTPResponse, + }[type(requests_message)] + yield from stream_class( + msg=message_class(requests_message), + with_headers=with_headers, + with_body=with_body, + **stream_kwargs, + ) + if env.stdout_isatty and with_body: + # Ensure a blank line after the response body. + # For terminal output only. + yield b'\n\n' + + +def get_stream_type_and_kwargs( + env: Environment, + args: argparse.Namespace +) -> Tuple[Type['BaseStream'], dict]: + """Pick the right stream type and kwargs for it based on `env` and `args`. + + """ + if not env.stdout_isatty and not args.prettify: + stream_class = RawStream + stream_kwargs = { + 'chunk_size': ( + RawStream.CHUNK_SIZE_BY_LINE + if args.stream + else RawStream.CHUNK_SIZE + ) + } + elif args.prettify: + stream_class = PrettyStream if args.stream else BufferedPrettyStream + stream_kwargs = { + 'env': env, + 'conversion': Conversion(), + 'formatting': Formatting( + env=env, + groups=args.prettify, + color_scheme=args.style, + explicit_json=args.json, + ) + } + else: + stream_class = EncodedStream + stream_kwargs = { + 'env': env + } + + return stream_class, stream_kwargs diff --git a/httpie/sessions.py b/httpie/sessions.py index 4f80cc30cd..f1def677d2 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -1,16 +1,14 @@ """Persistent, JSON-serialized sessions. """ -import argparse -import re import os +import re from pathlib import Path from typing import Optional, Union from urllib.parse import urlsplit from requests.auth import AuthBase from requests.cookies import RequestsCookieJar, create_cookie -import requests from httpie.cli.dicts import RequestHeadersDict from httpie.config import BaseConfigDict, DEFAULT_CONFIG_DIR @@ -26,23 +24,16 @@ SESSION_IGNORED_HEADER_PREFIXES = ['Content-', 'If-'] -def get_response( - requests_session: requests.Session, - session_name: str, +def get_httpie_session( config_dir: Path, - args: argparse.Namespace, - read_only=False, -) -> requests.Response: - """Like `client.get_responses`, but applies permanent - aspects of the session to the request. - - """ - from .client import make_requests_kwargs, dump_request + session_name: str, + host: Optional[str], + url: str, +) -> 'Session': 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 = host or urlsplit(url).netloc.split('@')[-1] if not hostname: # HACK/FIXME: httpie-unixsocket's URLs have no hostname. hostname = 'localhost' @@ -50,38 +41,11 @@ def get_response( # host:port => host_port hostname = hostname.replace(':', '_') path = ( - config_dir / SESSIONS_DIR_NAME / hostname - / (session_name + '.json') + config_dir / SESSIONS_DIR_NAME / hostname / f'{session_name}.json' ) - session = Session(path) session.load() - - kwargs = make_requests_kwargs(args, base_headers=session.headers) - if args.debug: - dump_request(kwargs) - session.update_headers(kwargs['headers']) - - if args.auth_plugin: - session.auth = { - 'type': args.auth_plugin.auth_type, - 'raw_auth': args.auth_plugin.raw_auth, - } - elif session.auth: - kwargs['auth'] = session.auth - - requests_session.cookies = session.cookies - - try: - response = requests_session.request(**kwargs) - except Exception: - raise - else: - # Existing sessions with `read_only=True` don't get updated. - if session.is_new() or not read_only: - session.cookies = requests_session.cookies - session.save() - return response + return session class Session(BaseConfigDict): diff --git a/tests/test_auth.py b/tests/test_auth.py index b555cd6ef0..e94bb3df76 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -71,7 +71,7 @@ def test_missing_auth(httpbin): '--auth-type=basic', 'GET', httpbin + '/basic-auth/user/password', - error_exit_ok=True + tolerate_error_exit_status=True ) assert HTTP_OK not in r assert '--auth required' in r.stderr diff --git a/tests/test_cli.py b/tests/test_cli.py index 2f428cb257..7f1e5f6f6d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -303,7 +303,7 @@ def test_valid_no_options(self, httpbin): def test_invalid_no_options(self, httpbin): r = http('--no-war', 'GET', httpbin.url + '/get', - error_exit_ok=True) + tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR assert 'unrecognized arguments: --no-war' in r.stderr assert 'GET /get HTTP/1.1' not in r @@ -322,7 +322,7 @@ def test_ignore_stdin(self, httpbin): def test_ignore_stdin_cannot_prompt_password(self, httpbin): r = http('--ignore-stdin', '--auth=no-password', httpbin.url + '/get', - error_exit_ok=True) + tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR assert 'because --ignore-stdin' in r.stderr diff --git a/tests/test_downloads.py b/tests/test_downloads.py index 76f04e45a2..572d039f96 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -135,10 +135,13 @@ def test_actual_download(self, httpbin_both, httpbin): def test_download_with_Content_Length(self, httpbin_both): with open(os.devnull, 'w') as devnull: downloader = Downloader(output_file=devnull, progress_file=devnull) - downloader.start(Response( - url=httpbin_both.url + '/', - headers={'Content-Length': 10} - )) + downloader.start( + initial_url='/', + final_response=Response( + url=httpbin_both.url + '/', + headers={'Content-Length': 10} + ) + ) time.sleep(1.1) downloader.chunk_downloaded(b'12345') time.sleep(1.1) @@ -150,7 +153,10 @@ def test_download_with_Content_Length(self, httpbin_both): def test_download_no_Content_Length(self, httpbin_both): with open(os.devnull, 'w') as devnull: downloader = Downloader(output_file=devnull, progress_file=devnull) - downloader.start(Response(url=httpbin_both.url + '/')) + downloader.start( + final_response=Response(url=httpbin_both.url + '/'), + initial_url='/' + ) time.sleep(1.1) downloader.chunk_downloaded(b'12345') downloader.finish() @@ -160,10 +166,13 @@ def test_download_no_Content_Length(self, httpbin_both): def test_download_interrupted(self, httpbin_both): with open(os.devnull, 'w') as devnull: downloader = Downloader(output_file=devnull, progress_file=devnull) - downloader.start(Response( - url=httpbin_both.url + '/', - headers={'Content-Length': 5} - )) + downloader.start( + final_response=Response( + url=httpbin_both.url + '/', + headers={'Content-Length': 5} + ), + initial_url='/' + ) downloader.chunk_downloaded(b'1234') downloader.finish() assert downloader.interrupted diff --git a/tests/test_errors.py b/tests/test_errors.py index 596e2f5e49..57788a4060 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -1,17 +1,17 @@ import mock from pytest import raises -from requests import Request, Timeout +from requests import Request from requests.exceptions import ConnectionError from httpie import ExitStatus from httpie.core import main -from utils import http, HTTP_OK +from utils import HTTP_OK, http error_msg = None -@mock.patch('httpie.core.get_response') +@mock.patch('httpie.core.program') def test_error(get_response): def error(msg, *args, **kwargs): global error_msg @@ -24,11 +24,11 @@ def error(msg, *args, **kwargs): assert ret == ExitStatus.ERROR assert error_msg == ( 'ConnectionError: ' - 'Connection aborted while doing GET request to URL: ' + 'Connection aborted while doing a GET request to URL: ' 'http://www.google.com') -@mock.patch('httpie.core.get_response') +@mock.patch('httpie.core.program') def test_error_traceback(get_response): exc = ConnectionError('Connection aborted') exc.request = Request(method='GET', url='http://www.google.com') diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index 77878222f6..fa25036b13 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -7,14 +7,14 @@ def test_keyboard_interrupt_during_arg_parsing_exit_status(httpbin): with mock.patch('httpie.cli.definition.parser.parse_args', side_effect=KeyboardInterrupt()): - r = http('GET', httpbin.url + '/get', error_exit_ok=True) + r = http('GET', httpbin.url + '/get', tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR_CTRL_C def test_keyboard_interrupt_in_program_exit_status(httpbin): with mock.patch('httpie.core.program', side_effect=KeyboardInterrupt()): - r = http('GET', httpbin.url + '/get', error_exit_ok=True) + r = http('GET', httpbin.url + '/get', tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR_CTRL_C @@ -34,7 +34,7 @@ def test_error_response_exits_0_without_check_status(httpbin): def test_timeout_exit_status(httpbin): r = http('--timeout=0.01', 'GET', httpbin.url + '/delay/0.5', - error_exit_ok=True) + tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR_TIMEOUT @@ -43,7 +43,7 @@ def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected( env = MockEnvironment(stdout_isatty=False) r = http('--check-status', '--headers', 'GET', httpbin.url + '/status/301', - env=env, error_exit_ok=True) + env=env, tolerate_error_exit_status=True) assert '301 MOVED PERMANENTLY' in r assert r.exit_status == ExitStatus.ERROR_HTTP_3XX assert '301 moved permanently' in r.stderr.lower() @@ -52,7 +52,7 @@ def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected( def test_3xx_check_status_redirects_allowed_exits_0(httpbin): r = http('--check-status', '--follow', 'GET', httpbin.url + '/status/301', - error_exit_ok=True) + tolerate_error_exit_status=True) # The redirect will be followed so 200 is expected. assert HTTP_OK in r assert r.exit_status == ExitStatus.SUCCESS @@ -60,7 +60,7 @@ def test_3xx_check_status_redirects_allowed_exits_0(httpbin): def test_4xx_check_status_exits_4(httpbin): r = http('--check-status', 'GET', httpbin.url + '/status/401', - error_exit_ok=True) + tolerate_error_exit_status=True) assert '401 UNAUTHORIZED' in r assert r.exit_status == ExitStatus.ERROR_HTTP_4XX # Also stderr should be empty since stdout isn't redirected. @@ -69,6 +69,6 @@ def test_4xx_check_status_exits_4(httpbin): def test_5xx_check_status_exits_5(httpbin): r = http('--check-status', 'GET', httpbin.url + '/status/500', - error_exit_ok=True) + tolerate_error_exit_status=True) assert '500 INTERNAL SERVER ERROR' in r assert r.exit_status == ExitStatus.ERROR_HTTP_5XX diff --git a/tests/test_httpie.py b/tests/test_httpie.py index d17e7c735b..e1a954f95f 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -15,13 +15,13 @@ def test_debug(): def test_help(): - r = http('--help', error_exit_ok=True) + r = http('--help', tolerate_error_exit_status=True) 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) + r = http('--version', tolerate_error_exit_status=True) assert r.exit_status == httpie.ExitStatus.SUCCESS # FIXME: py3 has version in stdout, py2 in stderr assert httpie.__version__ == r.strip() diff --git a/tests/test_redirects.py b/tests/test_redirects.py index 1895ea042a..95d51fe82a 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -28,20 +28,25 @@ def test_follow_all_output_options_used_for_redirects(httpbin): assert r.count('GET /') == 3 assert HTTP_OK not in r - -def test_follow_redirect_output_options(httpbin): - r = http('--check-status', - '--follow', - '--all', - '--print=h', - '--history-print=H', - httpbin.url + '/redirect/2') - assert r.count('GET /') == 2 - assert 'HTTP/1.1 302 FOUND' not in r - assert HTTP_OK in r +# +# def test_follow_redirect_output_options(httpbin): +# r = http('--check-status', +# '--follow', +# '--all', +# '--print=h', +# '--history-print=H', +# httpbin.url + '/redirect/2') +# assert r.count('GET /') == 2 +# assert 'HTTP/1.1 302 FOUND' not in r +# assert HTTP_OK in r +# def test_max_redirects(httpbin): - r = http('--max-redirects=1', '--follow', httpbin.url + '/redirect/3', - error_exit_ok=True) + r = http( + '--max-redirects=1', + '--follow', + httpbin.url + '/redirect/3', + tolerate_error_exit_status=True, + ) assert r.exit_status == ExitStatus.ERROR_TOO_MANY_REDIRECTS diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 765ca7b298..e199eec68f 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -45,10 +45,15 @@ def start_session(self, httpbin): """ super().start_session(httpbin) - r1 = http('--follow', '--session=test', '--auth=username:password', - 'GET', httpbin.url + '/cookies/set?hello=world', - 'Hello:World', - env=self.env()) + r1 = http( + '--follow', + '--session=test', + '--auth=username:password', + 'GET', + httpbin.url + '/cookies/set?hello=world', + 'Hello:World', + env=self.env() + ) assert HTTP_OK in r1 def test_session_created_and_reused(self, httpbin): diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 3437d6eb2a..e47e160121 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -66,7 +66,7 @@ def test_cert_pem(self, httpbin_secure): def test_cert_file_not_found(self, httpbin_secure): r = http(httpbin_secure + '/get', '--cert', '/__not_found__', - error_exit_ok=True) + tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR assert 'No such file or directory' in r.stderr diff --git a/tests/test_uploads.py b/tests/test_uploads.py index ba881014bc..81298fa58e 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -64,12 +64,17 @@ def test_request_body_from_file_by_path_no_field_name_allowed( self, httpbin): env = MockEnvironment(stdin_isatty=True) r = http('POST', httpbin.url + '/post', 'field-name@' + FILE_PATH_ARG, - env=env, error_exit_ok=True) + env=env, tolerate_error_exit_status=True) assert 'perhaps you meant --form?' in r.stderr def test_request_body_from_file_by_path_no_data_items_allowed( self, httpbin): env = MockEnvironment(stdin_isatty=False) - r = http('POST', httpbin.url + '/post', '@' + FILE_PATH_ARG, 'foo=bar', - env=env, error_exit_ok=True) + r = http( + 'POST', + httpbin.url + '/post', + '@' + FILE_PATH_ARG, 'foo=bar', + env=env, + tolerate_error_exit_status=True, + ) assert 'cannot be mixed' in r.stderr diff --git a/tests/test_windows.py b/tests/test_windows.py index 90be4814fe..e32ddacd30 100644 --- a/tests/test_windows.py +++ b/tests/test_windows.py @@ -27,5 +27,5 @@ def test_output_file_pretty_not_allowed_on_windows(self, httpbin): ) r = http('--output', output_file, '--pretty=all', 'GET', httpbin.url + '/get', - env=env, error_exit_ok=True) + env=env, tolerate_error_exit_status=True) assert 'Only terminal output can be colorized on Windows' in r.stderr diff --git a/tests/utils.py b/tests/utils.py index 141bd765d4..bf279ccddb 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -167,7 +167,7 @@ def http(*args, program_name='http', **kwargs): Exceptions are propagated. - If you pass ``error_exit_ok=True``, then error exit statuses + If you pass ``tolerate_error_exit_status=True``, then error exit statuses won't result into an exception. Example: @@ -188,7 +188,7 @@ def http(*args, program_name='http', **kwargs): True """ - error_exit_ok = kwargs.pop('error_exit_ok', False) + tolerate_error_exit_status = kwargs.pop('tolerate_error_exit_status', False) env = kwargs.get('env') if not env: env = kwargs['env'] = MockEnvironment() @@ -200,7 +200,7 @@ def http(*args, program_name='http', **kwargs): args_with_config_defaults = args + env.config.default_options add_to_args = [] if '--debug' not in args_with_config_defaults: - if not error_exit_ok and '--traceback' not in args_with_config_defaults: + if not tolerate_error_exit_status and '--traceback' not in args_with_config_defaults: add_to_args.append('--traceback') if not any('--timeout' in arg for arg in args_with_config_defaults): add_to_args.append('--timeout=3') @@ -218,7 +218,7 @@ def dump_stderr(): # Let the progress reporter thread finish. time.sleep(.5) except SystemExit: - if error_exit_ok: + if tolerate_error_exit_status: exit_status = ExitStatus.ERROR else: dump_stderr() @@ -228,7 +228,7 @@ def dump_stderr(): sys.stderr.write(stderr.read()) raise else: - if not error_exit_ok and exit_status != ExitStatus.SUCCESS: + if not tolerate_error_exit_status and exit_status != ExitStatus.SUCCESS: dump_stderr() raise ExitStatusError( 'httpie.core.main() unexpectedly returned' From 5a4392076a69c61886cb0911554b1556214b042e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 3 Sep 2019 22:34:04 +0200 Subject: [PATCH 0464/1182] Included tests in pypi package #182 --- MANIFEST.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MANIFEST.in b/MANIFEST.in index 3d6d0baba9..545f82f2b2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,3 +2,6 @@ include LICENSE include README.rst include CHANGELOG.rst include AUTHORS.rst + +# +recursive-include tests/ * From f86677842143774e86f1b4ec49b07c9237a18cf6 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 3 Sep 2019 22:37:18 +0200 Subject: [PATCH 0465/1182] CHANGELOG --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 18db9e91fc..a7b86195ed 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -23,6 +23,8 @@ This project adheres to `Semantic Versioning `_. * Added ``https`` alias command with ``https://`` as the default scheme. * Added ``$ALL_PROXY`` documentation. * Added type annotations throughout the codebase. +* Added ``tests/`` to PyPi package for the convenience of + downstream package maintainers’. * Fixed an error when ``stdin`` was a closed fd. * Fixed an error when the config directory was not writeable. * Improved ``--debug`` output formatting. From 99f8a8c23d45ea8f00bd3f428ada45b4c181fbca Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 3 Sep 2019 22:37:59 +0200 Subject: [PATCH 0466/1182] Typos --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a7b86195ed..686f63052e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -23,8 +23,8 @@ This project adheres to `Semantic Versioning `_. * Added ``https`` alias command with ``https://`` as the default scheme. * Added ``$ALL_PROXY`` documentation. * Added type annotations throughout the codebase. -* Added ``tests/`` to PyPi package for the convenience of - downstream package maintainers’. +* Added ``tests/`` to the PyPi package for the convenience of + downstream package maintainers. * Fixed an error when ``stdin`` was a closed fd. * Fixed an error when the config directory was not writeable. * Improved ``--debug`` output formatting. From c8fd4c2d6eb34145754d5e3f1e81752cb426d041 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 4 Sep 2019 00:00:03 +0200 Subject: [PATCH 0467/1182] Move compression out of adapter --- httpie/client.py | 66 +++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 40 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 278b85f444..175a89b32a 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -56,7 +56,6 @@ def collect_messages( send_kwargs_mergeable_from_env = make_send_kwargs_mergeable_from_env(args) requests_session = build_requests_session( ssl_version=args.ssl_version, - compress_arg=args.compress, ) if httpie_session: @@ -78,6 +77,8 @@ def collect_messages( request = requests.Request(**request_kwargs) prepared_request = requests_session.prepare_request(request) + if args.compress and prepared_request.body: + compress_body(prepared_request, always=args.compress > 1) response_count = 0 while prepared_request: yield prepared_request @@ -122,60 +123,45 @@ def max_headers(limit): http.client._MAXHEADERS = orig -class HTTPieHTTPAdapter(HTTPAdapter): +def compress_body(request: requests.PreparedRequest, always: bool): + deflater = zlib.compressobj() + body_bytes = ( + request.body + if isinstance(request.body, bytes) + else request.body.encode() + ) + deflated_data = deflater.compress(body_bytes) + deflated_data += deflater.flush() + is_economical = len(deflated_data) < len(body_bytes) + if is_economical or always: + request.body = deflated_data + request.headers['Content-Encoding'] = 'deflate' + request.headers['Content-Length'] = str(len(deflated_data)) + - def __init__( - self, - ssl_version=None, - compression_enabled=False, - compress_always=False, - **kwargs, - ): +class HTTPieHTTPSAdapter(HTTPAdapter): + + def __init__(self, ssl_version=None, **kwargs): self._ssl_version = ssl_version - self._compression_enabled = compression_enabled - self._compress_always = compress_always super().__init__(**kwargs) def init_poolmanager(self, *args, **kwargs): kwargs['ssl_version'] = self._ssl_version super().init_poolmanager(*args, **kwargs) - def send(self, request: requests.PreparedRequest, **kwargs): - if request.body and self._compression_enabled: - self._compress_body(request, always=self._compress_always) - return super().send(request, **kwargs) - - @staticmethod - def _compress_body(request: requests.PreparedRequest, always: bool): - deflater = zlib.compressobj() - body_bytes = ( - request.body - if isinstance(request.body, bytes) - else request.body.encode() - ) - deflated_data = deflater.compress(body_bytes) - deflated_data += deflater.flush() - is_economical = len(deflated_data) < len(body_bytes) - if is_economical or always: - request.body = deflated_data - request.headers['Content-Encoding'] = 'deflate' - request.headers['Content-Length'] = str(len(deflated_data)) - def build_requests_session( - compress_arg: int, ssl_version: str = None, ) -> requests.Session: requests_session = requests.Session() # Install our adapter. - adapter = HTTPieHTTPAdapter( - ssl_version=SSL_VERSION_ARG_MAPPING[ssl_version] if ssl_version else None, - compression_enabled=compress_arg > 0, - compress_always=compress_arg > 1, - ) - requests_session.mount('http://', adapter) - requests_session.mount('https://', adapter) + requests_session.mount('https://', HTTPieHTTPSAdapter( + ssl_version=( + SSL_VERSION_ARG_MAPPING[ssl_version] + if ssl_version else None + ) + )) # Install adapters from plugins. for plugin_cls in plugin_manager.get_transport_plugins(): From 3176785a5f0d935fa12a38790a79c64f0c4f93c3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 4 Sep 2019 13:38:56 +0200 Subject: [PATCH 0468/1182] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..2bc4be3772 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at jakub@roztocil.co. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq From 87414384841de86f8449722babfded9d60d3feca Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 9 Sep 2019 09:36:22 +0200 Subject: [PATCH 0469/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 686f63052e..9e15219c68 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,7 +8,7 @@ This project adheres to `Semantic Versioning `_. `2.0.0-dev`_ (unreleased) ------------------------- -* Removed Python 2.7 support (`EOL Jan 2020 `_). +* Removed Python 2.7 support (`EOL Jan 2020 `_). * Removed the default 30-second connection ``--timeout`` limit. * Removed Python’s default limit of 100 response headers. * Replaced the old collect-all-then-process handling of HTTP communication From 548857f35add65540e33341ccbaf7ce39320ca38 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 11:56:55 +0200 Subject: [PATCH 0470/1182] Update pythonpackage.yml --- .github/workflows/pythonpackage.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/pythonpackage.yml diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml new file mode 100644 index 0000000000..9d4197159e --- /dev/null +++ b/.github/workflows/pythonpackage.yml @@ -0,0 +1,22 @@ +name: Python package + +on: [push] + +jobs: + build: + + runs-on: ${{ matrix.os }} + strategy: + max-parallel: 4 + matrix: + python-version: [3.6, 3.7] + runs-on: [ubuntu-latest, macOS-latest, windows-latest] + + steps: + - uses: actions/checkout@v1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - name: make test + run: make test From a77f660ba761ce9656d77a139f113804b4084d64 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 12:17:03 +0200 Subject: [PATCH 0471/1182] Update pythonpackage.yml --- .github/workflows/pythonpackage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 9d4197159e..7c1d26c452 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -19,4 +19,4 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: make test - run: make test + run: pytest From 3909a436a9f6685e53ea3635946bffa35f9a683a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 12:44:25 +0200 Subject: [PATCH 0472/1182] Update pythonpackage.yml --- .github/workflows/pythonpackage.yml | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 7c1d26c452..bc2f6416fb 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -5,12 +5,11 @@ on: [push] jobs: build: - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest strategy: max-parallel: 4 matrix: - python-version: [3.6, 3.7] - runs-on: [ubuntu-latest, macOS-latest, windows-latest] + python-version: [2.7, 3.5, 3.6, 3.7] steps: - uses: actions/checkout@v1 @@ -18,5 +17,18 @@ jobs: uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - - name: make test - run: pytest + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Lint with flake8 + run: | + pip install flake8 + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pip install pytest + pytest From 3ec5c4a643064c2e98f6262288146edfdccf53e7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 12:46:34 +0200 Subject: [PATCH 0473/1182] Update pythonpackage.yml --- .github/workflows/pythonpackage.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index bc2f6416fb..d3ffecf940 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -5,11 +5,12 @@ on: [push] jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: max-parallel: 4 matrix: - python-version: [2.7, 3.5, 3.6, 3.7] + os: [macOS-latest, windows-latest, ubuntu-latest] + python-version: [3.6, 3.7] steps: - uses: actions/checkout@v1 From 7f8040894537e51bf0fe9efdb1d1b1a0f32ef19d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 12:49:46 +0200 Subject: [PATCH 0474/1182] Update pythonpackage.yml --- .github/workflows/pythonpackage.yml | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index d3ffecf940..7afd59f314 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -9,9 +9,8 @@ jobs: strategy: max-parallel: 4 matrix: - os: [macOS-latest, windows-latest, ubuntu-latest] + os: [ubuntu-latest, macOS-latest, windows-latest] python-version: [3.6, 3.7] - steps: - uses: actions/checkout@v1 - name: Set up Python ${{ matrix.python-version }} @@ -21,15 +20,5 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r requirements.txt - - name: Lint with flake8 - run: | - pip install flake8 - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with pytest - run: | - pip install pytest - pytest + - name: test + run: make test From 2ffd8d9d9bad9529f01dcbc433fc3b7a1e62f7e1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 13:10:29 +0200 Subject: [PATCH 0475/1182] workflow --- .github/workflows/pythonpackage.yml | 13 ++++++++++--- Makefile | 10 +++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 7afd59f314..2344071839 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -17,8 +17,15 @@ jobs: uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip + - name: upgrade pip + run: python -m pip install --upgrade pip + - name: install + run: make install - name: test run: make test + - name: pycodestyle + if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.7' + run: make pycodestyle + - name: coveralls + if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.7' + run: make coveralls diff --git a/Makefile b/Makefile index 85ebafb562..544e37c297 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,10 @@ TAG="\n\n\033[0;32m\#\#\# " END=" \#\#\# \033[0m\n" -all: test +all: uninstall-httpie install test -init: uninstall-httpie +install: @echo $(TAG)Installing dev requirements$(END) pip install --upgrade -r $(REQUIREMENTS) @@ -32,14 +32,14 @@ clean: ############################################################################### -test: init +test: @echo $(TAG)Running tests on the current Python interpreter with coverage $(END) py.test --cov ./httpie --cov ./tests --doctest-modules --verbose ./httpie ./tests @echo # test-all is meant to test everything — even this Makefile -test-all: uninstall-all clean init test test-tox test-dist pycodestyle +test-all: uninstall-all clean install test test-tox test-dist pycodestyle @echo @@ -47,7 +47,7 @@ test-dist: test-sdist test-bdist-wheel @echo -test-tox: init +test-tox: uninstall-httpie install @echo $(TAG)Running tests on all Pythons via Tox$(END) tox @echo From a5d9a839e5671b4ad685ab0f8064013d2cfd22f0 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 13:20:09 +0200 Subject: [PATCH 0476/1182] coveralls token --- .github/workflows/pythonpackage.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 2344071839..1f3ed6d461 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -29,3 +29,5 @@ jobs: - name: coveralls if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.7' run: make coveralls + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} From b7767b3c62030844ba1c96cee00dfe84cff83d8c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 13:36:02 +0200 Subject: [PATCH 0477/1182] workflow --- .github/workflows/pythonpackage.yml | 34 +++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 1f3ed6d461..b7d5ba55d9 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -3,8 +3,7 @@ name: Python package on: [push] jobs: - build: - + test: runs-on: ${{ matrix.os }} strategy: max-parallel: 4 @@ -17,17 +16,20 @@ jobs: uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - - name: upgrade pip - run: python -m pip install --upgrade pip - - name: install - run: make install - - name: test - run: make test - - name: pycodestyle - if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.7' - run: make pycodestyle - - name: coveralls - if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.7' - run: make coveralls - env: - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + - run: python -m pip install --upgrade pip + - run: make install + - run: make test + pycodestyle: + runs-on: ubuntu-latest + python-version: 3.7 + steps: + - name: pycodestyle + run: make pycodestyle + coveralls: + runs-on: ubuntu-latest + python-version: 3.7 + steps: + - name: coveralls + run: make coveralls + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} From 3fa583e591d8e996e8f52b6255dd2046c6a2d1a0 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 13:39:41 +0200 Subject: [PATCH 0478/1182] workflow --- .github/workflows/pythonpackage.yml | 34 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index b7d5ba55d9..958fb5c5f0 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -3,7 +3,7 @@ name: Python package on: [push] jobs: - test: + build: runs-on: ${{ matrix.os }} strategy: max-parallel: 4 @@ -16,20 +16,18 @@ jobs: uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - - run: python -m pip install --upgrade pip - - run: make install - - run: make test - pycodestyle: - runs-on: ubuntu-latest - python-version: 3.7 - steps: - - name: pycodestyle - run: make pycodestyle - coveralls: - runs-on: ubuntu-latest - python-version: 3.7 - steps: - - name: coveralls - run: make coveralls - env: - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + - name: upgrade pip + run: python -m pip install --upgrade pip + - name: install + run: make install + - name: test + run: make test + - name: pycodestyle + if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.7' + run: make pycodestyle + - name: coveralls + if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.7' + run: make coveralls + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + From 2bb54da368a3625dabf482b53944ad7f726eeac1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 13:58:05 +0200 Subject: [PATCH 0479/1182] worflow --- .github/workflows/pythonpackage.yml | 32 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 958fb5c5f0..5694de0184 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -3,10 +3,10 @@ name: Python package on: [push] jobs: - build: + test: + # run core httpie tests everywhere runs-on: ${{ matrix.os }} strategy: - max-parallel: 4 matrix: os: [ubuntu-latest, macOS-latest, windows-latest] python-version: [3.6, 3.7] @@ -16,18 +16,20 @@ jobs: uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - - name: upgrade pip - run: python -m pip install --upgrade pip - - name: install - run: make install - - name: test - run: make test - - name: pycodestyle - if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.7' - run: make pycodestyle - - name: coveralls - if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.7' - run: make coveralls + - run: python -m pip install --upgrade pip + - run: pip install --upgrade --editable . + - run: python setup.py test + + test-extras: + # coverage and extra tests only once + - runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.7] + - run: make install + - run: make test + - run: make test-dist + - run: make pycodestyle + - run: make coveralls env: COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} - From d9aadeef51fe8731420775b825e44ebe2a92f31a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 13:59:43 +0200 Subject: [PATCH 0480/1182] worflow --- .github/workflows/pythonpackage.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 5694de0184..18a8ad8d00 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -3,6 +3,7 @@ name: Python package on: [push] jobs: + name: tests test: # run core httpie tests everywhere runs-on: ${{ matrix.os }} @@ -22,7 +23,7 @@ jobs: test-extras: # coverage and extra tests only once - - runs-on: ubuntu-latest + runs-on: ubuntu-latest strategy: matrix: python-version: [3.7] From 3c4a5e7304bd8b41c38060a9c9e453ecf4992c59 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 14:00:28 +0200 Subject: [PATCH 0481/1182] worflow --- .github/workflows/pythonpackage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 18a8ad8d00..c2a817cedd 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -27,6 +27,7 @@ jobs: strategy: matrix: python-version: [3.7] + steps: - run: make install - run: make test - run: make test-dist From 525449f044250c2b22359fc536c5f5a7e35f9c8f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 14:01:04 +0200 Subject: [PATCH 0482/1182] worflow --- .github/workflows/pythonpackage.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index c2a817cedd..6fcf22dbbd 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -3,7 +3,6 @@ name: Python package on: [push] jobs: - name: tests test: # run core httpie tests everywhere runs-on: ${{ matrix.os }} From 0169151aa363b0f7fefd47cfd4432c76195c7a8a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 14:02:11 +0200 Subject: [PATCH 0483/1182] worflow --- .github/workflows/pythonpackage.yml | 35 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 6fcf22dbbd..bcaa7318d1 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -11,14 +11,14 @@ jobs: os: [ubuntu-latest, macOS-latest, windows-latest] python-version: [3.6, 3.7] steps: - - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - run: python -m pip install --upgrade pip - - run: pip install --upgrade --editable . - - run: python setup.py test + - uses: actions/checkout@v1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - run: python -m pip install --upgrade pip + - run: pip install --upgrade --editable . + - run: python setup.py test test-extras: # coverage and extra tests only once @@ -27,10 +27,15 @@ jobs: matrix: python-version: [3.7] steps: - - run: make install - - run: make test - - run: make test-dist - - run: make pycodestyle - - run: make coveralls - env: - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + - uses: actions/checkout@v1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - run: make install + - run: make test + - run: make test-dist + - run: make pycodestyle + - run: make coveralls + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} From 92fe452f92fb9516509ca98567e3aa8a4a08b09e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 14:05:40 +0200 Subject: [PATCH 0484/1182] worflow --- .github/workflows/pythonpackage.yml | 35 +++++++++++++++-------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index bcaa7318d1..555ae3e54f 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -3,25 +3,9 @@ name: Python package on: [push] jobs: - test: - # run core httpie tests everywhere - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macOS-latest, windows-latest] - python-version: [3.6, 3.7] - steps: - - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - run: python -m pip install --upgrade pip - - run: pip install --upgrade --editable . - - run: python setup.py test test-extras: - # coverage and extra tests only once + # Run coverage and extra tests only once runs-on: ubuntu-latest strategy: matrix: @@ -39,3 +23,20 @@ jobs: - run: make coveralls env: COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + + test-core: + # Run core httpie tests everywhere + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest, windows-latest] + python-version: [3.6, 3.7] + steps: + - uses: actions/checkout@v1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - run: python -m pip install --upgrade pip + - run: pip install --upgrade --editable . + - run: python setup.py test From ed6156084f150f095587030e8d3b6fa4fbffe03b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 14:14:08 +0200 Subject: [PATCH 0485/1182] Remove .travis.yml --- .travis.yml | 81 ----------------------------------------------------- 1 file changed, 81 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ae55a67263..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,81 +0,0 @@ -# -sudo: false -language: python -os: - - linux -env: - global: - - NEWEST_PYTHON=3.7 -python: - - 3.6 - # - 3.7 # is done in the matrix below as described in travis-ci/travis-ci#9069 - # pypy3 currently fails because of a Flask issue - # - pypy3 - -cache: pip -matrix: - include: - - # Manually defined macOS build - # - - os: osx - language: generic - env: - # 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 - - - # Travis Python 3.7 must run sudo on - - os: linux - 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_PYTHON_PACKAGE" ]]; then - export HOMEBREW_NO_INSTALL_CLEANUP=1 - brew update - if ! brew list --versions "$BREW_PYTHON_PACKAGE" >/dev/null; then - brew install "$BREW_PYTHON_PACKAGE" - elif ! brew outdated "$BREW_PYTHON_PACKAGE"; then - brew upgrade "$BREW_PYTHON_PACKAGE" - fi - fi - pip3 install tox - fi -script: - - | - if [[ $TRAVIS_OS_NAME == 'linux' ]]; then - if [[ $CODESTYLE_ONLY ]]; then - make pycodestyle - else - 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 - 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 From 79b0f65fef83d171c9f0de4a41e5cca8b8bfc41e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 14:14:39 +0200 Subject: [PATCH 0486/1182] Build on push via GitHub Actions --- .github/workflows/{pythonpackage.yml => build.yml} | 10 ++++------ README.rst | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) rename .github/workflows/{pythonpackage.yml => build.yml} (78%) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/build.yml similarity index 78% rename from .github/workflows/pythonpackage.yml rename to .github/workflows/build.yml index 555ae3e54f..f5f1e12e8a 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Python package +name: Build on: [push] @@ -12,8 +12,7 @@ jobs: python-version: [3.7] steps: - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + - uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - run: make install @@ -25,7 +24,7 @@ jobs: COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} test-core: - # Run core httpie tests everywhere + # Run core HTTPie tests everywhere runs-on: ${{ matrix.os }} strategy: matrix: @@ -33,8 +32,7 @@ jobs: python-version: [3.6, 3.7] steps: - uses: actions/checkout@v1 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + - uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - run: python -m pip install --upgrade pip diff --git a/README.rst b/README.rst index a9947f01cd..b12e29c7c3 100644 --- a/README.rst +++ b/README.rst @@ -11,7 +11,7 @@ generally interacting with HTTP servers. .. class:: no-web no-pdf - |pypi| |unix_build| |coverage| |downloads| |gitter| + |pypi| |build| |coverage| |downloads| |gitter| .. class:: no-web no-pdf @@ -1764,9 +1764,9 @@ have contributed. :target: https://coveralls.io/r/jakubroztocil/httpie?branch=master :alt: Test coverage -.. |unix_build| image:: https://img.shields.io/travis/jakubroztocil/httpie/master.svg?style=flat-square&label=unix%20build +.. |build| image::![](https://github.com/jakubroztocil/httpie/workflows/.github/workflows/build.yml/badge.svg) :target: https://travis-ci.org/jakubroztocil/httpie - :alt: Build status of the master branch on Mac/Linux + :alt: Build status of the master branch on Mac/Linux/Windows .. |gitter| image:: https://img.shields.io/gitter/room/jkbrzt/httpie.svg?style=flat-square :target: https://gitter.im/jkbrzt/httpie From b53ace480a6b187671c371edd9aa2a3fff3e157b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 14:18:06 +0200 Subject: [PATCH 0487/1182] Build on push via GitHub Actions --- .github/workflows/build.yml | 4 ++-- README.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f5f1e12e8a..505b594b36 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ on: [push] jobs: - test-extras: + extras: # Run coverage and extra tests only once runs-on: ubuntu-latest strategy: @@ -23,7 +23,7 @@ jobs: env: COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} - test-core: + test: # Run core HTTPie tests everywhere runs-on: ${{ matrix.os }} strategy: diff --git a/README.rst b/README.rst index b12e29c7c3..2805ffc98f 100644 --- a/README.rst +++ b/README.rst @@ -139,7 +139,7 @@ release so the experience might be not as smooth. .. class:: no-pdf -|unix_build| +|build| On macOS you can install it with Homebrew: From 0252c2642ea9393a9ae48f474ff71147a46076b0 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 14:24:55 +0200 Subject: [PATCH 0488/1182] Build badge --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 2805ffc98f..24185ceba0 100644 --- a/README.rst +++ b/README.rst @@ -1764,8 +1764,8 @@ have contributed. :target: https://coveralls.io/r/jakubroztocil/httpie?branch=master :alt: Test coverage -.. |build| image::![](https://github.com/jakubroztocil/httpie/workflows/.github/workflows/build.yml/badge.svg) - :target: https://travis-ci.org/jakubroztocil/httpie +.. |build| image:: https://github.com/jakubroztocil/httpie/workflows/Build/badge.svg + :target: https://github.com/jakubroztocil/httpie/actions :alt: Build status of the master branch on Mac/Linux/Windows .. |gitter| image:: https://img.shields.io/gitter/room/jkbrzt/httpie.svg?style=flat-square From 64c81fc2ec0238fc5fb808b697f0779a99a255eb Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 10 Sep 2019 14:40:34 +0200 Subject: [PATCH 0489/1182] Simplify --- .github/workflows/build.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 505b594b36..193dc139fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,14 +7,11 @@ jobs: extras: # Run coverage and extra tests only once runs-on: ubuntu-latest - strategy: - matrix: - python-version: [3.7] steps: - uses: actions/checkout@v1 - uses: actions/setup-python@v1 with: - python-version: ${{ matrix.python-version }} + python-version: 3.7 - run: make install - run: make test - run: make test-dist From 374c371ef1537fa9313b275998f2b276f4581358 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 16 Sep 2019 13:26:18 +0200 Subject: [PATCH 0490/1182] Add `httpie.status` --- httpie/__init__.py | 20 -------------------- httpie/__main__.py | 2 +- httpie/cli/definition.py | 2 +- httpie/core.py | 20 +++----------------- httpie/status.py | 39 +++++++++++++++++++++++++++++++++++++++ tests/test_cli.py | 2 +- tests/test_errors.py | 2 +- tests/test_exit_status.py | 2 +- tests/test_httpie.py | 7 ++++--- tests/test_output.py | 2 +- tests/test_redirects.py | 2 +- tests/test_ssl.py | 2 +- tests/utils.py | 2 +- 13 files changed, 55 insertions(+), 49 deletions(-) create mode 100644 httpie/status.py diff --git a/httpie/__init__.py b/httpie/__init__.py index 9929885d94..7686500bef 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -2,27 +2,7 @@ HTTPie - a CLI, cURL-like tool for humans. """ -from enum import Enum - __version__ = '2.0.0-dev' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' - - -class ExitStatus(Enum): - """Program exit code constants.""" - SUCCESS = 0 - ERROR = 1 - PLUGIN_ERROR = 7 - - # 128+2 SIGINT - ERROR_CTRL_C = 130 - - ERROR_TIMEOUT = 2 - ERROR_TOO_MANY_REDIRECTS = 6 - - # Used only when requested with --check-status: - ERROR_HTTP_3XX = 3 - ERROR_HTTP_4XX = 4 - ERROR_HTTP_5XX = 5 diff --git a/httpie/__main__.py b/httpie/__main__.py index 08d7a58f97..494a0d1cec 100644 --- a/httpie/__main__.py +++ b/httpie/__main__.py @@ -10,7 +10,7 @@ def main(): from .core import main exit_status = main() except KeyboardInterrupt: - from . import ExitStatus + from httpie.status import ExitStatus exit_status = ExitStatus.ERROR_CTRL_C sys.exit(exit_status.value) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index c770e5db7e..61ed3d3b6a 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -25,7 +25,7 @@ parser = HTTPieArgumentParser( prog='http', - description='%s ' % __doc__.strip(), + description='%s ' % __doc__.strip(), epilog=dedent(""" For every --OPTION there is also a --no-OPTION that reverts OPTION to its default value. diff --git a/httpie/core.py b/httpie/core.py index 69266f3135..84f31fbe13 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -7,7 +7,8 @@ from pygments import __version__ as pygments_version from requests import __version__ as requests_version -from httpie import ExitStatus, __version__ as httpie_version +from httpie import __version__ as httpie_version +from httpie.status import ExitStatus, http_status_to_exit_status from httpie.client import collect_messages from httpie.context import Environment from httpie.downloads import Downloader @@ -154,7 +155,7 @@ def program( else: final_response = message if args.check_status or downloader: - exit_status = get_exit_status( + exit_status = http_status_to_exit_status( http_status=message.status_code, follow=args.follow ) @@ -193,21 +194,6 @@ def program( args.output_file.close() -def get_exit_status(http_status: int, follow=False) -> ExitStatus: - """Translate HTTP status code to exit status code.""" - if 300 <= http_status <= 399 and not follow: - # Redirect - return ExitStatus.ERROR_HTTP_3XX - elif 400 <= http_status <= 499: - # Client Error - return ExitStatus.ERROR_HTTP_4XX - elif 500 <= http_status <= 599: - # Server Error - return ExitStatus.ERROR_HTTP_5XX - else: - return ExitStatus.SUCCESS - - def print_debug_info(env: Environment): env.stderr.writelines([ 'HTTPie %s\n' % httpie_version, diff --git a/httpie/status.py b/httpie/status.py new file mode 100644 index 0000000000..936713835c --- /dev/null +++ b/httpie/status.py @@ -0,0 +1,39 @@ +from enum import Enum + + +class ExitStatus(Enum): + """Program exit code constants.""" + SUCCESS = 0 + ERROR = 1 + PLUGIN_ERROR = 7 + + # 128+2 SIGINT + ERROR_CTRL_C = 130 + + ERROR_TIMEOUT = 2 + ERROR_TOO_MANY_REDIRECTS = 6 + + # Used only when requested with --check-status: + ERROR_HTTP_3XX = 3 + ERROR_HTTP_4XX = 4 + ERROR_HTTP_5XX = 5 + + +def http_status_to_exit_status(http_status: int, follow=False) -> ExitStatus: + """ + Translate HTTP status code to exit status code. + + (Relevant only when invoked with --check-status or --download.) + + """ + if 300 <= http_status <= 399 and not follow: + # Redirect + return ExitStatus.ERROR_HTTP_3XX + elif 400 <= http_status <= 499: + # Client Error + return ExitStatus.ERROR_HTTP_4XX + elif 500 <= http_status <= 599: + # Server Error + return ExitStatus.ERROR_HTTP_5XX + else: + return ExitStatus.SUCCESS diff --git a/tests/test_cli.py b/tests/test_cli.py index 7f1e5f6f6d..439aad3079 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -10,7 +10,7 @@ FILE_CONTENT, FILE_PATH, FILE_PATH_ARG, JSON_FILE_CONTENT, JSON_FILE_PATH_ARG, ) -from httpie import ExitStatus +from httpie.status import ExitStatus from httpie.cli import constants from httpie.cli.definition import parser from httpie.cli.argtypes import KeyValueArg, KeyValueArgType diff --git a/tests/test_errors.py b/tests/test_errors.py index 57788a4060..93594a809b 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -3,7 +3,7 @@ from requests import Request from requests.exceptions import ConnectionError -from httpie import ExitStatus +from httpie.status import ExitStatus from httpie.core import main from utils import HTTP_OK, http diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index fa25036b13..abc9351871 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -1,6 +1,6 @@ import mock -from httpie import ExitStatus +from httpie.status import ExitStatus from utils import MockEnvironment, http, HTTP_OK diff --git a/tests/test_httpie.py b/tests/test_httpie.py index e1a954f95f..430459d58b 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -1,6 +1,7 @@ """High-level tests.""" import pytest +import httpie.status from httpie.cli.exceptions import ParseError from utils import MockEnvironment, http, HTTP_OK from fixtures import FILE_PATH, FILE_CONTENT @@ -10,19 +11,19 @@ def test_debug(): r = http('--debug') - assert r.exit_status == httpie.ExitStatus.SUCCESS + assert r.exit_status == httpie.status.ExitStatus.SUCCESS assert 'HTTPie %s' % httpie.__version__ in r.stderr def test_help(): r = http('--help', tolerate_error_exit_status=True) - assert r.exit_status == httpie.ExitStatus.SUCCESS + assert r.exit_status == httpie.status.ExitStatus.SUCCESS assert 'https://github.com/jakubroztocil/httpie/issues' in r def test_version(): r = http('--version', tolerate_error_exit_status=True) - assert r.exit_status == httpie.ExitStatus.SUCCESS + assert r.exit_status == httpie.status.ExitStatus.SUCCESS # FIXME: py3 has version in stdout, py2 in stderr assert httpie.__version__ == r.strip() diff --git a/tests/test_output.py b/tests/test_output.py index 8bdfa572a7..cbbf8b7325 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -5,7 +5,7 @@ import pytest from utils import MockEnvironment, http, HTTP_OK, COLOR, CRLF -from httpie import ExitStatus +from httpie.status import ExitStatus from httpie.output.formatters.colors import get_lexer diff --git a/tests/test_redirects.py b/tests/test_redirects.py index 95d51fe82a..c1ad95372a 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -1,7 +1,7 @@ """High-level tests.""" import pytest -from httpie import ExitStatus +from httpie.status import ExitStatus from utils import http, HTTP_OK diff --git a/tests/test_ssl.py b/tests/test_ssl.py index e47e160121..051532f87d 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -4,7 +4,7 @@ import pytest_httpbin.certs import requests.exceptions -from httpie import ExitStatus +from httpie.status import ExitStatus from httpie.cli.constants import SSL_VERSION_ARG_MAPPING from utils import HTTP_OK, TESTS_ROOT, http diff --git a/tests/utils.py b/tests/utils.py index bf279ccddb..0bfce07ee0 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -8,7 +8,7 @@ from pathlib import Path from typing import Optional -from httpie import ExitStatus +from httpie.status import ExitStatus from httpie.config import Config from httpie.context import Environment from httpie.core import main From 0df4db7bb40d2a414338f74181e3af618ecf6ea8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 16 Sep 2019 13:28:01 +0200 Subject: [PATCH 0491/1182] Cleanup --- tests/test_httpie.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 430459d58b..cd634c0c9e 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -1,7 +1,7 @@ """High-level tests.""" import pytest -import httpie.status +from httpie.status import ExitStatus from httpie.cli.exceptions import ParseError from utils import MockEnvironment, http, HTTP_OK from fixtures import FILE_PATH, FILE_CONTENT @@ -11,19 +11,19 @@ def test_debug(): r = http('--debug') - assert r.exit_status == httpie.status.ExitStatus.SUCCESS + assert r.exit_status == ExitStatus.SUCCESS assert 'HTTPie %s' % httpie.__version__ in r.stderr def test_help(): r = http('--help', tolerate_error_exit_status=True) - assert r.exit_status == httpie.status.ExitStatus.SUCCESS + assert r.exit_status == ExitStatus.SUCCESS assert 'https://github.com/jakubroztocil/httpie/issues' in r def test_version(): r = http('--version', tolerate_error_exit_status=True) - assert r.exit_status == httpie.status.ExitStatus.SUCCESS + assert r.exit_status == ExitStatus.SUCCESS # FIXME: py3 has version in stdout, py2 in stderr assert httpie.__version__ == r.strip() From 37fa67cd3c3ea6b248209cca9e31702ab63c98c1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 17 Sep 2019 09:07:12 +0200 Subject: [PATCH 0492/1182] Runnable KeyValueArgType.tokenize doctest --- httpie/cli/argtypes.py | 52 ++++++++++++++++++++------------------ httpie/cli/requestitems.py | 2 +- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index 803e066cf7..849503e567 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -2,6 +2,7 @@ import getpass import os import sys +from typing import Union, List from httpie.cli.constants import SEPARATOR_CREDENTIALS from httpie.sessions import VALID_SESSION_NAME_PATTERN @@ -39,11 +40,14 @@ def __call__(self, value): class Escaped(str): """Represents an escaped character.""" + def __repr__(self): + return f"Escaped({repr(str(self))})" + class KeyValueArgType: """A key-value pair argument type used with `argparse`. - Parses a key-value arg and constructs a `KeyValuArge` instance. + Parses a key-value arg and constructs a `KeyValueArg` instance. Used for headers, form data, and other key-value pair types. """ @@ -65,29 +69,7 @@ def __call__(self, string) -> KeyValueArg: as well (r'\\'). """ - - def tokenize(string): - r"""Tokenize `string`. There are only two token types - strings - and escaped characters: - - tokenize(r'foo\=bar\\baz') - => ['foo', Escaped('='), 'bar', Escaped('\\'), 'baz'] - - """ - tokens = [''] - characters = iter(string) - for char in characters: - if char == '\\': - char = next(characters, '') - if char not in self.special_characters: - tokens[-1] += '\\' + char - else: - tokens.extend([Escaped(char), '']) - else: - tokens[-1] += char - return tokens - - tokens = tokenize(string) + tokens = self.tokenize(string) # Sorting by length ensures that the longest one will be # chosen as it will overwrite any shorter ones starting @@ -126,6 +108,28 @@ def tokenize(string): return self.key_value_class( key=key, value=value, sep=sep, orig=string) + def tokenize(self, s: str) -> List[Union[str, Escaped]]: + r"""Tokenize the raw arg string + + There are only two token types - strings and escaped characters: + + >>> KeyValueArgType('=').tokenize(r'foo\=bar\\baz') + ['foo', Escaped('='), 'bar', Escaped('\\'), 'baz'] + + """ + tokens = [''] + characters = iter(s) + for char in characters: + if char == '\\': + char = next(characters, '') + if char not in self.special_characters: + tokens[-1] += '\\' + char + else: + tokens.extend([Escaped(char), '']) + else: + tokens[-1] += char + return tokens + class AuthCredentials(KeyValueArg): """Represents parsed credentials.""" diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index c0293bf90b..1a0116fe55 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -140,7 +140,7 @@ def process_data_raw_json_embed_arg(arg: KeyValueArg) -> JSONType: return value -def load_text_file(item) -> str: +def load_text_file(item: KeyValueArg) -> str: path = item.value try: with open(os.path.expanduser(path), 'rb') as f: From a42b275ae2d71d9042831cc219ae95f462b0b0c1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 17 Sep 2019 09:21:49 +0200 Subject: [PATCH 0493/1182] Typing & cleanup --- httpie/cli/argtypes.py | 53 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index 849503e567..20e83897c9 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -2,7 +2,7 @@ import getpass import os import sys -from typing import Union, List +from typing import Union, List, Optional from httpie.cli.constants import SEPARATOR_CREDENTIALS from httpie.sessions import VALID_SESSION_NAME_PATTERN @@ -11,13 +11,13 @@ class KeyValueArg: """Base key-value pair parsed from CLI.""" - def __init__(self, key, value, sep, orig): + def __init__(self, key: str, value: Optional[str], sep: str, orig: str): self.key = key self.value = value self.sep = sep self.orig = orig - def __eq__(self, other): + def __eq__(self, other: 'KeyValueArg'): return self.__dict__ == other.__dict__ def __repr__(self): @@ -26,10 +26,10 @@ def __repr__(self): class SessionNameValidator: - def __init__(self, error_message): + def __init__(self, error_message: str): self.error_message = error_message - def __call__(self, value): + def __call__(self, value: str) -> str: # 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)): @@ -54,14 +54,14 @@ class KeyValueArgType: key_value_class = KeyValueArg - def __init__(self, *separators): + def __init__(self, *separators: str): self.separators = separators self.special_characters = set('\\') for separator in separators: self.special_characters.update(separator) - def __call__(self, string) -> KeyValueArg: - """Parse `string` and return `self.key_value_class()` instance. + def __call__(self, s: str) -> KeyValueArg: + """Parse raw string arg and return `self.key_value_class` instance. The best of `self.separators` is determined (first found, longest). Back slash escaped characters aren't considered as separators @@ -69,7 +69,7 @@ def __call__(self, string) -> KeyValueArg: as well (r'\\'). """ - tokens = self.tokenize(string) + tokens = self.tokenize(s) # Sorting by length ensures that the longest one will be # chosen as it will overwrite any shorter ones starting @@ -102,11 +102,9 @@ def __call__(self, string) -> KeyValueArg: break else: - raise argparse.ArgumentTypeError( - u'"%s" is not a valid value' % string) + raise argparse.ArgumentTypeError(f'{s!r} is not a valid value') - return self.key_value_class( - key=key, value=value, sep=sep, orig=string) + return self.key_value_class(key=key, value=value, sep=sep, orig=s) def tokenize(self, s: str) -> List[Union[str, Escaped]]: r"""Tokenize the raw arg string @@ -134,42 +132,43 @@ def tokenize(self, s: str) -> List[Union[str, Escaped]]: class AuthCredentials(KeyValueArg): """Represents parsed credentials.""" - def _getpass(self, prompt): - # To allow mocking. - return getpass.getpass(str(prompt)) - - def has_password(self): + def has_password(self) -> bool: return self.value is not None - def prompt_password(self, host): + def prompt_password(self, host: str): + prompt_text = f'http: password for {self.key}@{host}: ' try: - self.value = self._getpass( - 'http: password for %s@%s: ' % (self.key, host)) + self.value = self._getpass(prompt_text) except (EOFError, KeyboardInterrupt): sys.stderr.write('\n') sys.exit(0) + @staticmethod + def _getpass(prompt): + # To allow easy mocking. + return getpass.getpass(str(prompt)) + class AuthCredentialsArgType(KeyValueArgType): """A key-value arg type that parses credentials.""" key_value_class = AuthCredentials - def __call__(self, string): - """Parse credentials from `string`. + def __call__(self, s): + """Parse credentials from `s`. ("username" or "username:password"). """ try: - return super().__call__(string) + return super().__call__(s) except argparse.ArgumentTypeError: # No password provided, will prompt for it later. return self.key_value_class( - key=string, + key=s, value=None, sep=SEPARATOR_CREDENTIALS, - orig=string + orig=s ) @@ -181,4 +180,4 @@ def readable_file_arg(filename): with open(filename, 'rb'): return filename except IOError as ex: - raise argparse.ArgumentTypeError('%s: %s' % (filename, ex.args[1])) + raise argparse.ArgumentTypeError(f'{filename}: {ex.args[1]}') From 85da430d16607eb9e694d04097c08d77c0ef04a7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 18 Sep 2019 11:09:46 +0200 Subject: [PATCH 0494/1182] codecov --- .github/workflows/build.yml | 4 ++-- Makefile | 6 +++--- README.rst | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 193dc139fe..8e33cb32df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,9 +16,9 @@ jobs: - run: make test - run: make test-dist - run: make pycodestyle - - run: make coveralls + - run: make codecov env: - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + CODECOV_TOKEN: ${{ secrets.CODECOV_REPO_TOKEN }} test: # Run core HTTPie tests everywhere diff --git a/Makefile b/Makefile index 544e37c297..58b9e9a582 100644 --- a/Makefile +++ b/Makefile @@ -75,9 +75,9 @@ pycodestyle: @echo -coveralls: - which coveralls || pip install python-coveralls - coveralls +codecov: + which codecov || pip install codecov + codecov @echo diff --git a/README.rst b/README.rst index 24185ceba0..daed98886c 100644 --- a/README.rst +++ b/README.rst @@ -1760,8 +1760,8 @@ have contributed. :target: https://pypi.python.org/pypi/httpie :alt: Latest version released on PyPi -.. |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 +.. |coverage| image:: https://img.shields.io/codecov/c/github/jakubroztocil/httpie?style=flat-square + :target: https://codecov.io/gh/jakubroztocil/httpie :alt: Test coverage .. |build| image:: https://github.com/jakubroztocil/httpie/workflows/Build/badge.svg From 3affc245c4f4f17a398ac3d7549a79f38ffe3bac Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 18 Sep 2019 11:14:34 +0200 Subject: [PATCH 0495/1182] Fix step order --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8e33cb32df..f26329c3d3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,10 +13,10 @@ jobs: with: python-version: 3.7 - run: make install - - run: make test - - run: make test-dist - run: make pycodestyle + - run: make test - run: make codecov + - run: make test-dist env: CODECOV_TOKEN: ${{ secrets.CODECOV_REPO_TOKEN }} From 2dbafe27ed01121cce9700d0f4a2152231622e8b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 18 Sep 2019 11:16:19 +0200 Subject: [PATCH 0496/1182] Fix codecov token --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f26329c3d3..7944b7bf14 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,9 +16,9 @@ jobs: - run: make pycodestyle - run: make test - run: make codecov - - run: make test-dist env: CODECOV_TOKEN: ${{ secrets.CODECOV_REPO_TOKEN }} + - run: make test-dist test: # Run core HTTPie tests everywhere From f031b8cc8b9579a287d55eee1fe40de26284c95e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 18 Sep 2019 11:17:33 +0200 Subject: [PATCH 0497/1182] Make codecov fail loudly --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 58b9e9a582..1b6a3007aa 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,7 @@ pycodestyle: codecov: which codecov || pip install codecov - codecov + codecov --required @echo From d9b3a16fa63211a95accb1021eda68fb140bc772 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 18 Sep 2019 11:57:06 +0200 Subject: [PATCH 0498/1182] Make `ExitStatus` subclass `IntEnum` to allow direct `int` comparisons --- httpie/core.py | 4 ++-- httpie/status.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/httpie/core.py b/httpie/core.py index 84f31fbe13..cf1f16f740 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -68,7 +68,7 @@ def log_error(msg, level='error'): raise exit_status = ExitStatus.ERROR_CTRL_C except SystemExit as e: - if e.code != ExitStatus.SUCCESS.value: + if e.code != ExitStatus.SUCCESS: env.stderr.write('\n') if include_traceback: raise @@ -86,7 +86,7 @@ def log_error(msg, level='error'): raise exit_status = ExitStatus.ERROR_CTRL_C except SystemExit as e: - if e.code != ExitStatus.SUCCESS.value: + if e.code != ExitStatus.SUCCESS: env.stderr.write('\n') if include_traceback: raise diff --git a/httpie/status.py b/httpie/status.py index 936713835c..28c75b63fb 100644 --- a/httpie/status.py +++ b/httpie/status.py @@ -1,7 +1,7 @@ -from enum import Enum +from enum import IntEnum -class ExitStatus(Enum): +class ExitStatus(IntEnum): """Program exit code constants.""" SUCCESS = 0 ERROR = 1 From 9bae27354eb89a5b2e07d9ba249ebd044e4e6448 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 18 Sep 2019 11:57:27 +0200 Subject: [PATCH 0499/1182] Add main entry point tests --- tests/test_httpie.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/test_httpie.py b/tests/test_httpie.py index cd634c0c9e..252b0a17aa 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -1,6 +1,11 @@ """High-level tests.""" +import io +from unittest import mock + import pytest +import httpie.__main__ +from httpie.context import Environment from httpie.status import ExitStatus from httpie.cli.exceptions import ParseError from utils import MockEnvironment, http, HTTP_OK @@ -9,6 +14,23 @@ import httpie +def test_main_entry_point(): + # Patch stdin to bypass pytest capture + with mock.patch.object(Environment, 'stdin', io.StringIO()): + with pytest.raises(SystemExit) as e: + httpie.__main__.main() + assert e.value.code == ExitStatus.ERROR + + +@mock.patch('httpie.core.main') +def test_main_entry_point_keyboard_interrupt(main): + main.side_effect = KeyboardInterrupt() + with mock.patch.object(Environment, 'stdin', io.StringIO()): + with pytest.raises(SystemExit) as e: + httpie.__main__.main() + assert e.value.code == ExitStatus.ERROR_CTRL_C + + def test_debug(): r = http('--debug') assert r.exit_status == ExitStatus.SUCCESS From b48ba74ce28aed9e85a563cd3de481deef8cae34 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 28 Sep 2019 10:36:12 +0200 Subject: [PATCH 0500/1182] Update build.yml --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7944b7bf14..4c8519e624 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,6 +12,7 @@ jobs: - uses: actions/setup-python@v1 with: python-version: 3.7 + - run: pip install --upgrade pip - run: make install - run: make pycodestyle - run: make test From fc497daf7d9a7c9eec1896fad6037c6e861d38d5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 28 Sep 2019 10:36:28 +0200 Subject: [PATCH 0501/1182] Update build.yml --- .github/workflows/build.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4c8519e624..77cf777272 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,9 +1,6 @@ name: Build - on: [push] - jobs: - extras: # Run coverage and extra tests only once runs-on: ubuntu-latest @@ -20,7 +17,6 @@ jobs: env: CODECOV_TOKEN: ${{ secrets.CODECOV_REPO_TOKEN }} - run: make test-dist - test: # Run core HTTPie tests everywhere runs-on: ${{ matrix.os }} From a23b636a6346b7cecb93fcc566aa36c7b2c71c44 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 2 Dec 2019 00:57:29 +0100 Subject: [PATCH 0502/1182] Cleanup --- httpie/status.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/httpie/status.py b/httpie/status.py index 28c75b63fb..2abf291843 100644 --- a/httpie/status.py +++ b/httpie/status.py @@ -1,23 +1,24 @@ -from enum import IntEnum +from enum import IntEnum, unique +@unique class ExitStatus(IntEnum): - """Program exit code constants.""" + """Program exit status code constants.""" SUCCESS = 0 ERROR = 1 - PLUGIN_ERROR = 7 - - # 128+2 SIGINT - ERROR_CTRL_C = 130 - ERROR_TIMEOUT = 2 - ERROR_TOO_MANY_REDIRECTS = 6 - # Used only when requested with --check-status: + # See --check-status ERROR_HTTP_3XX = 3 ERROR_HTTP_4XX = 4 ERROR_HTTP_5XX = 5 + ERROR_TOO_MANY_REDIRECTS = 6 + PLUGIN_ERROR = 7 + # 128+2 SIGINT + # + ERROR_CTRL_C = 130 + def http_status_to_exit_status(http_status: int, follow=False) -> ExitStatus: """ From f0058eeaeeb5e5e442ed2036346995625edb97ce Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 2 Dec 2019 10:42:33 +0100 Subject: [PATCH 0503/1182] cleanup --- httpie/cli/requestitems.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index 1a0116fe55..37392bb081 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -5,10 +5,8 @@ from httpie.cli.argtypes import KeyValueArg from httpie.cli.constants import ( SEPARATOR_DATA_EMBED_FILE_CONTENTS, SEPARATOR_DATA_EMBED_RAW_JSON_FILE, - SEPARATOR_DATA_RAW_JSON, - SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD, SEPARATOR_HEADER, - SEPARATOR_HEADER_EMPTY, - SEPARATOR_QUERY_PARAM, + SEPARATOR_DATA_RAW_JSON, SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD, + SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY, SEPARATOR_QUERY_PARAM, ) from httpie.cli.dicts import ( RequestDataDict, RequestFilesDict, RequestHeadersDict, RequestJSONDataDict, @@ -34,7 +32,7 @@ def from_args( as_form=False, chunked=False ) -> 'RequestItems': - instance = RequestItems(as_form=as_form, chunked=chunked) + instance = cls(as_form=as_form, chunked=chunked) rules: Dict[str, Tuple[Callable, dict]] = { SEPARATOR_HEADER: ( process_header_arg, From f202f338a47d7e2a7e14bb7b14e5c934356ad66e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 2 Dec 2019 17:43:16 +0100 Subject: [PATCH 0504/1182] Remove automatic config file creation to avoid concurrency issues. Close #788 Close #812 --- CHANGELOG.rst | 2 +- README.rst | 54 ++++++++++++++++++++++++++--------------- httpie/cli/argparser.py | 3 +-- httpie/client.py | 2 +- httpie/config.py | 54 ++++++++++++++++++++++------------------- httpie/context.py | 32 +++++++++++++++--------- httpie/core.py | 49 ++++++++++++++++--------------------- httpie/sessions.py | 9 +++---- tests/test_config.py | 44 +++++++++++++++++++++------------ tests/test_errors.py | 31 +++++++++-------------- tests/utils.py | 31 +++++++++++++++-------- 11 files changed, 174 insertions(+), 137 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9e15219c68..c16e570865 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,7 @@ This project adheres to `Semantic Versioning `_. * Removed Python 2.7 support (`EOL Jan 2020 `_). * Removed the default 30-second connection ``--timeout`` limit. * Removed Python’s default limit of 100 response headers. +* Removed automatic config file creation to avoid concurrency issues. * Replaced the old collect-all-then-process handling of HTTP communication with one-by-one processing of each HTTP request or response as they become available. This means that you can see headers immediately, @@ -26,7 +27,6 @@ This project adheres to `Semantic Versioning `_. * Added ``tests/`` to the PyPi package for the convenience of downstream package maintainers. * Fixed an error when ``stdin`` was a closed fd. -* Fixed an error when the config directory was not writeable. * Improved ``--debug`` output formatting. diff --git a/README.rst b/README.rst index daed98886c..6a32f0fffe 100644 --- a/README.rst +++ b/README.rst @@ -1487,7 +1487,8 @@ To create or reuse a different session, simple specify a different name: $ http --session=user2 -a user2:password example.org X-Bar:Foo -Named sessions' data is stored in JSON files in the directory +Named sessions’s data is stored in JSON files in the the ``sessions`` +subdirectory of the `config`_ directory: ``~/.httpie/sessions//.json`` (``%APPDATA%\httpie\sessions\\.json`` on Windows). @@ -1517,45 +1518,60 @@ exchange once it is created, specify the session name via Config ====== -HTTPie uses a simple JSON config file. +HTTPie uses a simple ``config.json`` file. The file doesn’t exist by default +but you can create it manually. +Config file directory +--------------------- -Config file location --------------------- +The default location of the configuration file is ``~/.httpie/config.json`` +(or ``%APPDATA%\httpie\config.json`` on Windows). +The config directory can be changed by setting the ``$HTTPIE_CONFIG_DIR`` +environment variable: + +.. code-block:: bash + + $ export HTTPIE_CONFIG_DIR=/tmp/httpie + $ http example.org + +To view the exact location run ``http --debug``. -The default location of the configuration file is ``~/.httpie/config.json`` -(or ``%APPDATA%\httpie\config.json`` on Windows). The config directory -location can be changed by setting the ``HTTPIE_CONFIG_DIR`` -environment variable. To view the exact location run ``http --debug``. Configurable options -------------------- -The JSON file contains an object with the following keys: +Currently HTTPie offers a single configurable option: ``default_options`` ~~~~~~~~~~~~~~~~~~~ - An ``Array`` (by default empty) of default options that should be applied to every invocation of HTTPie. -For instance, you can use this option to change the default style and output -options: ``"default_options": ["--style=fruity", "--body"]`` Another useful -default option could be ``"--session=default"`` to make HTTPie always -use `sessions`_ (one named ``default`` will automatically be used). -Or you could change the implicit request content type from JSON to form by -adding ``--form`` to the list. +For instance, you can use this config option to change your default color theme: -``__meta__`` -~~~~~~~~~~~~ +.. code-block:: bash + + $ cat ~/.httpie/config.json + + +.. code-block:: json + + { + "default_options": [ + "--style=fruity" + ] + } -HTTPie automatically stores some of its metadata here. Please do not change. +Even though it is technically possible to include there any of HTTPie’s +options, it is not recommended to modify the default behaviour in a way +that would break your compatibility with the wider world as that can +generate a lot of confusion. Un-setting previously specified options diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index fb7d567b4e..4924552e80 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -61,7 +61,6 @@ def __init__(self, *args, formatter_class=HTTPieHelpFormatter, **kwargs): def parse_args( self, env: Environment, - program_name='http', args=None, namespace=None ) -> argparse.Namespace: @@ -89,7 +88,7 @@ def parse_args( if self.has_stdin_data: self._body_from_file(self.env.stdin) if not URL_SCHEME_RE.match(self.args.url): - if os.path.basename(program_name) == 'https': + if os.path.basename(env.program_name) == 'https': scheme = 'https://' else: scheme = self.args.default_scheme + "://" diff --git a/httpie/client.py b/httpie/client.py index 175a89b32a..34aa2f10fc 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -35,7 +35,7 @@ def collect_messages( args: argparse.Namespace, - config_dir: Path + config_dir: Path, ) -> Iterable[Union[requests.PreparedRequest, requests.Response]]: httpie_session = None httpie_session_headers = None diff --git a/httpie/config.py b/httpie/config.py index e7991f129f..821937437b 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -15,42 +15,43 @@ )) +class ConfigFileError(Exception): + pass + + class BaseConfigDict(dict): name = None helpurl = None about = None - def _get_path(self) -> Path: - """Return the config file path without side-effects.""" - raise NotImplementedError() + def __init__(self, path: Path): + super().__init__() + self.path = path - def path(self) -> Path: - """Return the config file path creating basedir, if needed.""" - path = self._get_path() + def ensure_directory(self): try: - path.parent.mkdir(mode=0o700, parents=True) + self.path.parent.mkdir(mode=0o700, parents=True) except OSError as e: if e.errno != errno.EEXIST: raise - return path def is_new(self) -> bool: - return not self._get_path().exists() + return not self.path.exists() def load(self): + config_type = type(self).__name__.lower() try: - with self.path().open('rt') as f: + with self.path.open('rt') as f: try: data = json.load(f) except ValueError as e: - raise ValueError( - 'Invalid %s JSON: %s [%s]' % - (type(self).__name__, str(e), self.path()) + raise ConfigFileError( + f'invalid {config_type} file: {e} [{self.path}]' ) self.update(data) except IOError as e: if e.errno != errno.ENOENT: - raise + raise ConfigFileError(f'cannot read {config_type} file: {e}') def save(self, fail_silently=False): self['__meta__'] = { @@ -62,9 +63,17 @@ def save(self, fail_silently=False): if self.about: self['__meta__']['about'] = self.about + self.ensure_directory() + try: - with self.path().open('w') as f: - json.dump(self, f, indent=4, sort_keys=True, ensure_ascii=True) + with self.path.open('w') as f: + json.dump( + obj=self, + fp=f, + indent=4, + sort_keys=True, + ensure_ascii=True, + ) f.write('\n') except IOError: if not fail_silently: @@ -72,27 +81,22 @@ def save(self, fail_silently=False): def delete(self): try: - self.path().unlink() + self.path.unlink() except OSError as e: if e.errno != errno.ENOENT: raise class Config(BaseConfigDict): - name = 'config' - helpurl = 'https://httpie.org/doc#config' - about = 'HTTPie configuration file' + FILENAME = 'config.json' DEFAULTS = { 'default_options': [] } def __init__(self, directory: Union[str, Path] = DEFAULT_CONFIG_DIR): - super().__init__() - self.update(self.DEFAULTS) self.directory = Path(directory) - - def _get_path(self) -> Path: - return self.directory / (self.name + '.json') + super().__init__(path=self.directory / self.FILENAME) + self.update(self.DEFAULTS) @property def default_options(self) -> list: diff --git a/httpie/context.py b/httpie/context.py index 4c19fc2f3b..4cd8214be5 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -1,3 +1,4 @@ +import os import sys from pathlib import Path from typing import Union, IO, Optional @@ -9,7 +10,7 @@ curses = None # Compiled w/o curses from httpie.compat import is_windows -from httpie.config import DEFAULT_CONFIG_DIR, Config +from httpie.config import DEFAULT_CONFIG_DIR, Config, ConfigFileError from httpie.utils import repr_dict @@ -35,6 +36,7 @@ class Environment: stderr: IO = sys.stderr stderr_isatty: bool = stderr.isatty() colors = 256 + program_name: str = 'http' if not is_windows: if curses: try: @@ -79,16 +81,6 @@ def __init__(self, **kwargs): self.stdout_encoding = getattr( actual_stdout, 'encoding', None) or 'utf8' - @property - def config(self) -> Config: - if not hasattr(self, '_config'): - self._config = Config(directory=self.config_dir) - if self._config.is_new(): - self._config.save(fail_silently=True) - else: - self._config.load() - return self._config - def __str__(self): defaults = dict(type(self).__dict__) actual = dict(defaults) @@ -102,3 +94,21 @@ def __str__(self): def __repr__(self): return f'<{type(self).__name__} {self}>' + + _config: Config = None + + @property + def config(self) -> Config: + config = self._config + if not config: + self._config = config = Config(directory=self.config_dir) + if not config.is_new(): + try: + config.load() + except ConfigFileError as e: + self.log_error(e, level='warning') + return config + + def log_error(self, msg, level='error'): + assert level in ['error', 'warning'] + self.stderr.write(f'\n{self.program_name}: {level}: {msg}\n\n') diff --git a/httpie/core.py b/httpie/core.py index cf1f16f740..575257c16a 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -1,25 +1,25 @@ import argparse +import os import platform import sys -from typing import Callable, List, Union +from typing import List, Union import requests from pygments import __version__ as pygments_version from requests import __version__ as requests_version from httpie import __version__ as httpie_version -from httpie.status import ExitStatus, http_status_to_exit_status from httpie.client import collect_messages from httpie.context import Environment from httpie.downloads import Downloader from httpie.output.writer import write_message, write_stream from httpie.plugins import plugin_manager +from httpie.status import ExitStatus, http_status_to_exit_status def main( args: List[Union[str, bytes]] = sys.argv, env=Environment(), - custom_log_error: Callable = None ) -> ExitStatus: """ The main function. @@ -30,22 +30,16 @@ def main( Return exit status code. """ - args = decode_raw_args(args, env.stdin_encoding) program_name, *args = args + env.program_name = os.path.basename(program_name) + args = decode_raw_args(args, env.stdin_encoding) plugin_manager.load_installed_plugins() - def log_error(msg, level='error'): - assert level in ['error', 'warning'] - env.stderr.write(f'\n{program_name}: {level}: {msg}\n') - from httpie.cli.definition import parser if env.config.default_options: args = env.config.default_options + args - if custom_log_error: - log_error = custom_log_error - include_debug_info = '--debug' in args include_traceback = include_debug_info or '--traceback' in args @@ -59,7 +53,6 @@ def log_error(msg, level='error'): try: parsed_args = parser.parse_args( args=args, - program_name=program_name, env=env, ) except KeyboardInterrupt: @@ -78,7 +71,6 @@ def log_error(msg, level='error'): exit_status = program( args=parsed_args, env=env, - log_error=log_error, ) except KeyboardInterrupt: env.stderr.write('\n') @@ -93,10 +85,10 @@ def log_error(msg, level='error'): exit_status = ExitStatus.ERROR except requests.Timeout: exit_status = ExitStatus.ERROR_TIMEOUT - log_error(f'Request timed out ({parsed_args.timeout}s).') + env.log_error(f'Request timed out ({parsed_args.timeout}s).') except requests.TooManyRedirects: exit_status = ExitStatus.ERROR_TOO_MANY_REDIRECTS - log_error( + env.log_error( f'Too many redirects' f' (--max-redirects=parsed_args.max_redirects).' ) @@ -110,7 +102,7 @@ def log_error(msg, level='error'): f'{msg} while doing a {request.method}' f' request to URL: {request.url}' ) - log_error(f'{type(e).__name__}: {msg}') + env.log_error(f'{type(e).__name__}: {msg}') if include_traceback: raise exit_status = ExitStatus.ERROR @@ -121,7 +113,6 @@ def log_error(msg, level='error'): def program( args: argparse.Namespace, env: Environment, - log_error: Callable ) -> ExitStatus: """ The main program without error handling. @@ -159,8 +150,9 @@ def program( http_status=message.status_code, follow=args.follow ) - if not env.stdout_isatty and exit_status != ExitStatus.SUCCESS: - log_error( + if (not env.stdout_isatty + and exit_status != ExitStatus.SUCCESS): + env.log_error( f'HTTP {message.raw.status} {message.raw.reason}', level='warning' ) @@ -179,10 +171,11 @@ def program( downloader.finish() if downloader.interrupted: exit_status = ExitStatus.ERROR - log_error('Incomplete download: size=%d; downloaded=%d' % ( - downloader.status.total_size, - downloader.status.downloaded - )) + env.log_error( + 'Incomplete download: size=%d; downloaded=%d' % ( + downloader.status.total_size, + downloader.status.downloaded + )) return exit_status finally: @@ -196,11 +189,11 @@ def program( def print_debug_info(env: Environment): env.stderr.writelines([ - 'HTTPie %s\n' % httpie_version, - 'Requests %s\n' % requests_version, - 'Pygments %s\n' % pygments_version, - 'Python %s\n%s\n' % (sys.version, sys.executable), - '%s %s' % (platform.system(), platform.release()), + f'HTTPie {httpie_version}\n', + f'Requests {requests_version}\n', + f'Pygments {pygments_version}\n', + f'Python {sys.version}\n{sys.executable}\n', + f'{platform.system()} {platform.release()}', ]) env.stderr.write('\n\n') env.stderr.write(repr(env)) diff --git a/httpie/sessions.py b/httpie/sessions.py index f1def677d2..7d75583e9c 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -1,4 +1,5 @@ -"""Persistent, JSON-serialized sessions. +""" +Persistent, JSON-serialized sessions. """ import os @@ -53,8 +54,7 @@ class Session(BaseConfigDict): about = 'HTTPie session file' def __init__(self, path: Union[str, Path]): - super().__init__() - self._path = Path(path) + super().__init__(path=Path(path)) self['headers'] = {} self['cookies'] = {} self['auth'] = { @@ -63,9 +63,6 @@ def __init__(self, path: Union[str, Path]): 'password': None } - def _get_path(self) -> Path: - return self._path - def update_headers(self, request_headers: RequestHeadersDict): """ Update the session headers with the request ones while ignoring diff --git a/tests/test_config.py b/tests/test_config.py index 08cfe5de68..45dd86deba 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,6 +1,5 @@ -from httpie import __version__ -from utils import MockEnvironment, http, HTTP_OK -from httpie.context import Environment +from httpie.config import Config +from utils import HTTP_OK, MockEnvironment, http def test_default_options(httpbin): @@ -8,15 +7,33 @@ def test_default_options(httpbin): env.config['default_options'] = ['--form'] env.config.save() r = http(httpbin.url + '/post', 'foo=bar', env=env) - assert r.json['form'] == {"foo": "bar"} + assert r.json['form'] == { + "foo": "bar" + } -def test_config_dir_not_writeable(httpbin): - r = http(httpbin + '/get', env=MockEnvironment( - config_dir='/', - create_temp_config_dir=False, - )) +def test_config_file_not_valid(httpbin): + env = MockEnvironment() + env.create_temp_config_dir() + with (env.config_dir / Config.FILENAME).open('w') as f: + f.write('{invalid json}') + r = http(httpbin + '/get', env=env) assert HTTP_OK in r + assert 'http: warning' in r.stderr + assert 'invalid config file' in r.stderr + + +def test_config_file_not_inaccessible(httpbin): + env = MockEnvironment() + env.create_temp_config_dir() + config_path = env.config_dir / Config.FILENAME + assert not config_path.exists() + config_path.touch(0o000) + assert config_path.exists() + r = http(httpbin + '/get', env=env) + assert HTTP_OK in r + assert 'http: warning' in r.stderr + assert 'cannot read config file' in r.stderr def test_default_options_overwrite(httpbin): @@ -24,9 +41,6 @@ def test_default_options_overwrite(httpbin): env.config['default_options'] = ['--form'] env.config.save() r = http('--json', httpbin.url + '/post', 'foo=bar', env=env) - assert r.json['json'] == {"foo": "bar"} - - -def test_current_version(): - version = MockEnvironment().config['__meta__']['httpie'] - assert version == __version__ + assert r.json['json'] == { + "foo": "bar" + } diff --git a/tests/test_errors.py b/tests/test_errors.py index 93594a809b..4f066a8a5d 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -4,37 +4,30 @@ from requests.exceptions import ConnectionError from httpie.status import ExitStatus -from httpie.core import main from utils import HTTP_OK, http -error_msg = None - - @mock.patch('httpie.core.program') -def test_error(get_response): - def error(msg, *args, **kwargs): - global error_msg - error_msg = msg % args - +def test_error(program): exc = ConnectionError('Connection aborted') exc.request = Request(method='GET', url='http://www.google.com') - get_response.side_effect = exc - ret = main(['http', '--ignore-stdin', 'www.google.com'], custom_log_error=error) - assert ret == ExitStatus.ERROR - assert error_msg == ( - 'ConnectionError: ' - 'Connection aborted while doing a GET request to URL: ' - 'http://www.google.com') + program.side_effect = exc + r = http('www.google.com', tolerate_error_exit_status=True) + assert r.exit_status == ExitStatus.ERROR + assert ( + 'ConnectionError: ' + 'Connection aborted while doing a GET request to URL: ' + 'http://www.google.com' + ) in r.stderr @mock.patch('httpie.core.program') -def test_error_traceback(get_response): +def test_error_traceback(program): exc = ConnectionError('Connection aborted') exc.request = Request(method='GET', url='http://www.google.com') - get_response.side_effect = exc + program.side_effect = exc with raises(ConnectionError): - main(['http', '--ignore-stdin', '--traceback', 'www.google.com']) + http('--traceback', 'www.google.com') def test_max_headers_limit(httpbin_both): diff --git a/tests/utils.py b/tests/utils.py index 0bfce07ee0..34f618031d 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -6,7 +6,7 @@ import json import tempfile from pathlib import Path -from typing import Optional +from typing import Optional, Union from httpie.status import ExitStatus from httpie.config import Config @@ -18,6 +18,7 @@ CRLF = '\r\n' COLOR = '\x1b[' HTTP_OK = '200 OK' +# noinspection GrazieInspection HTTP_OK_COLOR = ( 'HTTP\x1b[39m\x1b[38;5;245m/\x1b[39m\x1b' '[38;5;37m1.1\x1b[39m\x1b[38;5;245m \x1b[39m\x1b[38;5;37m200' @@ -62,10 +63,13 @@ def __init__(self, create_temp_config_dir=True, **kwargs): def config(self) -> Config: if (self._create_temp_config_dir and self._temp_dir not in self.config_dir.parents): - self.config_dir = mk_config_dir() - self._delete_config_dir = True + self.create_temp_config_dir() return super().config + def create_temp_config_dir(self): + self.config_dir = mk_config_dir() + self._delete_config_dir = True + def cleanup(self): self.stdout.close() self.stderr.close() @@ -75,6 +79,7 @@ def cleanup(self): rmtree(self.config_dir) def __del__(self): + # noinspection PyBroadException try: self.cleanup() except Exception: @@ -83,7 +88,7 @@ def __del__(self): class BaseCLIResponse: """ - Represents the result of simulated `$ http' invocation via `http()`. + Represents the result of simulated `$ http' invocation via `http()`. Holds and provides access to: @@ -113,8 +118,8 @@ class StrCLIResponse(str, BaseCLIResponse): @property def json(self) -> Optional[dict]: """ - Return deserialized JSON body, if one included in the output - and is parsable. + Return deserialized the request or response JSON body, + if one (and only one) included in the output and is parsable. """ if not hasattr(self, '_json'): @@ -147,7 +152,12 @@ class ExitStatusError(Exception): pass -def http(*args, program_name='http', **kwargs): +def http( + *args, + program_name='http', + tolerate_error_exit_status=False, + **kwargs, +) -> Union[StrCLIResponse, BytesCLIResponse]: # noinspection PyUnresolvedReferences """ Run HTTPie and capture stderr/out and exit status. @@ -188,7 +198,6 @@ def http(*args, program_name='http', **kwargs): True """ - tolerate_error_exit_status = kwargs.pop('tolerate_error_exit_status', False) env = kwargs.get('env') if not env: env = kwargs['env'] = MockEnvironment() @@ -200,7 +209,8 @@ def http(*args, program_name='http', **kwargs): args_with_config_defaults = args + env.config.default_options add_to_args = [] if '--debug' not in args_with_config_defaults: - if not tolerate_error_exit_status and '--traceback' not in args_with_config_defaults: + if (not tolerate_error_exit_status + and '--traceback' not in args_with_config_defaults): add_to_args.append('--traceback') if not any('--timeout' in arg for arg in args_with_config_defaults): add_to_args.append('--timeout=3') @@ -228,7 +238,8 @@ def dump_stderr(): sys.stderr.write(stderr.read()) raise else: - if not tolerate_error_exit_status and exit_status != ExitStatus.SUCCESS: + if (not tolerate_error_exit_status + and exit_status != ExitStatus.SUCCESS): dump_stderr() raise ExitStatusError( 'httpie.core.main() unexpectedly returned' From 6cb822255d333c92b79c37e688d40f1ea18ff283 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 2 Dec 2019 17:46:40 +0100 Subject: [PATCH 0505/1182] PEP8 --- tests/test_errors.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/test_errors.py b/tests/test_errors.py index 4f066a8a5d..ec6ca5a4e9 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -14,11 +14,12 @@ def test_error(program): program.side_effect = exc r = http('www.google.com', tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR - assert ( - 'ConnectionError: ' - 'Connection aborted while doing a GET request to URL: ' - 'http://www.google.com' - ) in r.stderr + error_msg = ( + 'ConnectionError: ' + 'Connection aborted while doing a GET request to URL: ' + 'http://www.google.com' + ) + assert error_msg in r.stderr @mock.patch('httpie.core.program') From 0af486d1b7dd019d2f8271f875fbb0440076e3e4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 2 Dec 2019 17:53:29 +0100 Subject: [PATCH 0506/1182] Ignore test cleanup rmtree errors (Win) --- tests/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/utils.py b/tests/utils.py index 34f618031d..9c2f2a04de 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -76,7 +76,7 @@ def cleanup(self): if self._delete_config_dir: assert self._temp_dir in self.config_dir.parents from shutil import rmtree - rmtree(self.config_dir) + rmtree(self.config_dir, ignore_errors=True) def __del__(self): # noinspection PyBroadException From 7390869cd670019267a6c8837ddefe091d3b86c2 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 2 Dec 2019 17:59:44 +0100 Subject: [PATCH 0507/1182] Skip test_config_file_inaccessible on Windows --- tests/test_config.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_config.py b/tests/test_config.py index 45dd86deba..0a33ef6864 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,3 +1,6 @@ +import pytest + +from httpie.compat import is_windows from httpie.config import Config from utils import HTTP_OK, MockEnvironment, http @@ -23,7 +26,8 @@ def test_config_file_not_valid(httpbin): assert 'invalid config file' in r.stderr -def test_config_file_not_inaccessible(httpbin): +@pytest.mark.skipif(is_windows, reason='cannot chmod 000 on Windows') +def test_config_file_inaccessible(httpbin): env = MockEnvironment() env.create_temp_config_dir() config_path = env.config_dir / Config.FILENAME From ab2bda3ffe90fc67cef29399dcaee0de056e7050 Mon Sep 17 00:00:00 2001 From: onnadi-sa <51714064+onnadi-sa@users.noreply.github.com> Date: Mon, 2 Dec 2019 11:04:52 -0600 Subject: [PATCH 0508/1182] Fix typo (#808) --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6a32f0fffe..eb8e34eca0 100644 --- a/README.rst +++ b/README.rst @@ -794,7 +794,7 @@ For example: HTTP/1.1 200 OK [...] -This can be disable with the ``--ignore-netrc`` option: +This can be disabled with the ``--ignore-netrc`` option: .. code-block:: bash From dcd6b63e4597f5a17fe9ee72285cbff705afa98f Mon Sep 17 00:00:00 2001 From: Semen Zhydenko Date: Mon, 2 Dec 2019 18:12:51 +0100 Subject: [PATCH 0509/1182] withing -> within (#795) --- tests/test_sessions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index e199eec68f..3b7c7ed5f6 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -24,7 +24,7 @@ def env(self): """ Return an environment. - Each environment created withing a test method + Each environment created within a test method will share the same config_dir. It is necessary for session files being reused. From fcc3aaf873e88060d3b2bfdf558c934ee3713a56 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 2 Dec 2019 20:39:00 +0100 Subject: [PATCH 0510/1182] Add Python 3.8 build --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 77cf777272..0979d5c4ae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-python@v1 with: - python-version: 3.7 + python-version: 3.8 - run: pip install --upgrade pip - run: make install - run: make pycodestyle @@ -23,7 +23,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] - python-version: [3.6, 3.7] + python-version: [3.6, 3.7, 3.8] steps: - uses: actions/checkout@v1 - uses: actions/setup-python@v1 From 0608b5869f91e23c71bf19fc235eabc35fb1a1c3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 2 Dec 2019 20:47:09 +0100 Subject: [PATCH 0511/1182] Upgrade setuptools --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0979d5c4ae..484424d3d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ jobs: - uses: actions/setup-python@v1 with: python-version: 3.8 - - run: pip install --upgrade pip + - run: pip install --upgrade pip setuptools - run: make install - run: make pycodestyle - run: make test @@ -29,6 +29,6 @@ jobs: - uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - - run: python -m pip install --upgrade pip + - run: python -m pip install --upgrade pip setuptools - run: pip install --upgrade --editable . - run: python setup.py test From 6e2c31a5a95f011d337ea71196a5d5e7c8cf5283 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 2 Dec 2019 20:57:21 +0100 Subject: [PATCH 0512/1182] Fix build --- .github/workflows/build.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 484424d3d0..7190b4fe09 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ jobs: - uses: actions/setup-python@v1 with: python-version: 3.8 - - run: pip install --upgrade pip setuptools + - run: pip install --upgrade pip - run: make install - run: make pycodestyle - run: make test @@ -24,11 +24,14 @@ jobs: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] python-version: [3.6, 3.7, 3.8] + exclude: + - os: windows-latest + python-version: 3.8 steps: - uses: actions/checkout@v1 - uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - - run: python -m pip install --upgrade pip setuptools + - run: python -m pip install --upgrade pip - run: pip install --upgrade --editable . - run: python setup.py test From f1ab816ecd2526c12ccff07d9384d89002d8e27c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 3 Dec 2019 12:23:33 +0100 Subject: [PATCH 0513/1182] Tweak querystring parameters doc --- README.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index eb8e34eca0..f76e99d6b6 100644 --- a/README.rst +++ b/README.rst @@ -294,20 +294,22 @@ Querystring parameters 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, -will also automatically escaped (HTTPie otherwise expects the URL to be -already escaped). To search for ``HTTPie logo`` on Google Images you could use -this command: +URL parameters. + +With that, you don't have to worry about escaping the ``&`` +separators for your shell. Additionally, any special characters in the +parameter name or value get automatically URL-escaped +(as opposed to parameters specified in the full URL, which HTTPie doesn’t +modify). .. code-block:: bash - $ http www.google.com search=='HTTPie logo' tbm==isch + $ http https://api.github.com/search/repositories q==httpie per_page==1 .. code-block:: http - GET /?search=HTTPie+logo&tbm=isch HTTP/1.1 + GET /search/repositories?q=httpie&per_page=1 HTTP/1.1 From 490eeaa650a4dbffd411413e183b96ce806939dd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 3 Dec 2019 19:09:09 +0100 Subject: [PATCH 0514/1182] Cleanup --- httpie/cli/constants.py | 2 +- httpie/client.py | 8 ++++---- httpie/sessions.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index 2b22fbe033..ba34dcc9d6 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -6,7 +6,7 @@ # TODO: Use MultiDict for headers once added to `requests`. -# https://github.com/jakubroztocil/httpie/issues/130 +# # ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) diff --git a/httpie/client.py b/httpie/client.py index 34aa2f10fc..431bee4f39 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -183,13 +183,13 @@ def finalize_headers(headers: RequestHeadersDict) -> RequestHeadersDict: final_headers = RequestHeadersDict() for name, value in headers.items(): if value is not None: - # >leading or trailing LWS MAY be removed without - # >changing the semantics of the field value" - # -https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html + # “leading or trailing LWS MAY be removed without + # changing the semantics of the field value” + # # Also, requests raises `InvalidHeader` for leading spaces. value = value.strip() if isinstance(value, str): - # See: https://github.com/jakubroztocil/httpie/issues/212 + # See value = value.encode('utf8') final_headers[name] = value return final_headers diff --git a/httpie/sessions.py b/httpie/sessions.py index 7d75583e9c..7ed7331e1e 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -21,7 +21,7 @@ VALID_SESSION_NAME_PATTERN = re.compile('^[a-zA-Z0-9_.-]+$') # Request headers starting with these prefixes won't be stored in sessions. # They are specific to each request. -# https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requests +# SESSION_IGNORED_HEADER_PREFIXES = ['Content-', 'If-'] @@ -102,7 +102,7 @@ def cookies(self) -> RequestsCookieJar: @cookies.setter def cookies(self, jar: RequestsCookieJar): - # https://docs.python.org/2/library/cookielib.html#cookie-objects + # stored_attrs = ['value', 'path', 'secure', 'expires'] self['cookies'] = {} for cookie in jar: From 89faec994a56698746077ed6ea0d18a26c7fa3e0 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Wed, 4 Dec 2019 23:32:08 +1100 Subject: [PATCH 0515/1182] Fix simple typo: downland -> download (#823) Closes #822 --- httpie/downloads.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/downloads.py b/httpie/downloads.py index 78e1eb209f..2a1beeacbf 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -347,7 +347,7 @@ def _get_output_file_from_response( class DownloadStatus: - """Holds details about the downland status.""" + """Holds details about the download status.""" def __init__(self): self.downloaded = 0 From 615d8875131a686113c5726699d9bac84f1553f2 Mon Sep 17 00:00:00 2001 From: Roger Wernersson Date: Wed, 4 Dec 2019 13:33:13 +0100 Subject: [PATCH 0516/1182] run rst2pseudoxml.py with shell=true (#821) makes rst2pseudoxml.py work properly on Windows executes via a shell instead of not working --- tests/test_docs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_docs.py b/tests/test_docs.py index 766810afd8..3966f81d94 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -34,7 +34,8 @@ def test_rst_file_syntax(filename): p = subprocess.Popen( ['rst2pseudoxml.py', '--report=1', '--exit-status=1', filename], stderr=subprocess.PIPE, - stdout=subprocess.PIPE + stdout=subprocess.PIPE, + shell=True ) err = p.communicate()[1] assert p.returncode == 0, err.decode('utf8') From e8b22d8b5123b71fab43de41e3c43b5bf05f5c56 Mon Sep 17 00:00:00 2001 From: Roger Wernersson Date: Wed, 4 Dec 2019 13:37:57 +0100 Subject: [PATCH 0517/1182] exclude site-packages from .rst file scanning (#820) make test fails when finding .rst files from site packages installed in the virtual environment --- tests/test_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_docs.py b/tests/test_docs.py index 3966f81d94..304d8ef920 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -19,7 +19,7 @@ def has_docutils(): def rst_filenames(): # noinspection PyShadowingNames for root, dirnames, filenames in os.walk(os.path.dirname(TESTS_ROOT)): - if '.tox' not in root: + if '.tox' not in root and 'site-packages' not in root: for filename in fnmatch.filter(filenames, '*.rst'): yield os.path.join(root, filename) From 5aa9ed795ea85eba4f28d53279f0b92365f6a2fe Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 4 Dec 2019 13:51:45 +0100 Subject: [PATCH 0518/1182] Switch to explicitly listed directories to search in for `*.rst` #820 --- tests/test_docs.py | 27 +++++++++++++++++++-------- tests/utils.py | 2 +- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/tests/test_docs.py b/tests/test_docs.py index 304d8ef920..f850c588b3 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -1,12 +1,19 @@ import os -import fnmatch import subprocess +from glob import glob import pytest from utils import TESTS_ROOT +SOURCE_DIRECTORIES = [ + 'extras', + 'httpie', + 'tests', +] + + def has_docutils(): try: # noinspection PyUnresolvedReferences,PyPackageRequirements @@ -17,25 +24,29 @@ def has_docutils(): def rst_filenames(): - # noinspection PyShadowingNames - for root, dirnames, filenames in os.walk(os.path.dirname(TESTS_ROOT)): - if '.tox' not in root and 'site-packages' not in root: - for filename in fnmatch.filter(filenames, '*.rst'): - yield os.path.join(root, filename) + cwd = os.getcwd() + os.chdir(TESTS_ROOT.parent) + try: + yield from glob('*.rst') + for directory in SOURCE_DIRECTORIES: + yield from glob(f'{directory}/**/*.rst', recursive=True) + finally: + os.chdir(cwd) -filenames = list(rst_filenames()) +filenames = list(sorted(rst_filenames())) assert filenames @pytest.mark.skipif(not has_docutils(), reason='docutils not installed') @pytest.mark.parametrize('filename', filenames) def test_rst_file_syntax(filename): + print(filename) p = subprocess.Popen( ['rst2pseudoxml.py', '--report=1', '--exit-status=1', filename], stderr=subprocess.PIPE, stdout=subprocess.PIPE, - shell=True + shell=True, ) err = p.communicate()[1] assert p.returncode == 0, err.decode('utf8') diff --git a/tests/utils.py b/tests/utils.py index 9c2f2a04de..690765af5b 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -14,7 +14,7 @@ from httpie.core import main -TESTS_ROOT = os.path.abspath(os.path.dirname(__file__)) +TESTS_ROOT = Path(__file__).parent CRLF = '\r\n' COLOR = '\x1b[' HTTP_OK = '200 OK' From fe8b547cc7b67c9ca7982ada55de6dc5d072037e Mon Sep 17 00:00:00 2001 From: Martin Hellspong Date: Wed, 4 Dec 2019 13:54:00 +0100 Subject: [PATCH 0519/1182] Fix make target in CONTRIBUTING.rst (#819) --- CONTRIBUTING.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index f0126ac9ba..80d860413a 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -47,7 +47,7 @@ Go to https://github.com/jakubroztocil/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 init + make install Making Changes From 1bc54d4cb4827b3a411fec880248985e04217b58 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 4 Dec 2019 17:49:07 +0100 Subject: [PATCH 0520/1182] Create Python virtual environment (via venv) for tests & development, etc. --- .github/workflows/build.yml | 4 +- .gitignore | 141 ++++++++++++++++++++++++++++++++++-- CONTRIBUTING.rst | 106 +++++++++++++++++++++------ Makefile | 115 +++++++++++++++++++---------- 4 files changed, 298 insertions(+), 68 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7190b4fe09..2acc5b7f17 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,8 +12,8 @@ jobs: - run: pip install --upgrade pip - run: make install - run: make pycodestyle - - run: make test - - run: make codecov + - run: make test-cover + - run: make codecov-upload env: CODECOV_TOKEN: ${{ secrets.CODECOV_REPO_TOKEN }} - run: make test-dist diff --git a/.gitignore b/.gitignore index 7da36e0c97..762a8407da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,142 @@ .DS_Store .idea/ -__pycache__/ -dist/ -build/ *.egg-info .cache/ -.tox/ -.coverage *.pyc -*.egg htmlcov + + +############################################################################## +# The bellow is GitHub template for Python project. gitignore. +# +############################################################################## + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ .pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 80d860413a..78b1a8254b 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -29,25 +29,75 @@ is a bigger one, it's always good to discuss before you start working on it. -Creating Development Environment +Development Environment -------------------------------- + +Getting the code +**************** + Go to https://github.com/jakubroztocil/httpie and fork the project repository. .. code-block:: bash - git clone https://github.com//httpie + # Clone your fork + git clone git@github.com:/httpie.git + # Enter the project directory cd httpie + # Create a branch for your changes git checkout -b my_topical_branch - # (Recommended: create a new virtualenv) - # Install dev. requirements and also HTTPie (in editable mode - # so that the `http' command will point to your working copy): - make install +Setup +***** + +The `Makefile`_ contains a bunch of tasks to get you started. Just run +the following command: + + +.. code-block:: bash + + make + +* The commands creates an isolated Python virtual environment inside ``./venv`` + (via the standard library `venv`_ tool); +* installs all dependencies and also installs HTTPie + (in editable mode so that the ``http`` command will point to your + working copy). +* and runs tests (It is the same as running ``make install test``). + + +Python virtual environment +************************** + +Activate the Python virtual environment—created via the ``make install`` +task during `setup`_—for your active shell session using the following command: + +.. code-block:: bash + + source venv/bin/activate + +(If you use ``virtualenvwrapper``, you can also use ``workon httpie`` to +active the environment — we have created a symlink for you. It’s a bit of +a hack but it works™.) + +You should now see ``(httpie)`` next to your shell prompt, and +the ``http`` should point to you development copy: + +.. code-block:: + + (httpie) ~/Code/httpie $ which http + /Users/jakub/Code/httpie/venv/bin/http + (httpie) ~/Code/httpie $ http --version + 2.0.0-dev + +(Btw, you don’t need to activate the virtual environment if you just want +run some of the ``make`` tasks. You can also invoke the development +version of HTTPie directly with ``./venv/bin/http`` without having to activate +the environment first. The same goes for ``./venv/bin/py.test``, etc.). Making Changes @@ -57,36 +107,47 @@ Please make sure your changes conform to `Style Guide for Python Code`_ (PEP8) and that ``make pycodestyle`` passes. -Testing -------- +Testing & CI +------------ -Before opening a pull requests, please make sure the `test suite`_ passes -in all of the `supported Python environments`_. You should also add tests -for any new features and bug fixes. +Please add tests for any new features and bug fixes. -HTTPie uses `pytest`_ and `Tox`_ for testing. +When you open a pull request, +`Github Actions `_ +will automatically run HTTPie’s `test suite`_ against your code +so please make sure all checks pass. -Running all tests: -****************** +Running tests locally +********************* + +HTTPie uses the `pytest`_ runner. It also uses `Tox`_ which allows you to run +tests on multiple Python versions even when testing locally. + .. code-block:: bash - # Run all tests on the current Python interpreter with coverage + # Run tests on the current Python interpreter with coverage. make test + # Run tests 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 + # Run extended tests — for code as well as .rst files syntax, packaging, etc. + make test-all + -Running specific tests: -*********************** +Running specific tests +********************** + +After you have activated your virtual environment (see `setup`_), you +can run specific tests from the terminal: .. code-block:: bash @@ -104,7 +165,9 @@ Running specific tests: ----- See `Makefile`_ for additional development utilities. -Don't forget to add yourself to `AUTHORS`_! + + +Finally, don't forget to add yourself to `AUTHORS`_! .. _Tox: http://tox.testrun.org @@ -112,6 +175,7 @@ Don't forget to add yourself to `AUTHORS`_! .. _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 +.. _venv: https://docs.python.org/3/library/venv.html .. _pytest: https://pytest.org/ .. _Style Guide for Python Code: https://python.org/dev/peps/pep-0008/ .. _test suite: https://github.com/jakubroztocil/httpie/tree/master/tests diff --git a/Makefile b/Makefile index 1b6a3007aa..a141b57fd7 100644 --- a/Makefile +++ b/Makefile @@ -2,29 +2,68 @@ # See ./CONTRIBUTING.rst ############################################################################### +ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) VERSION=$(shell grep __version__ httpie/__init__.py) -REQUIREMENTS="requirements-dev.txt" -TAG="\n\n\033[0;32m\#\#\# " -END=" \#\#\# \033[0m\n" +REQUIREMENTS=requirements-dev.txt +H1="\n\n\033[0;32m\#\#\# " +H1END=" \#\#\# \033[0m\n" + + +# Only used to create our venv. +SYSTEM_PYTHON=python3 + +VENV_ROOT=venv +VENV_BIN=$(VENV_ROOT)/bin +VENV_PIP=$(VENV_BIN)/pip3 +VENV_PYTHON=$(VENV_BIN)/python3 all: uninstall-httpie install test -install: - @echo $(TAG)Installing dev requirements$(END) - pip install --upgrade -r $(REQUIREMENTS) +install: venv + @echo $(H1)Installing dev requirements$(H1END) + $(VENV_PIP) install --upgrade -r $(REQUIREMENTS) - @echo $(TAG)Installing HTTPie$(END) - pip install --upgrade --editable . + @echo $(H1)Installing HTTPie$(H1END) + $(VENV_PIP) install --upgrade --editable . @echo clean: - @echo $(TAG)Cleaning up$(END) + @echo $(H1)Cleaning up$(H1END) + rm -rf $(VENV_ROOT) + # Symlink for virtualenvwrapper, if we’ve created one. + [ -n "$(WORKON_HOME)" -a -L "$(WORKON_HOME)/httpie" -a -f "$(WORKON_HOME)/httpie" ] && rm $(WORKON_HOME)/httpie || true rm -rf .tox *.egg dist build .coverage .cache .pytest_cache httpie.egg-info - find . -name '__pycache__' -delete -print -o -name '*.pyc' -delete -print + find . -name '__pycache__' -delete -o -name '*.pyc' -delete + @echo + + +venv: + @echo $(H1)Creating a Python environment $(VENV_ROOT) $(H1END) + + $(SYSTEM_PYTHON) -m venv --prompt httpie $(VENV_ROOT) + + @echo + @echo done. @echo + @echo To active it manually, run: + @echo + @echo " source $(VENV_BIN)/activate" + @echo + @echo '(learn more: https://docs.python.org/3/library/venv.html)' + @echo + @if [ -n "$(WORKON_HOME)" ]; then \ + echo $(ROOT_DIR) > $(VENV_ROOT)/.project; \ + if [ ! -d $(WORKON_HOME)/httpie -a ! -L $(WORKON_HOME)/httpie ]; then \ + ln -s $(ROOT_DIR)/$(VENV_ROOT) $(WORKON_HOME)/httpie ; \ + echo ''; \ + echo 'Since you use virtualenvwrapper, we created a symlink'; \ + echo 'so you can also use "workon httpie" to activate the venv.'; \ + echo ''; \ + fi; \ + fi ############################################################################### @@ -33,13 +72,18 @@ clean: test: - @echo $(TAG)Running tests on the current Python interpreter with coverage $(END) - py.test --cov ./httpie --cov ./tests --doctest-modules --verbose ./httpie ./tests + @echo $(H1)Running tests on the current Python interpreter $(HEADER_EXTRA) $(H1END) + $(VENV_BIN)/py.test $(COV) ./httpie $(COV) ./tests --doctest-modules --verbose ./httpie ./tests @echo +test-cover: COV=--cov +test-cover: HEADER_EXTRA='(with coverage)' +test-cover: test + + # test-all is meant to test everything — even this Makefile -test-all: uninstall-all clean install test test-tox test-dist pycodestyle +test-all: clean install test test-tox test-dist pycodestyle @echo @@ -48,36 +92,38 @@ test-dist: test-sdist test-bdist-wheel test-tox: uninstall-httpie install - @echo $(TAG)Running tests on all Pythons via Tox$(END) + @echo $(H1)Running tests on all Pythons via Tox$(H1END) tox @echo test-sdist: clean uninstall-httpie - @echo $(TAG)Testing sdist build an installation$(END) - python setup.py sdist - pip install --force-reinstall --upgrade dist/*.gz - which http + @echo $(H1)Testing sdist build an installation$(H1END) + $(VENV_PYTHON) setup.py sdist + $(VENV_PIP) install --force-reinstall --upgrade dist/*.gz + $(VENV_BIN)/http --version @echo test-bdist-wheel: clean uninstall-httpie - @echo $(TAG)Testing wheel build an installation$(END) - python setup.py bdist_wheel - pip install --force-reinstall --upgrade dist/*.whl - which http + @echo $(H1)Testing wheel build an installation$(H1END) + $(VENV_PYTHON) setup.py bdist_wheel + $(VENV_PIP) install --force-reinstall --upgrade dist/*.whl + $(VENV_BIN)/http --version @echo pycodestyle: - which pycodestyle || pip install pycodestyle - pycodestyle + @echo $(H1)Running pycodestyle$(H1END) + @[ -f $(VENV_BIN)/pycodestyle ] || $(VENV_PIP) install pycodestyle + $(VENV_BIN)/pycodestyle httpie/ tests/ extras/ *.py @echo -codecov: - which codecov || pip install codecov - codecov --required +codecov-upload: + @echo $(H1)Running codecov$(H1END) + @[ -f $(VENV_BIN)/codecov ] || $(VENV_PIP) install codecov + $(VENV_BIN)/codecov --required @echo @@ -90,7 +136,7 @@ publish: test-all publish-no-test publish-no-test: - @echo $(TAG)Testing wheel build an installation$(END) + @echo $(H1)Testing wheel build an installation$(H1END) @echo "$(VERSION)" @echo "$(VERSION)" | grep -q "dev" && echo '!!!Not publishing dev version!!!' && exit 1 || echo ok python setup.py sdist bdist_wheel @@ -104,8 +150,8 @@ publish-no-test: ############################################################################### uninstall-httpie: - @echo $(TAG)Uninstalling httpie$(END) - - pip uninstall --yes httpie &2>/dev/null + @echo $(H1)Uninstalling httpie$(H1END) + - $(VENV_PIP) uninstall --yes httpie &2>/dev/null @echo "Verifying…" cd .. && ! python -m httpie --version &2>/dev/null @@ -114,15 +160,6 @@ uninstall-httpie: @echo -uninstall-all: uninstall-httpie - - @echo $(TAG)Uninstalling httpie requirements$(END) - - pip uninstall --yes pygments requests - - @echo $(TAG)Uninstalling development requirements$(END) - - pip uninstall --yes -r $(REQUIREMENTS) - - ############################################################################### # Docs ############################################################################### From 38bc57874420698158bf1ea6261f6efea61379a7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 4 Dec 2019 18:09:51 +0100 Subject: [PATCH 0521/1182] Fix tests --- Makefile | 8 ++++---- tests/test_docs.py | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index a141b57fd7..757924b8b9 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,7 @@ test-dist: test-sdist test-bdist-wheel test-tox: uninstall-httpie install @echo $(H1)Running tests on all Pythons via Tox$(H1END) - tox + $(VENV_BIN)/tox @echo @@ -139,8 +139,8 @@ publish-no-test: @echo $(H1)Testing wheel build an installation$(H1END) @echo "$(VERSION)" @echo "$(VERSION)" | grep -q "dev" && echo '!!!Not publishing dev version!!!' && exit 1 || echo ok - python setup.py sdist bdist_wheel - twine upload dist/* + $(VENV_PYTHON) setup.py sdist bdist_wheel + $(VENV_BIN)/twine upload dist/* @echo @@ -154,7 +154,7 @@ uninstall-httpie: - $(VENV_PIP) uninstall --yes httpie &2>/dev/null @echo "Verifying…" - cd .. && ! python -m httpie --version &2>/dev/null + cd .. && ! $(VENV_PYTHON) -m httpie --version &2>/dev/null @echo "Done" @echo diff --git a/tests/test_docs.py b/tests/test_docs.py index f850c588b3..7a418228c0 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -1,6 +1,7 @@ import os import subprocess from glob import glob +from pathlib import Path import pytest @@ -38,12 +39,24 @@ def rst_filenames(): assert filenames -@pytest.mark.skipif(not has_docutils(), reason='docutils not installed') +# HACK: hardcoded paths, venv should be irrelevant, etc. +# TODO: replaces the process with Python code +VENV_BIN = Path(__file__).parent.parent / 'venv/bin' +VENV_PYTHON = VENV_BIN / 'python' +VENV_RST2PSEUDOXML = VENV_BIN / 'rst2pseudoxml.py' + + +@pytest.mark.skipif(not os.path.exists(VENV_RST2PSEUDOXML), reason='docutils not installed') @pytest.mark.parametrize('filename', filenames) def test_rst_file_syntax(filename): - print(filename) p = subprocess.Popen( - ['rst2pseudoxml.py', '--report=1', '--exit-status=1', filename], + [ + VENV_PYTHON, + VENV_RST2PSEUDOXML, + '--report=1', + '--exit-status=1', + filename, + ], stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True, From cd5116705cc0ce8af9cba79729f11ae29b3abef8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 4 Dec 2019 18:24:53 +0100 Subject: [PATCH 0522/1182] Set path in makefile --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 757924b8b9..7b4608754f 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,9 @@ VENV_PIP=$(VENV_BIN)/pip3 VENV_PYTHON=$(VENV_BIN)/python3 +export PATH := $(VENV_BIN):$(PATH) + + all: uninstall-httpie install test From ab3ea24630c2d0da474d95b536f5b9383c68b817 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 4 Dec 2019 18:34:26 +0100 Subject: [PATCH 0523/1182] Fixes --- CONTRIBUTING.rst | 14 ++++++++------ Makefile | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 78b1a8254b..0232538482 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -55,14 +55,10 @@ Setup ***** The `Makefile`_ contains a bunch of tasks to get you started. Just run -the following command: +the following command, which: -.. code-block:: bash - - make - -* The commands creates an isolated Python virtual environment inside ``./venv`` +* Creates an isolated Python virtual environment inside ``./venv`` (via the standard library `venv`_ tool); * installs all dependencies and also installs HTTPie (in editable mode so that the ``http`` command will point to your @@ -70,6 +66,12 @@ the following command: * and runs tests (It is the same as running ``make install test``). +.. code-block:: bash + + make + + + Python virtual environment ************************** diff --git a/Makefile b/Makefile index 7b4608754f..d40fa75cc0 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ SYSTEM_PYTHON=python3 VENV_ROOT=venv VENV_BIN=$(VENV_ROOT)/bin VENV_PIP=$(VENV_BIN)/pip3 -VENV_PYTHON=$(VENV_BIN)/python3 +VENV_PYTHON=$(VENV_BIN)/python export PATH := $(VENV_BIN):$(PATH) From 348cc7d5c541baffa80859b1f2edda408e23b9bc Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 4 Dec 2019 18:48:39 +0100 Subject: [PATCH 0524/1182] Fixes --- CONTRIBUTING.rst | 2 +- Makefile | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 0232538482..7f959a0ab1 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -83,7 +83,7 @@ task during `setup`_—for your active shell session using the following command source venv/bin/activate (If you use ``virtualenvwrapper``, you can also use ``workon httpie`` to -active the environment — we have created a symlink for you. It’s a bit of +activate the environment — we have created a symlink for you. It’s a bit of a hack but it works™.) You should now see ``(httpie)`` next to your shell prompt, and diff --git a/Makefile b/Makefile index d40fa75cc0..5c8697645c 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,7 @@ test-tox: uninstall-httpie install @echo -test-sdist: clean uninstall-httpie +test-sdist: clean venv @echo $(H1)Testing sdist build an installation$(H1END) $(VENV_PYTHON) setup.py sdist $(VENV_PIP) install --force-reinstall --upgrade dist/*.gz @@ -108,8 +108,9 @@ test-sdist: clean uninstall-httpie @echo -test-bdist-wheel: clean uninstall-httpie +test-bdist-wheel: clean venv @echo $(H1)Testing wheel build an installation$(H1END) + $(VENV_PIP) install wheel $(VENV_PYTHON) setup.py bdist_wheel $(VENV_PIP) install --force-reinstall --upgrade dist/*.whl $(VENV_BIN)/http --version From e4a3ce8b9d5d994e233771c6d56e36a46ba31cb2 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 4 Dec 2019 23:31:47 +0100 Subject: [PATCH 0525/1182] Cleanup --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5c8697645c..f009827a1f 100644 --- a/Makefile +++ b/Makefile @@ -75,13 +75,13 @@ venv: test: - @echo $(H1)Running tests on the current Python interpreter $(HEADER_EXTRA) $(H1END) + @echo $(H1)Running tests$(HEADER_EXTRA)$(H1END) $(VENV_BIN)/py.test $(COV) ./httpie $(COV) ./tests --doctest-modules --verbose ./httpie ./tests @echo test-cover: COV=--cov -test-cover: HEADER_EXTRA='(with coverage)' +test-cover: HEADER_EXTRA=' (with coverage)' test-cover: test From 4b524e6a8c644283857787929947588e40a3b3ff Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 12 Jan 2020 10:50:57 +0100 Subject: [PATCH 0526/1182] v2.0.0 --- CHANGELOG.rst | 5 +++-- Makefile | 2 +- httpie/__init__.py | 2 +- httpie/cli/requestitems.py | 15 ++------------- setup.py | 4 ++-- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c16e570865..7bd11ec3f1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,7 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. -`2.0.0-dev`_ (unreleased) +`2.0.0`_ (2020-01-12) ------------------------- * Removed Python 2.7 support (`EOL Jan 2020 `_). * Removed the default 30-second connection ``--timeout`` limit. @@ -408,4 +408,5 @@ This project adheres to `Semantic Versioning `_. .. _1.0.1: https://github.com/jakubroztocil/httpie/compare/1.0.0...1.0.1 .. _1.0.2: https://github.com/jakubroztocil/httpie/compare/1.0.1...1.0.2 .. _1.0.3: https://github.com/jakubroztocil/httpie/compare/1.0.2...1.0.3 -.. _2.0.0-dev: https://github.com/jakubroztocil/httpie/compare/1.0.3...master +.. _2.0.0-dev: https://github.com/jakubroztocil/httpie/compare/1.0.3...2.0.0 +.. _2.1.0-dev: https://github.com/jakubroztocil/httpie/compare/2.0.0...master diff --git a/Makefile b/Makefile index f009827a1f..ec5c5f1cba 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ install: venv clean: @echo $(H1)Cleaning up$(H1END) rm -rf $(VENV_ROOT) - # Symlink for virtualenvwrapper, if we’ve created one. + # Remove symlink for virtualenvwrapper, if we’ve created one. [ -n "$(WORKON_HOME)" -a -L "$(WORKON_HOME)/httpie" -a -f "$(WORKON_HOME)/httpie" ] && rm $(WORKON_HOME)/httpie || true rm -rf .tox *.egg dist build .coverage .cache .pytest_cache httpie.egg-info find . -name '__pycache__' -delete -o -name '*.pyc' -delete diff --git a/httpie/__init__.py b/httpie/__init__.py index 7686500bef..c5f7ac4766 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '2.0.0-dev' +__version__ = '2.0.0' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index 37392bb081..ec8e6c1ef1 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -18,21 +18,19 @@ class RequestItems: - def __init__(self, as_form=False, chunked=False): + def __init__(self, as_form=False): self.headers = RequestHeadersDict() self.data = RequestDataDict() if as_form else RequestJSONDataDict() self.files = RequestFilesDict() self.params = RequestQueryParamsDict() - self.chunked = chunked @classmethod def from_args( cls, request_item_args: List[KeyValueArg], as_form=False, - chunked=False ) -> 'RequestItems': - instance = cls(as_form=as_form, chunked=chunked) + instance = cls(as_form=as_form) rules: Dict[str, Tuple[Callable, dict]] = { SEPARATOR_HEADER: ( process_header_arg, @@ -110,15 +108,6 @@ def process_file_upload_arg(arg: KeyValueArg) -> Tuple[str, IO, str]: ) -def parse_file_item_chunked(arg: KeyValueArg): - fn = arg.value - try: - f = open(os.path.expanduser(fn), 'rb') - except IOError as e: - raise ParseError('"%s": %s' % (arg.orig, e)) - return os.path.basename(fn), f, get_content_type(fn) - - def process_data_item_arg(arg: KeyValueArg) -> str: return arg.value diff --git a/setup.py b/setup.py index 2d18d38519..4392270ccc 100644 --- a/setup.py +++ b/setup.py @@ -35,8 +35,8 @@ def run_tests(self): install_requires = [ - 'requests>=2.21.0', - 'Pygments>=2.3.1', + 'requests>=2.22.0', + 'Pygments>=2.5.2', ] From ce5ca6c480d01edae4c94a10df01b149ea882ed2 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 12 Jan 2020 10:55:45 +0100 Subject: [PATCH 0527/1182] Fix version --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7bd11ec3f1..49254d2e1d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -408,5 +408,5 @@ This project adheres to `Semantic Versioning `_. .. _1.0.1: https://github.com/jakubroztocil/httpie/compare/1.0.0...1.0.1 .. _1.0.2: https://github.com/jakubroztocil/httpie/compare/1.0.1...1.0.2 .. _1.0.3: https://github.com/jakubroztocil/httpie/compare/1.0.2...1.0.3 -.. _2.0.0-dev: https://github.com/jakubroztocil/httpie/compare/1.0.3...2.0.0 +.. _2.0.0: https://github.com/jakubroztocil/httpie/compare/1.0.3...2.0.0 .. _2.1.0-dev: https://github.com/jakubroztocil/httpie/compare/2.0.0...master From 364edc4bd877cc7d66bef8838180a22b649f510b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 12 Jan 2020 10:57:14 +0100 Subject: [PATCH 0528/1182] Ignore codecov upload failures --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ec5c5f1cba..81b668735b 100644 --- a/Makefile +++ b/Makefile @@ -127,7 +127,8 @@ pycodestyle: codecov-upload: @echo $(H1)Running codecov$(H1END) @[ -f $(VENV_BIN)/codecov ] || $(VENV_PIP) install codecov - $(VENV_BIN)/codecov --required + # $(VENV_BIN)/codecov --required + $(VENV_BIN)/codecov @echo From 5d628756ab7238669df359c7c10527fa3ed02462 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 12 Jan 2020 11:00:25 +0100 Subject: [PATCH 0529/1182] Update Python version info --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f76e99d6b6..a62a4166a4 100644 --- a/README.rst +++ b/README.rst @@ -126,7 +126,7 @@ and always provides the latest version) is to use `pip`_: Python version -------------- -Starting with version 2.0.0 (currently under development) Python 3.6+ is required. +Python version 3.6 or greater is required. Unstable version From a7e52287129a8f61826b9c1e6b4c61ab11861b1f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 12 Jan 2020 11:06:43 +0100 Subject: [PATCH 0530/1182] Cleanup --- CHANGELOG.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 49254d2e1d..f9f2a47fb1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,15 +9,15 @@ This project adheres to `Semantic Versioning `_. `2.0.0`_ (2020-01-12) ------------------------- * Removed Python 2.7 support (`EOL Jan 2020 `_). -* Removed the default 30-second connection ``--timeout`` limit. -* Removed Python’s default limit of 100 response headers. -* Removed automatic config file creation to avoid concurrency issues. +* Added ``--offline`` to allow building an HTTP request and printing it but not + actually sending it over the network. * Replaced the old collect-all-then-process handling of HTTP communication with one-by-one processing of each HTTP request or response as they become available. This means that you can see headers immediately, see what is being send even when the request fails, etc. -* Added ``--offline`` to allow building an HTTP request and printing it but not - actually sending it over the network. +* Removed automatic config file creation to avoid concurrency issues. +* Removed the default 30-second connection ``--timeout`` limit. +* Removed Python’s default limit of 100 response headers. * Added ``--max-headers`` to allow setting the max header limit. * Added ``--compress`` to allow request body compression. * Added ``--ignore-netrc`` to allow bypassing credentials from ``.netrc``. From c3be72218837aa99cb5f8141c617835e91ba5e4c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 12 Jan 2020 11:44:58 +0100 Subject: [PATCH 0531/1182] Update brew formula --- extras/httpie.rb | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/extras/httpie.rb b/extras/httpie.rb index 04f6123db4..606fa4e5d0 100644 --- a/extras/httpie.rb +++ b/extras/httpie.rb @@ -9,22 +9,23 @@ class Httpie < Formula desc "User-friendly cURL replacement (command-line HTTP client)" homepage "https://httpie.org/" - url "https://files.pythonhosted.org/packages/d5/a4/ab61c1dbfdef33c7b7f5f7df0d79eb5cd55a106601a4acc17f983f320b4a/httpie-1.0.3.tar.gz" - sha256 "6d1b6e21da7d3ec030ae95536d4032c1129bdaf9de4adc72c596b87e5f646e80" + url "https://files.pythonhosted.org/packages/35/6c/93da2ebd4eb768c3733437ce01b5fae297522434fdeabeeabdc4f42aabd3/httpie-2.0.0.tar.gz" + sha256 "8c04f9756f1a7eac71a6dfa0834d0f6813dc8a982d8564f3a7418dcd19107c09" + revision 1 head "https://github.com/jakubroztocil/httpie.git" bottle do cellar :any_skip_relocation - sha256 "158258be68ac93de13860be2bef02da6fd8b68aa24b2e6609bcff1ec3f93e7a0" => :mojave - sha256 "54352116b6fa2c3bd65f26136fdcb57986dbff8a52de5febf7aea59c126d29e1" => :high_sierra - sha256 "9cce71768fe388808e11b26d651b44a6b54219f5406845b4273b5099f5c1f76f" => :sierra + sha256 "19694b5ec311939a8b73cc329ca49386155ed3a17e4eca691779c725d36286b5" => :catalina + sha256 "8c7d93d55ea3351e25fadfdd3748ca0a3ff7dd62ab9dbf31b7243fba76890c4d" => :mojave + sha256 "e0d5269bb5d03a1797c8612005fa46d6a35f2b84eb76e9607ef1169464b566ea" => :high_sierra end - depends_on "python" + depends_on "python@3.8" resource "Pygments" do - url "https://files.pythonhosted.org/packages/7e/ae/26808275fc76bf2832deb10d3a3ed3107bc4de01b85dcccbe525f2cd6d1e/Pygments-2.4.2.tar.gz" - sha256 "881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297" + url "https://files.pythonhosted.org/packages/cb/9f/27d4844ac5bf158a33900dbad7985951e2910397998e85712da03ce125f0/Pygments-2.5.2.tar.gz" + sha256 "98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe" end resource "requests" do @@ -33,13 +34,13 @@ class Httpie < Formula end resource "certifi" do - url "https://files.pythonhosted.org/packages/c5/67/5d0548226bcc34468e23a0333978f0e23d28d0b3f0c71a151aef9c3f7680/certifi-2019.6.16.tar.gz" - sha256 "945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" + url "https://files.pythonhosted.org/packages/41/bf/9d214a5af07debc6acf7f3f257265618f1db242a3f8e49a9b516f24523a6/certifi-2019.11.28.tar.gz" + sha256 "25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" end resource "urllib3" do - url "https://files.pythonhosted.org/packages/4c/13/2386233f7ee40aa8444b47f7463338f3cbdf00c316627558784e3f542f07/urllib3-1.25.3.tar.gz" - sha256 "dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" + url "https://files.pythonhosted.org/packages/ad/fc/54d62fa4fc6e675678f9519e677dfc29b8964278d75333cf142892caf015/urllib3-1.25.7.tar.gz" + sha256 "f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745" end resource "idna" do @@ -53,8 +54,8 @@ class Httpie < Formula end resource "PySocks" do - url "https://files.pythonhosted.org/packages/15/ab/35824cfdee1aac662e3298275fa1e6cbedb52126d1785f8977959b769ccf/PySocks-1.7.0.tar.gz" - sha256 "d9031ea45fdfacbe59a99273e9f0448ddb33c1580fe3831c1b09557c5718977c" + url "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz" + sha256 "3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0" end def install From deee2dffd05927f28d8ed586a9be5476f7d72259 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 13 Jan 2020 14:50:58 +0100 Subject: [PATCH 0532/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f9f2a47fb1..2776c3f941 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,7 +14,7 @@ This project adheres to `Semantic Versioning `_. * Replaced the old collect-all-then-process handling of HTTP communication with one-by-one processing of each HTTP request or response as they become available. This means that you can see headers immediately, - see what is being send even when the request fails, etc. + see what is being sent even if the request fails, etc. * Removed automatic config file creation to avoid concurrency issues. * Removed the default 30-second connection ``--timeout`` limit. * Removed Python’s default limit of 100 response headers. From 6e9cd139a610a7163de1ba870ad9ef29601fb687 Mon Sep 17 00:00:00 2001 From: Brad Solomon Date: Thu, 23 Jan 2020 09:05:07 -0500 Subject: [PATCH 0533/1182] Clean up Python-version related PyPI classifiers (#841) - Removes 'Programming Language :: Python :: 3.5' per the README, which specifies 'Python version 3.6 or greater is required.' - Adds 'Programming Language :: Python :: 3 :: Only' in place --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4392270ccc..2189469bbc 100644 --- a/setup.py +++ b/setup.py @@ -92,7 +92,7 @@ def long_description(): classifiers=[ 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', - 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Environment :: Console', From e6bad645edc4605ca10cc708b296d145390b55db Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 23 Jan 2020 15:54:43 +0100 Subject: [PATCH 0534/1182] Fixed `--form` file upload mixed with redirected `stdin` error handling. Close #840 --- CHANGELOG.rst | 5 +++++ httpie/__init__.py | 2 +- httpie/cli/argparser.py | 3 ++- tests/test_httpie.py | 21 +++++++++++++++++++++ tests/test_uploads.py | 2 ++ 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2776c3f941..293a32df55 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,11 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. +`2.1.0-dev`_ (unreleased) +------------------------- +* Fixed ``--form`` file upload mixed with redirected ``stdin`` error handling. + + `2.0.0`_ (2020-01-12) ------------------------- * Removed Python 2.7 support (`EOL Jan 2020 `_). diff --git a/httpie/__init__.py b/httpie/__init__.py index c5f7ac4766..eee945f83b 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '2.0.0' +__version__ = '2.1.0-dev' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 4924552e80..cf096d8d20 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -246,7 +246,8 @@ def _body_from_file(self, fd): if self.args.data: self.error('Request body (from stdin or a file) and request ' 'data (key=value) cannot be mixed. Pass ' - '--ignore-stdin to let key/value take priority.') + '--ignore-stdin to let key/value take priority. ' + 'See https://httpie.org/doc#scripting for details.') self.args.data = getattr(fd, 'buffer', fd).read() def _guess_method(self): diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 252b0a17aa..70bc2f9d54 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -98,6 +98,27 @@ def test_POST_file(httpbin_both): assert FILE_CONTENT in r +def test_form_POST_file_redirected_stdin(httpbin): + """ + + + """ + with open(FILE_PATH) as f: + r = http( + '--form', + 'POST', + httpbin + '/post', + 'file@' + FILE_PATH, + tolerate_error_exit_status=True, + env=MockEnvironment( + stdin=f, + stdin_isatty=False, + ), + ) + assert r.exit_status == ExitStatus.ERROR + assert 'cannot be mixed' in r.stderr + + def test_headers(httpbin_both): r = http('GET', httpbin_both + '/headers', 'Foo:bar') assert HTTP_OK in r diff --git a/tests/test_uploads.py b/tests/test_uploads.py index 81298fa58e..b0c7fc5d5a 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -3,6 +3,7 @@ import pytest from httpie.cli.exceptions import ParseError +from httpie.status import ExitStatus from utils import MockEnvironment, http, HTTP_OK from fixtures import FILE_PATH_ARG, FILE_PATH, FILE_CONTENT @@ -77,4 +78,5 @@ def test_request_body_from_file_by_path_no_data_items_allowed( env=env, tolerate_error_exit_status=True, ) + assert r.exit_status == ExitStatus.ERROR assert 'cannot be mixed' in r.stderr From 381dd4f619bfde1e2c3306cc6e7bef0a70f1f862 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 23 Jan 2020 15:56:29 +0100 Subject: [PATCH 0535/1182] Actually fixed `--form` file upload w/ redirected `stdin` error handling #840 --- httpie/cli/argparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index cf096d8d20..4a817b816e 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -243,7 +243,7 @@ def _body_from_file(self, fd): Bytes are always read. """ - if self.args.data: + if self.args.data or self.args.files: self.error('Request body (from stdin or a file) and request ' 'data (key=value) cannot be mixed. Pass ' '--ignore-stdin to let key/value take priority. ' From 8d246415fdd402463e88f20449dc1ec3c6cdd444 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 22 Mar 2020 12:29:01 +0100 Subject: [PATCH 0536/1182] 2020 --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 91f8b9510a..469f901f9d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright © 2012-2019 Jakub Roztocil +Copyright © 2012-2020 Jakub Roztocil Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From 7340b2b64d49fa24eee1198b9cd4392ee915624d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 20 Mar 2020 11:57:58 +0100 Subject: [PATCH 0537/1182] Update --download doc --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index a62a4166a4..eb3215605b 100644 --- a/README.rst +++ b/README.rst @@ -1386,6 +1386,8 @@ Other notes * The ``--download`` option only changes how the response body is treated. * You can still set custom headers, use sessions, ``--verbose, -v``, etc. * ``--download`` always implies ``--follow`` (redirects are followed). +* ``--download`` also implies ``--check-status`` + (error HTTP status will result in a non-zero exist static code). * HTTPie exits with status code ``1`` (error) if the body hasn't been fully downloaded. * ``Accept-Encoding`` cannot be set with ``--download``. From c73858b9c32ed5565e7d1753df6ddac8d3d4824b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 27 Mar 2020 10:03:09 +0100 Subject: [PATCH 0538/1182] Update examples --- README.rst | 100 ++++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/README.rst b/README.rst index eb3215605b..57cd01d9da 100644 --- a/README.rst +++ b/README.rst @@ -195,21 +195,21 @@ Custom `HTTP method`_, `HTTP headers`_ and `JSON`_ data: .. code-block:: bash - $ http PUT example.org X-API-Token:123 name=John + $ http PUT httpbin.org/put X-API-Token:123 name=John Submitting `forms`_: .. code-block:: bash - $ http -f POST example.org hello=World + $ http -f POST httpbin.org/post hello=World See the request that is being sent using one of the `output options`_: .. code-block:: bash - $ http -v example.org + $ http -v httpbin.org/get Use `Github API`_ to post a comment on an @@ -225,21 +225,21 @@ Upload a file using `redirected input`_: .. code-block:: bash - $ http example.org < file.json + $ http httpbin.org/post < file.json Download a file and save it via `redirected output`_: .. code-block:: bash - $ http example.org/file > file + $ http httpbin.org/image/png > image.png Download a file ``wget`` style: .. code-block:: bash - $ http --download example.org/file + $ http --download httpbin.org/image/png Use named `sessions`_ to make certain aspects or the communication persistent between requests to the same host: @@ -267,14 +267,14 @@ The name of the HTTP method comes right before the URL argument: .. code-block:: bash - $ http DELETE example.org/todos/7 + $ http DELETE httpbin.org/delete Which looks similar to the actual ``Request-Line`` that is sent: .. code-block:: http - DELETE /todos/7 HTTP/1.1 + DELETE /delete HTTP/1.1 When the ``METHOD`` argument is omitted from the command, HTTPie defaults to @@ -464,7 +464,7 @@ Simple example: .. code-block:: bash - $ http PUT example.org name=John email=john@example.org + $ http PUT httpbin.org/put name=John email=john@example.org .. code-block:: http @@ -472,7 +472,7 @@ Simple example: Accept: application/json, */* Accept-Encoding: gzip, deflate Content-Type: application/json - Host: example.org + Host: httpbin.org { "name": "John", @@ -515,7 +515,7 @@ fields using ``=@`` and ``:=@``: .. code-block:: bash - $ http PUT api.example.com/person/1 \ + $ http PUT httpbin.org/put \ name=John \ age:=29 married:=false hobbies:='["http", "pies"]' \ # Raw JSON description=@about-john.txt \ # Embed text file @@ -527,7 +527,7 @@ fields using ``=@`` and ``:=@``: PUT /person/1 HTTP/1.1 Accept: application/json, */* Content-Type: application/json - Host: api.example.com + Host: httpbin.org { "age": 29, @@ -549,7 +549,7 @@ complex data. In that case it's always better to use `redirected input`_: .. code-block:: bash - $ http POST api.example.com/person/1 < person.json + $ http POST httpbin.org/post < data.json Forms @@ -568,12 +568,12 @@ Regular forms .. code-block:: bash - $ http --form POST api.example.org/person/1 name='John Smith' + $ http --form POST httpbin.org/post name='John Smith' .. code-block:: http - POST /person/1 HTTP/1.1 + POST /post HTTP/1.1 Content-Type: application/x-www-form-urlencoded; charset=utf-8 name=John+Smith @@ -587,7 +587,7 @@ If one or more file fields is present, the serialization and content type is .. code-block:: bash - $ http -f POST example.com/jobs name='John Smith' cv@~/Documents/cv.pdf + $ http -f POST httpbin.org/post name='John Smith' cv@~/Documents/cv.pdf The request above is the same as if the following HTML form were @@ -611,17 +611,17 @@ To set custom headers you can use the ``Header:Value`` notation: .. code-block:: bash - $ http example.org User-Agent:Bacon/1.0 'Cookie:valued-visitor=yes;foo=bar' \ + $ http httpbin.org/headers User-Agent:Bacon/1.0 'Cookie:valued-visitor=yes;foo=bar' \ X-Foo:Bar Referer:https://httpie.org/ .. code-block:: http - GET / HTTP/1.1 + GET /headers HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Cookie: valued-visitor=yes;foo=bar - Host: example.org + Host: httpbin.org Referer: https://httpie.org/ User-Agent: Bacon/1.0 X-Foo: Bar @@ -691,7 +691,7 @@ Send a single cookie: .. code-block:: bash - $ http example.org Cookie:sessionid=foo + $ http httpbin.org/cookies Cookie:sessionid=foo .. code-block:: http @@ -700,7 +700,7 @@ Send a single cookie: Accept-Encoding: gzip, deflate Connection: keep-alive Cookie: sessionid=foo - Host: example.org + Host: httpbin.org User-Agent: HTTPie/0.9.9 @@ -709,7 +709,7 @@ Send multiple cookies .. code-block:: bash - $ http example.org 'Cookie:sessionid=foo;another-cookie=bar' + $ http httpbin.org/cookies 'Cookie:sessionid=foo;another-cookie=bar' .. code-block:: http @@ -718,7 +718,7 @@ Send multiple cookies Accept-Encoding: gzip, deflate Connection: keep-alive Cookie: sessionid=foo;another-cookie=bar - Host: example.org + Host: httpbin.org User-Agent: HTTPie/0.9.9 @@ -755,7 +755,7 @@ Basic auth .. code-block:: bash - $ http -a username:password example.org + $ http -a username:password httpbin.org/basic-auth/username/password Digest auth @@ -764,7 +764,7 @@ Digest auth .. code-block:: bash - $ http -A digest -a username:password example.org + $ http -A digest -a username:password httpbin.org/digest-auth/httpie/username/password Password prompt @@ -940,7 +940,7 @@ To skip the host's SSL certificate verification, you can pass ``--verify=no`` .. code-block:: bash - $ http --verify=no https://example.org + $ http --verify=no https://httpbin.org/get Custom CA bundle @@ -1095,7 +1095,7 @@ status code after an update: .. code-block:: bash - $ http --headers PATCH example.org/Really-Huge-Resource name='New Name' + $ http --headers PATCH httpbin.org/patch name='New Name' Since we are only printing the HTTP headers here, the connection to the server @@ -1117,28 +1117,28 @@ Redirect from a file: .. code-block:: bash - $ http PUT example.com/person/1 X-API-Token:123 < person.json + $ http PUT httpbin.org/put X-API-Token:123 < person.json Or the output of another program: .. code-block:: bash - $ grep '401 Unauthorized' /var/log/httpd/error_log | http POST example.org/intruders + $ grep '401 Unauthorized' /var/log/httpd/error_log | http POST httpbin.org/post You can use ``echo`` for simple data: .. code-block:: bash - $ echo '{"name": "John"}' | http PATCH example.com/person/1 X-API-Token:123 + $ echo '{"name": "John"}' | http PATCH httpbin.org/patch X-API-Token:123 You can also use a Bash *here string*: .. code-block:: bash - $ http example.com/ <<<'{"name": "John"}' + $ http httpbin.org/post <<<'{"name": "John"}' You can even pipe web services together using HTTPie: @@ -1152,14 +1152,14 @@ You can use ``cat`` to enter multiline data on the terminal: .. code-block:: bash - $ cat | http POST example.com + $ cat | http POST httpbin.org/post ^D .. code-block:: bash - $ cat | http POST example.com/todos Content-Type:text/plain + $ cat | http POST httpbin.org/post Content-Type:text/plain - buy milk - call parents ^D @@ -1169,7 +1169,7 @@ On OS X, you can send the contents of the clipboard with ``pbpaste``: .. code-block:: bash - $ pbpaste | http PUT example.com + $ pbpaste | http PUT httpbin.org/put Passing data through ``stdin`` cannot be combined with data fields specified @@ -1243,7 +1243,7 @@ that the response body is binary, .. code-block:: bash - $ http example.org/Movie.mov + $ http httpbin.org/bytes/2000 You will nearly instantly see something like this: @@ -1251,10 +1251,7 @@ You will nearly instantly see something like this: .. code-block:: http HTTP/1.1 200 OK - Accept-Ranges: bytes - Content-Encoding: gzip - Content-Type: video/quicktime - Transfer-Encoding: chunked + Content-Type: application/octet-stream +-----------------------------------------+ | NOTE: binary data not shown in terminal | @@ -1279,7 +1276,7 @@ Download a file: .. code-block:: bash - $ http example.org/Movie.mov > Movie.mov + $ http httpbin.org/image/png > image.png Download an image of Octocat, resize it using ImageMagick, upload it elsewhere: @@ -1294,7 +1291,7 @@ Force colorizing and formatting, and show both the request and the response in .. code-block:: bash - $ http --pretty=all --verbose example.org | less -R + $ http --pretty=all --verbose httpbin.org/get | less -R The ``-R`` flag tells ``less`` to interpret color escape sequences included @@ -1453,10 +1450,10 @@ to the same host. .. code-block:: bash # Create a new session - $ http --session=/tmp/session.json example.org API-Token:123 + $ http --session=/tmp/session.json httpbin.org/headers API-Token:123 # Re-use an existing session — API-Token will be set: - $ http --session=/tmp/session.json example.org + $ http --session=/tmp/session.json httpbin.org/headers All session data, including credentials, cookie data, @@ -1471,11 +1468,11 @@ Named sessions You can create one or more named session per host. For example, this is how -you can create a new session named ``user1`` for ``example.org``: +you can create a new session named ``user1`` for ``httpbin.org``: .. code-block:: bash - $ http --session=user1 -a user1:password example.org X-Foo:Bar + $ http --session=user1 -a user1:password httpbin.org/get X-Foo:Bar 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 @@ -1483,13 +1480,13 @@ will automatically be set: .. code-block:: bash - $ http --session=user1 example.org + $ http --session=user1 httpbin.org/get To create or reuse a different session, simple specify a different name: .. code-block:: bash - $ http --session=user2 -a user2:password example.org X-Bar:Foo + $ http --session=user2 -a user2:password httpbin.org/get X-Bar:Foo Named sessions’s data is stored in JSON files in the the ``sessions`` subdirectory of the `config`_ directory: @@ -1538,7 +1535,7 @@ environment variable: .. code-block:: bash $ export HTTPIE_CONFIG_DIR=/tmp/httpie - $ http example.org + $ http httpbin.org/get To view the exact location run ``http --debug``. @@ -1600,7 +1597,7 @@ respectively. #!/bin/bash - if http --check-status --ignore-stdin --timeout=2.5 HEAD example.org/health &> /dev/null; then + if http --check-status --ignore-stdin --timeout=2.5 HEAD httpbin.org/get &> /dev/null; then echo 'OK!' else case $? in @@ -1648,7 +1645,8 @@ HTTP request: .. code-block:: http - POST /collection HTTP/1.1 + POST /post HTTP/1.1 + Host: httpbin.org X-API-Key: 123 User-Agent: Bacon/1.0 Content-Type: application/x-www-form-urlencoded @@ -1660,7 +1658,7 @@ with the HTTPie command that sends it: .. code-block:: bash - $ http -f POST example.org/collection \ + $ http -f POST httpbin.org/post \ X-API-Key:123 \ User-Agent:Bacon/1.0 \ name=value \ From e9080e6b220b585cbb17d4e36a633d389ca234d0 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 13 Apr 2020 17:24:18 +0200 Subject: [PATCH 0539/1182] Build on PRs as well --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2acc5b7f17..f2237f2f32 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,5 @@ name: Build -on: [push] +on: [push, pull_request] jobs: extras: # Run coverage and extra tests only once From 3a6ac7d1265a38ed006d568088ddc829ca66d43a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 13 Apr 2020 17:37:27 +0200 Subject: [PATCH 0540/1182] Remove unused imports --- httpie/context.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/httpie/context.py b/httpie/context.py index 4cd8214be5..57a6c833bb 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -1,7 +1,6 @@ -import os import sys from pathlib import Path -from typing import Union, IO, Optional +from typing import IO, Optional try: From 14fe7dbb272aa3c2fddc8e015164abf92b0e63d1 Mon Sep 17 00:00:00 2001 From: Doug Beney Date: Mon, 13 Apr 2020 12:15:16 -0400 Subject: [PATCH 0541/1182] apt (#890) Co-authored-by: Doug Beney --- README.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 57cd01d9da..66cfb812cf 100644 --- a/README.rst +++ b/README.rst @@ -86,7 +86,7 @@ system package manager, for example: .. code-block:: bash # Debian, Ubuntu, etc. - $ apt-get install httpie + $ apt install httpie .. code-block:: bash @@ -1793,4 +1793,3 @@ have contributed. .. |downloads| image:: https://pepy.tech/badge/httpie :target: https://pepy.tech/project/httpie :alt: Download count - From 5754e33a75cd50e558a64694cd40c133001e0e45 Mon Sep 17 00:00:00 2001 From: Mio Date: Tue, 14 Apr 2020 00:15:48 +0800 Subject: [PATCH 0542/1182] Removed duplicate type annotation. (#888) --- httpie/downloads.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/httpie/downloads.py b/httpie/downloads.py index 2a1beeacbf..565a14d045 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -196,7 +196,6 @@ def __init__( """ :param resume: Should the download resume if partial download already exists. - :type resume: bool :param output_file: The file to store response body in. If not provided, it will be guessed from the response. @@ -322,7 +321,6 @@ def chunk_downloaded(self, chunk: bytes): :param chunk: A chunk of response body data that has just been downloaded and written to the output. - :type chunk: bytes """ self.status.chunk_downloaded(len(chunk)) From 684a4708d7eaecdf06a132da2633d06834bb08a3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 13 Apr 2020 20:18:01 +0200 Subject: [PATCH 0543/1182] Add `--path-as-is` Close #895 --- CHANGELOG.rst | 1 + httpie/cli/definition.py | 9 +++++++++ httpie/client.py | 33 +++++++++++++++++++++++++++++++++ tests/test_httpie.py | 19 +++++++++++++++++++ 4 files changed, 62 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 293a32df55..2faf451697 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,7 @@ This project adheres to `Semantic Versioning `_. `2.1.0-dev`_ (unreleased) ------------------------- +* Add ``--path-as-is`` to bypass dot segment (``/../`` or ``/./``) URL squashing. * Fixed ``--form`` file upload mixed with redirected ``stdin`` error handling. diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 61ed3d3b6a..43fb5348b5 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -552,6 +552,15 @@ def __iter__(self): """ ) +network.add_argument( + '--path-as-is', + default=False, + action='store_true', + help=""" + Bypass dot segment (/../ or /./) URL squashing. + + """ +) ####################################################################### # SSL diff --git a/httpie/client.py b/httpie/client.py index 431bee4f39..6c412e7388 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -6,6 +6,7 @@ from contextlib import contextmanager from pathlib import Path from typing import Iterable, Union +from urllib.parse import urlparse, urlunparse import requests from requests.adapters import HTTPAdapter @@ -77,6 +78,11 @@ def collect_messages( request = requests.Request(**request_kwargs) prepared_request = requests_session.prepare_request(request) + if args.path_as_is: + prepared_request.url = ensure_path_as_is( + orig_url=args.url, + prepped_url=prepared_request.url, + ) if args.compress and prepared_request.body: compress_body(prepared_request, always=args.compress > 1) response_count = 0 @@ -278,3 +284,30 @@ def make_request_kwargs( } return kwargs + + +def ensure_path_as_is(orig_url: str, prepped_url: str) -> str: + """ + Handle `--path-as-is` by replacing the path component of the prepared + URL with the path component from the original URL. Other parts stay + untouched because other (welcome) processing on the URL might have + taken place. + + + + + + + + >>> ensure_path_as_is('http://foo/../', 'http://foo/?foo=bar') + 'http://foo/../?foo=bar' + + """ + parsed_orig, parsed_prepped = urlparse(orig_url), urlparse(prepped_url) + final_dict = { + # noinspection PyProtectedMember + **parsed_prepped._asdict(), + 'path': parsed_orig.path, + } + final_url = urlunparse(tuple(final_dict.values())) + return final_url diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 70bc2f9d54..66caba5222 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -55,6 +55,25 @@ def test_GET(httpbin_both): assert HTTP_OK in r +def test_path_dot_normalization(): + r = http( + '--offline', + 'example.org/../../etc/password', + 'param==value' + ) + assert 'GET /etc/password?param=value' in r + + +def test_path_as_is(): + r = http( + '--offline', + '--path-as-is', + 'example.org/../../etc/password', + 'param==value' + ) + assert 'GET /../../etc/password?param=value' in r + + def test_DELETE(httpbin_both): r = http('DELETE', httpbin_both + '/delete') assert HTTP_OK in r From cdf691c21273e0e53d3885681dc1448db4a74179 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 13 Apr 2020 22:12:06 +0200 Subject: [PATCH 0544/1182] Change default JSON `Accept` to `application/json, */*;q=0.5` Close #488 --- CHANGELOG.rst | 9 +++++++-- README.rst | 10 +++++----- httpie/client.py | 2 +- tests/test_defaults.py | 9 +++++---- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2faf451697..97a92d0345 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,8 +8,13 @@ This project adheres to `Semantic Versioning `_. `2.1.0-dev`_ (unreleased) ------------------------- -* Add ``--path-as-is`` to bypass dot segment (``/../`` or ``/./``) URL squashing. -* Fixed ``--form`` file upload mixed with redirected ``stdin`` error handling. +* Added ``--path-as-is`` to bypass dot segment (``/../`` or ``/./``) + URL squashing (#895). +* Changed the default value ``Accept`` header value for JSON requests from + ``application/json, */*`` to ``application/json, */*;q=0.5`` + to clearly indicate preference (#488). +* Fixed ``--form`` file upload mixed with redirected ``stdin`` error handling + (#840). `2.0.0`_ (2020-01-12) diff --git a/README.rst b/README.rst index 66cfb812cf..b4864799d8 100644 --- a/README.rst +++ b/README.rst @@ -469,7 +469,7 @@ Simple example: .. code-block:: http PUT / HTTP/1.1 - Accept: application/json, */* + Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Content-Type: application/json Host: httpbin.org @@ -490,7 +490,7 @@ both of which can be overwritten: ================ ======================================= ``Content-Type`` ``application/json`` -``Accept`` ``application/json, */*`` +``Accept`` ``application/json, */*;q=0.5`` ================ ======================================= @@ -500,7 +500,7 @@ Explicit JSON You can use ``--json, -j`` to explicitly set ``Accept`` to ``application/json`` regardless of whether you are sending data (it's a shortcut for setting the header via the usual header notation: -``http url Accept:'application/json, */*'``). Additionally, +``http url Accept:'application/json, */*;q=0.5'``). Additionally, HTTPie will try to detect JSON responses even when the ``Content-Type`` is incorrectly ``text/plain`` or unknown. @@ -525,7 +525,7 @@ fields using ``=@`` and ``:=@``: .. code-block:: http PUT /person/1 HTTP/1.1 - Accept: application/json, */* + Accept: application/json, */*;q=0.5 Content-Type: application/json Host: httpbin.org @@ -1009,7 +1009,7 @@ documentation examples: $ http --verbose PUT httpbin.org/put hello=world PUT /put HTTP/1.1 - Accept: application/json, */* + Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Content-Type: application/json Host: httpbin.org diff --git a/httpie/client.py b/httpie/client.py index 6c412e7388..e3c6fa3982 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -30,7 +30,7 @@ FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8' JSON_CONTENT_TYPE = 'application/json' -JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*' +JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*;q=0.5' DEFAULT_UA = f'HTTPie/{__version__}' diff --git a/tests/test_defaults.py b/tests/test_defaults.py index 10221fe46c..5489c193ee 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -22,6 +22,7 @@ def test_default_headers_case_insensitive(httpbin): assert 'Content-Type' not in r +# noinspection PyPep8Naming class TestImplicitHTTPMethod: def test_implicit_GET(self, httpbin): r = http(httpbin.url + '/get') @@ -51,9 +52,9 @@ def test_implicit_POST_stdin(self, httpbin): class TestAutoContentTypeAndAcceptHeaders: """ - Test that Accept and Content-Type correctly defaults to JSON, - but can still be overridden. The same with Content-Type when --form - -f is used. + Test that `Accept` and `Content-Type` correctly default to JSON, + but can still be overridden. The same with Content-Type when `--form` + `-f` is used. """ @@ -84,7 +85,7 @@ def test_GET_with_data_auto_JSON_headers(self, httpbin): assert r.json['headers']['Accept'] == JSON_ACCEPT assert r.json['headers']['Content-Type'] == 'application/json' - def test_POST_explicit_JSON_auto_JSON_accept(self, httpbin): + def test_POST_explicit_JSON_JSON_ACCEPT(self, httpbin): r = http('--json', 'POST', httpbin.url + '/post') assert HTTP_OK in r assert r.json['headers']['Accept'] == JSON_ACCEPT From c9d770017e7156ec46978bdf8bf48cd4124affc8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 15 Apr 2020 17:43:08 +0200 Subject: [PATCH 0545/1182] Fix 'Too many redirects' error message formatting --- httpie/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/core.py b/httpie/core.py index 575257c16a..7c955e7e6f 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -90,7 +90,7 @@ def main( exit_status = ExitStatus.ERROR_TOO_MANY_REDIRECTS env.log_error( f'Too many redirects' - f' (--max-redirects=parsed_args.max_redirects).' + f' (--max-redirects={parsed_args.max_redirects}).' ) except Exception as e: # TODO: Further distinction between expected and unexpected errors. From 4f32b762237670dc3e90169f774d2e4a8fdb9211 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 15 Apr 2020 18:01:28 +0200 Subject: [PATCH 0546/1182] Readme WIP --- README.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index b4864799d8..592d10ffcd 100644 --- a/README.rst +++ b/README.rst @@ -225,7 +225,7 @@ Upload a file using `redirected input`_: .. code-block:: bash - $ http httpbin.org/post < file.json + $ http httpbin.org/post < files/data.json Download a file and save it via `redirected output`_: @@ -549,7 +549,7 @@ complex data. In that case it's always better to use `redirected input`_: .. code-block:: bash - $ http POST httpbin.org/post < data.json + $ http POST httpbin.org/post < files/data.json Forms @@ -587,7 +587,7 @@ If one or more file fields is present, the serialization and content type is .. code-block:: bash - $ http -f POST httpbin.org/post name='John Smith' cv@~/Documents/cv.pdf + $ http -f POST httpbin.org/post name='John Smith' cv@~/files/data.xml The request above is the same as if the following HTML form were @@ -1117,7 +1117,7 @@ Redirect from a file: .. code-block:: bash - $ http PUT httpbin.org/put X-API-Token:123 < person.json + $ http PUT httpbin.org/put X-API-Token:123 < files/data.json Or the output of another program: @@ -1198,7 +1198,7 @@ verbatim contents of that XML file with ``Content-Type: application/xml``: .. code-block:: bash - $ http PUT httpbin.org/put @/data/file.xml + $ http PUT httpbin.org/put @files/data.xml Terminal output From 8936d1b71e37da66312ad3068b80811006768896 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 16 Apr 2020 11:28:21 +0200 Subject: [PATCH 0547/1182] Add tests for `--offline` --- tests/test_httpie.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 66caba5222..959287c9f7 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -181,3 +181,23 @@ def test_json_input_preserve_order(httpbin_both): assert HTTP_OK in r assert r.json['data'] == \ '{"order": {"map": {"1": "first", "2": "second"}}}' + + +def test_offline(): + r = http( + '--offline', + 'https://this-should.never-resolve/foo', + 'param==value' + ) + assert 'GET /foo?param=value' in r + + +def test_offline_download(): + """Absence of response should be handled gracefully with --download""" + r = http( + '--offline', + '--download', + 'https://this-should.never-resolve/foo', + 'param==value' + ) + assert 'GET /foo?param=value' in r From 29b692d5970d68389c586bb8925a731b6401b12b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 16 Apr 2020 11:29:33 +0200 Subject: [PATCH 0548/1182] Add `--offline` mode docs --- README.rst | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/README.rst b/README.rst index 592d10ffcd..02e407cef4 100644 --- a/README.rst +++ b/README.rst @@ -679,6 +679,50 @@ HTTPie reads before giving up (the default ``0``, i.e., there’s no limit). +Offline mode +============ + +Use ``--offline`` to construct HTTP requests without sending them anywhere. +With ``--offline``, HTTPie builds a request based on the specified options and arguments, prints it to ``stdout``, +and then exists. It works completely offline; no network connection is ever made. +This has a number of use cases, including: + + +Generating API documentation examples that you can copy & paste without sending a request: + + +.. code-block:: bash + + $ http --offline POST server.chess/api/games API-Key:ZZZ w=magnus b=hikaru t=180 i=2 + + +.. code-block:: bash + + $ http --offline MOVE server.chess/api/games/123 API-Key:ZZZ p=b a=R1a3 t=77 + + +Generating raw requests that can be sent with any other client: + +.. code-block:: bash + + # 1. save a raw request to a file: + $ http --offline POST httpbin.org/post hello=world > request.http + + +.. code-block:: bash + + # 2. send it over the wire with, for example, the fantastic netcat tool: + $ nc httpbin.org 80 < request.http + + +You can also use the ``--offline`` mode for debugging and exploring HTTP and HTTPie, and for “dry runs”. + +``--offline`` has the side-effect of automatically activating ``--print=HB``, i.e., both the request headers and the body +are printed. You can customize the output with the usual `output options`_, with the exception that there +is not response to be printed. You can use ``--offline`` in combination with all the other options (e.g., ``--session``). + + + Cookies ======= From 770976a66e95eb67a308e1a2f10a95d709079cab Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 16 Apr 2020 11:29:58 +0200 Subject: [PATCH 0549/1182] Add `--path-as-is` docs --- README.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.rst b/README.rst index 02e407cef4..5fbbdef10d 100644 --- a/README.rst +++ b/README.rst @@ -380,6 +380,34 @@ Example for the `httpie-unixsocket # Now the scheme can be omitted $ http-unix %2Fvar%2Frun%2Fdocker.sock/info + +``--path-as-is`` +---------------- + +The standard behaviour of HTTP clients is to normalize the path portion of URLs by squashing dot segments +as a typically filesystem would: + + +.. code-block:: bash + + $ http -v example.org/./../../etc/password + +.. code-block:: http + + GET /etc/password HTTP/1.1 + + +The ``--path-as-is`` option allows you to disable this behavior: + +.. code-block:: bash + + $ http --path-as-is -v example.org/./../../etc/password + +.. code-block:: http + + GET /../../etc/password HTTP/1.1 + + Request items ============= From 43516506911652a9b48a2c6daf5848581a26f821 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 16 Apr 2020 11:41:12 +0200 Subject: [PATCH 0550/1182] Ignore `--download` with `--offline` --- httpie/cli/argparser.py | 8 ++++++-- tests/test_httpie.py | 6 ++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 4a817b816e..835df376e1 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -78,7 +78,7 @@ def parse_args( # Arguments processing and environment setup. self._apply_no_options(no_options) - self._validate_download_options() + self._process_download_options() self._setup_standard_streams() self._process_output_options() self._process_pretty_options() @@ -379,7 +379,11 @@ def _process_pretty_options(self): # noinspection PyTypeChecker self.args.prettify = PRETTY_MAP[self.args.prettify] - def _validate_download_options(self): + def _process_download_options(self): + if self.args.offline: + self.args.download = False + self.args.download_resume = False + return if not self.args.download: if self.args.download_resume: self.error('--continue only works with --download') diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 959287c9f7..48af07570e 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -187,9 +187,8 @@ def test_offline(): r = http( '--offline', 'https://this-should.never-resolve/foo', - 'param==value' ) - assert 'GET /foo?param=value' in r + assert 'GET /foo' in r def test_offline_download(): @@ -198,6 +197,5 @@ def test_offline_download(): '--offline', '--download', 'https://this-should.never-resolve/foo', - 'param==value' ) - assert 'GET /foo?param=value' in r + assert 'GET /foo' in r From 3af5f1f3051659f683bd4b6231559d4eb6456280 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 16 Apr 2020 11:47:34 +0200 Subject: [PATCH 0551/1182] Add an `--offline` example --- README.rst | 72 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 5fbbdef10d..0f600b08f8 100644 --- a/README.rst +++ b/README.rst @@ -212,6 +212,13 @@ See the request that is being sent using one of the `output options`_: $ http -v httpbin.org/get +Build and print a request without sending it using `offline mode`_: + +.. code-block:: bash + + $ http --offline httpbin.org/post hello=offline + + Use `Github API`_ to post a comment on an `issue `_ with `authentication`_: @@ -241,13 +248,17 @@ Download a file ``wget`` style: $ http --download httpbin.org/image/png -Use named `sessions`_ to make certain aspects or the communication persistent +Use named `sessions`_ to make certain aspects of the communication persistent between requests to the same host: + .. code-block:: bash $ http --session=logged-in -a username:password httpbin.org/get API-Key:123 + +.. code-block:: bash + $ http --session=logged-in httpbin.org/headers @@ -1495,7 +1506,7 @@ Prettified streamed response: $ http --stream -f -a YOUR-TWITTER-NAME https://stream.twitter.com/1/statuses/filter.json track='Justin Bieber' -Streamed output by small chunks alá ``tail -f``: +Streamed output by small chunks à la ``tail -f``: .. code-block:: bash @@ -1521,11 +1532,20 @@ to the same host. .. code-block:: bash - # Create a new session - $ http --session=/tmp/session.json httpbin.org/headers API-Token:123 + # Create a new session: + $ http --session=./session.json httpbin.org/headers API-Token:123 - # Re-use an existing session — API-Token will be set: - $ http --session=/tmp/session.json httpbin.org/headers + +.. code-block:: bash + + # Inspect / edit the generated session file: + $ cat session.json + + +.. code-block:: bash + + # Re-use the existing session — the API-Token header will be set: + $ http --session=./session.json httpbin.org/headers All session data, including credentials, cookie data, @@ -1546,8 +1566,8 @@ you can create a new session named ``user1`` for ``httpbin.org``: $ http --session=user1 -a user1:password httpbin.org/get X-Foo:Bar -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 +From now on, you can refer to the session by its name (``user1``). When you choose +to use the session again, any previously specified authentication or HTTP headers will automatically be set: .. code-block:: bash @@ -1565,6 +1585,14 @@ subdirectory of the `config`_ directory: ``~/.httpie/sessions//.json`` (``%APPDATA%\httpie\sessions\\.json`` on Windows). +If you have executed the above commands on a unix machine, +you should be able list the generated sessions files using: + + +.. code-block:: bash + + $ ls -l ~/.httpie/sessions/httpbin.org + Anonymous sessions ------------------ @@ -1574,19 +1602,43 @@ allows for sessions to be re-used across multiple hosts: .. code-block:: bash + # Create a session: $ http --session=/tmp/session.json example.org + + +.. code-block:: bash + + # Use the session to make a request to another host: $ http --session=/tmp/session.json admin.example.org + +.. code-block:: bash + + # You can also refer to a previously created named session: $ http --session=~/.httpie/sessions/another.example.org/test.json example.org - $ http --session-read-only=/tmp/session.json example.org + + +When creating anonymous sessions, please remember to always include at least +one ``/``, even if the session files is located in the current directory +(i.e., ``--session=./session.json`` instead of just ``--session=session.json``), +otherwise HTTPie assumes a named session instead. Readonly session ---------------- To use an existing session file without updating it from the request/response -exchange once it is created, specify the session name via +exchange after it has been created, specify the session name via ``--session-read-only=SESSION_NAME_OR_PATH`` instead. +.. code-block:: bash + + # If the session file doesn’t exist, then it is created: + $ http --session-read-only=./ro-session.json httpbin.org/headers Custom-Header:orig-value + +.. code-block:: bash + + # But it is not updated: + $ http --session-read-only=./ro-session.json httpbin.org/headers Custom-Header:new-value Config ====== From 83bd8059de23ea136549735b10307132114ab628 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 6 Apr 2020 14:10:47 +0200 Subject: [PATCH 0552/1182] accept wip --- tests/test_defaults.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_defaults.py b/tests/test_defaults.py index 5489c193ee..f7976f1982 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -2,7 +2,7 @@ Tests for the provided defaults regarding HTTP method, and --json vs. --form. """ -from httpie.client import JSON_ACCEPT +from httpie.client import EXPLICIT_JSON_ACCEPT, AUTO_JSON_ACCEPT from utils import MockEnvironment, http, HTTP_OK from fixtures import FILE_PATH @@ -75,20 +75,20 @@ def test_POST_no_data_no_auto_headers(self, httpbin): def test_POST_with_data_auto_JSON_headers(self, httpbin): r = http('POST', httpbin.url + '/post', 'a=b') assert HTTP_OK in r - assert r.json['headers']['Accept'] == JSON_ACCEPT + assert r.json['headers']['Accept'] == AUTO_JSON_ACCEPT assert r.json['headers']['Content-Type'] == 'application/json' def test_GET_with_data_auto_JSON_headers(self, httpbin): # JSON headers should automatically be set also for GET with data. r = http('POST', httpbin.url + '/post', 'a=b') assert HTTP_OK in r - assert r.json['headers']['Accept'] == JSON_ACCEPT + assert r.json['headers']['Accept'] == AUTO_JSON_ACCEPT assert r.json['headers']['Content-Type'] == 'application/json' def test_POST_explicit_JSON_JSON_ACCEPT(self, httpbin): r = http('--json', 'POST', httpbin.url + '/post') assert HTTP_OK in r - assert r.json['headers']['Accept'] == JSON_ACCEPT + assert r.json['headers']['Accept'] == EXPLICIT_JSON_ACCEPT # Make sure Content-Type gets set even with no data. # https://github.com/jakubroztocil/httpie/issues/137 assert 'application/json' in r.json['headers']['Content-Type'] From fc859883689d366a375015729257ab3bee4668f6 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 13 Apr 2020 22:06:02 +0200 Subject: [PATCH 0553/1182] Change default JSON `Accept` to `application/json, */*;q=0.5` See #488 --- tests/test_defaults.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_defaults.py b/tests/test_defaults.py index f7976f1982..5489c193ee 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -2,7 +2,7 @@ Tests for the provided defaults regarding HTTP method, and --json vs. --form. """ -from httpie.client import EXPLICIT_JSON_ACCEPT, AUTO_JSON_ACCEPT +from httpie.client import JSON_ACCEPT from utils import MockEnvironment, http, HTTP_OK from fixtures import FILE_PATH @@ -75,20 +75,20 @@ def test_POST_no_data_no_auto_headers(self, httpbin): def test_POST_with_data_auto_JSON_headers(self, httpbin): r = http('POST', httpbin.url + '/post', 'a=b') assert HTTP_OK in r - assert r.json['headers']['Accept'] == AUTO_JSON_ACCEPT + assert r.json['headers']['Accept'] == JSON_ACCEPT assert r.json['headers']['Content-Type'] == 'application/json' def test_GET_with_data_auto_JSON_headers(self, httpbin): # JSON headers should automatically be set also for GET with data. r = http('POST', httpbin.url + '/post', 'a=b') assert HTTP_OK in r - assert r.json['headers']['Accept'] == AUTO_JSON_ACCEPT + assert r.json['headers']['Accept'] == JSON_ACCEPT assert r.json['headers']['Content-Type'] == 'application/json' def test_POST_explicit_JSON_JSON_ACCEPT(self, httpbin): r = http('--json', 'POST', httpbin.url + '/post') assert HTTP_OK in r - assert r.json['headers']['Accept'] == EXPLICIT_JSON_ACCEPT + assert r.json['headers']['Accept'] == JSON_ACCEPT # Make sure Content-Type gets set even with no data. # https://github.com/jakubroztocil/httpie/issues/137 assert 'application/json' in r.json['headers']['Content-Type'] From 70a78249c14572c36c5903140e21308398693850 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 18 Apr 2020 12:54:40 +0200 Subject: [PATCH 0554/1182] 2.1.0 #488 #840 #895 --- CHANGELOG.rst | 12 +++-- README.rst | 119 ++++++++++++++++++++++++++++++--------------- httpie/__init__.py | 2 +- setup.cfg | 1 - setup.py | 35 +++++++------ 5 files changed, 109 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 97a92d0345..39c7ddf20c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,8 +6,9 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. -`2.1.0-dev`_ (unreleased) -------------------------- +`2.1.0`_ (2020-04-18) +--------------------- + * Added ``--path-as-is`` to bypass dot segment (``/../`` or ``/./``) URL squashing (#895). * Changed the default value ``Accept`` header value for JSON requests from @@ -420,4 +421,9 @@ This project adheres to `Semantic Versioning `_. .. _1.0.2: https://github.com/jakubroztocil/httpie/compare/1.0.1...1.0.2 .. _1.0.3: https://github.com/jakubroztocil/httpie/compare/1.0.2...1.0.3 .. _2.0.0: https://github.com/jakubroztocil/httpie/compare/1.0.3...2.0.0 -.. _2.1.0-dev: https://github.com/jakubroztocil/httpie/compare/2.0.0...master +.. _2.1.0: https://github.com/jakubroztocil/httpie/compare/2.0.0...2.1.0 + + +.. _#488:https://github.com/jakubroztocil/httpie/issues/488 +.. _#840:https://github.com/jakubroztocil/httpie/issues/840 +.. _#895:https://github.com/jakubroztocil/httpie/issues/895 diff --git a/README.rst b/README.rst index 0f600b08f8..15eeb1e389 100644 --- a/README.rst +++ b/README.rst @@ -27,11 +27,20 @@ generally interacting with HTTP servers. .. section-numbering:: +About this document +=================== + +This documentation is best viewed at `httpie.org/docs `_, +where you can select your corresponding HTTPie version as well as run examples directly from the +browser using a `termible.io `_ embedded terminal. +If you are reading this on GitHub, then this text covers the current *development* version. +You are invited to submit fixes and improvements to the the docs by editing +`README.rst `_. + Main features ============= - * Expressive and intuitive syntax * Formatted and colorized terminal output * Built-in JSON support @@ -157,13 +166,13 @@ Otherwise with ``pip``: Verify that now we have the -`current development version identifier `_ +`current development version identifier `_ with the ``-dev`` suffix, for example: .. code-block:: bash $ http --version - 1.0.0-dev + # 2.0.0-dev Usage @@ -175,7 +184,7 @@ Hello World: .. code-block:: bash - $ http httpie.org + $ http https://httpie.org/hello Synopsis: @@ -307,7 +316,7 @@ 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 ``&`` +With that, you don’t have to worry about escaping the ``&`` separators for your shell. Additionally, any special characters in the parameter name or value get automatically URL-escaped (as opposed to parameters specified in the full URL, which HTTPie doesn’t @@ -459,14 +468,14 @@ their type is distinguished only by the separator used: +-----------------------+-----------------------------------------------------+ -Note that data fields aren't the only way to specify request data: +Note that data fields aren’t the only way to specify request data: `Redirected input`_ is a mechanism for passing arbitrary request data. Escaping rules -------------- -You can use ``\`` to escape characters that shouldn't be used as separators +You can use ``\`` to escape characters that shouldn’t be used as separators (or parts thereof). For instance, ``foo\==bar`` will become a data key/value pair (``foo=`` and ``bar``) instead of a URL parameter. @@ -538,7 +547,7 @@ Explicit JSON You can use ``--json, -j`` to explicitly set ``Accept`` to ``application/json`` regardless of whether you are sending data -(it's a shortcut for setting the header via the usual header notation: +(it’s a shortcut for setting the header via the usual header notation: ``http url Accept:'application/json, */*;q=0.5'``). Additionally, HTTPie will try to detect JSON responses even when the ``Content-Type`` is incorrectly ``text/plain`` or unknown. @@ -548,17 +557,20 @@ HTTPie will try to detect JSON responses even when the Non-string JSON fields ---------------------- -Non-string fields use the ``:=`` separator, which allows you to embed raw JSON -into the resulting object. Text and raw JSON files can also be embedded into +Non-string JSON fields use the ``:=`` separator, which allows you to embed arbitrary JSON data +into the resulting JSON object. Additionally, text and raw JSON files can also be embedded into fields using ``=@`` and ``:=@``: .. code-block:: bash $ http PUT httpbin.org/put \ - name=John \ - age:=29 married:=false hobbies:='["http", "pies"]' \ # Raw JSON - description=@about-john.txt \ # Embed text file - bookmarks:=@bookmarks.json # Embed JSON file + name=John \ # String (default) + age:=29 \ # Raw JSON — Number + married:=false \ # Raw JSON — Boolean + hobbies:='["http", "pies"]' \ # Raw JSON — Array + favorite:='{"tool": "HTTPie"}' \ # Raw JSON — Object + bookmarks:=@files/data.json \ # Embed JSON file + description=@files/text.txt # Embed text file .. code-block:: http @@ -577,19 +589,33 @@ fields using ``=@`` and ``:=@``: "description": "John is a nice guy who likes pies.", "married": false, "name": "John", + "favorite": { + "tool": "HTTPie" + }, "bookmarks": { "HTTPie": "https://httpie.org", } } -Please note that with this syntax the command gets unwieldy when sending -complex data. In that case it's always better to use `redirected input`_: +Raw and complex JSON +-------------------- + +Please note that with the `request items`_ data field syntax, commands +can quickly become unwieldy when sending complex structures. +In such cases, it’s better to pass the full raw JSON data via +`redirected input`_, for example: + +.. code-block:: bash + + $ echo '{"hello": "world"}' | http POST httpbin.org/post .. code-block:: bash $ http POST httpbin.org/post < files/data.json +Furthermore, this syntax only allows you to send an object as the JSON document, but not an array, etc. +Here, again, the solution is to use `redirected input`_. Forms ===== @@ -805,7 +831,7 @@ Send multiple cookies User-Agent: HTTPie/0.9.9 -If you often deal with cookies in your requests, then chances are you'd appreciate +If you often deal with cookies in your requests, then chances are you’d appreciate the `sessions`_ feature. @@ -818,7 +844,7 @@ The currently supported authentication schemes are Basic and Digest =================== ====================================================== ``--auth, -a`` Pass a ``username:password`` pair as the argument. Or, if you only specify a username - (``-a username``), you'll be prompted for + (``-a username``), you’ll be prompted for the password before the request is sent. To send an empty password, pass ``username:``. The ``username:password@hostname`` URL syntax is @@ -855,7 +881,15 @@ Password prompt .. code-block:: bash - $ http -a username example.org + $ http -a username httpbin.org/basic-auth/username/password + + +Empty password +-------------- + +.. code-block:: bash + + $ http -a username: httpbin.org/headers ``.netrc`` @@ -893,7 +927,7 @@ Auth plugins Additional authentication mechanism can be installed as plugins. They can be found on the `Python Package Index `_. -Here's a few picks: +Here’s a few picks: * `httpie-api-auth `_: ApiAuth * `httpie-aws-auth `_: AWS / Amazon S3 @@ -954,7 +988,7 @@ To change the default limit of maximum ``30`` redirects, use the .. code-block:: bash - $ http --follow --all --max-redirects=5 httpbin.org/redirect/3 + $ http --follow --all --max-redirects=2 httpbin.org/redirect/3 Proxies @@ -996,7 +1030,7 @@ SOCKS ----- Homebrew-installed HTTPie comes with SOCKS proxy support out of the box. -To enable SOCKS proxy support for non-Homebrew installations, you'll +To enable SOCKS proxy support for non-Homebrew installations, you’ll might need to install ``requests[socks]`` manually using ``pip``: @@ -1018,7 +1052,7 @@ HTTPS Server SSL certificate verification ----------------------------------- -To skip the host's SSL certificate verification, you can pass ``--verify=no`` +To skip the host’s SSL certificate verification, you can pass ``--verify=no`` (default is ``yes``): .. code-block:: bash @@ -1154,7 +1188,7 @@ authentication is used (``--auth=digest``), etc. The intermediary requests/response are by default formatted according to -``--print, -p`` (and its shortcuts described above). If you'd like to change +``--print, -p`` (and its shortcuts described above). If you’d like to change that, use the ``--history-print, -P`` option. It takes the same arguments as ``--print, -p`` but applies to the intermediary requests only. @@ -1169,10 +1203,10 @@ Conditional body download ------------------------- As an optimization, the response body is downloaded from the server -only if it's part of the output. This is similar to performing a ``HEAD`` +only if it’s part of the output. This is similar to performing a ``HEAD`` request, except that it applies to any HTTP method you use. -Let's say that there is an API that returns the whole resource when it is +Let’s say that there is an API that returns the whole resource when it is updated, but you are only interested in the response headers to see the status code after an update: @@ -1183,8 +1217,8 @@ status code after an update: Since we are only printing the HTTP headers here, the connection to the server is closed as soon as all the response headers have been received. -Therefore, bandwidth and time isn't wasted downloading the body -which you don't care about. The response headers are downloaded always, +Therefore, bandwidth and time isn’t wasted downloading the body +which you don’t care about. The response headers are downloaded always, even if they are not part of the output @@ -1296,8 +1330,16 @@ Colors and formatting Syntax highlighting is applied to HTTP headers and bodies (where it makes sense). You can choose your preferred color scheme via the ``--style`` option -if you don't like the default one (see ``$ http --help`` for the possible -values). +if you don’t like the default one. There dozens of styles available, here are just a few special or notable ones: + +==================== ======================================================================== +``auto`` Follows your terminal ANSI color styles. This is the default style used by HTTPie. +``default`` Default styles of the underlying Pygments library. Not actually used by default by HTTPie. + You can enable it with ``--style=default`` +``monokai`` A popular color scheme. Enable with ``--style=monokai``. +``fruity`` A bold, colorful scheme. Enable with ``--style=fruity``. +… See ``$ http --help`` for all the possible ``--style`` values. +==================== ======================================================================== Also, the following formatting is applied: @@ -1347,11 +1389,11 @@ Redirected output HTTPie uses a different set of defaults for redirected output than for `terminal output`_. The differences being: -* Formatting and colors aren't applied (unless ``--pretty`` is specified). +* Formatting and colors aren’t applied (unless ``--pretty`` is specified). * Only the response body is printed (unless one of the `output options`_ is set). -* Also, binary data isn't suppressed. +* Also, binary data isn’t suppressed. -The reason is to make piping HTTPie's output to another programs and +The reason is to make piping HTTPie’s output to another programs and downloading files work with no extra flags. Most of the time, only the raw response body is of an interest when the output is redirected. @@ -1453,7 +1495,7 @@ Resuming downloads If ``--output, -o`` is specified, you can resume a partial download using the ``--continue, -c`` option. This only works with servers that support -``Range`` requests and ``206 Partial Content`` responses. If the server doesn't +``Range`` requests and ``206 Partial Content`` responses. If the server doesn’t support that, the whole file will simply be downloaded: .. code-block:: bash @@ -1468,7 +1510,7 @@ Other notes * ``--download`` always implies ``--follow`` (redirects are followed). * ``--download`` also implies ``--check-status`` (error HTTP status will result in a non-zero exist static code). -* HTTPie exits with status code ``1`` (error) if the body hasn't been fully +* HTTPie exits with status code ``1`` (error) if the body hasn’t been fully downloaded. * ``Accept-Encoding`` cannot be set with ``--download``. @@ -1541,7 +1583,6 @@ to the same host. # Inspect / edit the generated session file: $ cat session.json - .. code-block:: bash # Re-use the existing session — the API-Token header will be set: @@ -1747,7 +1788,7 @@ What happens is that when HTTPie is invoked for example from a cron job, ``stdin`` is not connected to a terminal. Therefore, rules for `redirected input`_ apply, i.e., HTTPie starts to read it expecting that the request body will be passed through. -And since there's no data nor ``EOF``, it will be stuck. So unless you're +And since there’s no data nor ``EOF``, it will be stuck. So unless you’re piping some data to HTTPie, this flag should be used in scripts. Also, it might be good to set a connection ``--timeout`` limit to prevent @@ -1762,7 +1803,7 @@ Interface design ---------------- The syntax of the command arguments closely corresponds to the actual HTTP -requests sent over the wire. It has the advantage that it's easy to remember +requests sent over the wire. It has the advantage that it’s easy to remember and read. It is often possible to translate an HTTP request to an HTTPie argument list just by inlining the request elements. For example, compare this HTTP request: @@ -1791,7 +1832,7 @@ with the HTTPie command that sends it: Notice that both the order of elements and the syntax is very similar, and that only a small portion of the command is used to control HTTPie and -doesn't directly correspond to any part of the request (here it's only ``-f`` +doesn’t directly correspond to any part of the request (here it’s only ``-f`` asking HTTPie to send a form request). The two modes, ``--pretty=all`` (default for terminal) and ``--pretty=none`` diff --git a/httpie/__init__.py b/httpie/__init__.py index eee945f83b..574bf64eba 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '2.1.0-dev' +__version__ = '2.1.0' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' diff --git a/setup.cfg b/setup.cfg index 3db9ed60e8..2b20304218 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,4 @@ [wheel] -universal = 1 [tool:pytest] diff --git a/setup.py b/setup.py index 2189469bbc..084ea47c8b 100644 --- a/setup.py +++ b/setup.py @@ -10,8 +10,11 @@ class PyTest(TestCommand): - # `$ python setup.py test' simply installs minimal requirements - # and runs the tests with no fancy stuff like parallel execution. + """ + Running `$ python setup.py test' simply installs minimal requirements + and runs the tests with no fancy stuff like parallel execution. + + """ def finalize_options(self): TestCommand.finalize_options(self) self.test_args = [ @@ -26,8 +29,6 @@ def run_tests(self): tests_require = [ - # Pytest needs to come last. - # https://bitbucket.org/pypa/setuptools/issue/196/ 'pytest-httpbin', 'pytest', 'mock', @@ -38,28 +39,24 @@ def run_tests(self): 'requests>=2.22.0', 'Pygments>=2.5.2', ] - +install_requires_win_only = [ + 'colorama>=0.2.4', +] # Conditional dependencies: # sdist if 'bdist_wheel' not in sys.argv: - try: - # noinspection PyUnresolvedReferences - import argparse - except ImportError: - install_requires.append('argparse>=1.2.1') if 'win32' in str(sys.platform).lower(): # Terminal colors for Windows - install_requires.append('colorama>=0.2.4') + install_requires.extend(install_requires_win_only) # bdist_wheel extras_require = { # https://wheel.readthedocs.io/en/latest/#defining-conditional-dependencies - 'python_version == "3.0" or python_version == "3.1"': ['argparse>=1.2.1'], - ':sys_platform == "win32"': ['colorama>=0.2.4'], + ':sys_platform == "win32"': install_requires_win_only, } @@ -74,7 +71,7 @@ def long_description(): description=httpie.__doc__.strip(), long_description=long_description(), url='https://httpie.org/', - download_url='https://github.com/jakubroztocil/httpie', + download_url=f'https://github.com/jakubroztocil/httpie/archive/{httpie.__version__}.tar.gz', author=httpie.__author__, author_email='jakub@roztocil.co', license=httpie.__licence__, @@ -85,6 +82,7 @@ def long_description(): 'https = httpie.__main__:main', ], }, + python_requires='>=3.6', extras_require=extras_require, install_requires=install_requires, tests_require=tests_require, @@ -93,8 +91,6 @@ def long_description(): 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', 'Environment :: Console', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', @@ -106,4 +102,11 @@ def long_description(): 'Topic :: Text Processing', 'Topic :: Utilities' ], + project_urls={ + 'Documentation': 'https://httpie.org/docs', + 'Source': 'https://github.com/jakubroztocil/httpie', + 'Online Demo': 'https://httpie.org/run', + 'Donate': 'https://httpie.org/donate', + 'Twitter': 'https://twitter.com/clihttp', + }, ) From 774ff148cdebeb8ff268eae777b65035f3175cad Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 18 Apr 2020 12:57:56 +0200 Subject: [PATCH 0555/1182] 2.2.0-dev --- CHANGELOG.rst | 4 ++++ httpie/__init__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 39c7ddf20c..8dda80c99a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,9 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. +`2.2.0-dev`_ (unreleased) +------------------------- + `2.1.0`_ (2020-04-18) --------------------- @@ -422,6 +425,7 @@ This project adheres to `Semantic Versioning `_. .. _1.0.3: https://github.com/jakubroztocil/httpie/compare/1.0.2...1.0.3 .. _2.0.0: https://github.com/jakubroztocil/httpie/compare/1.0.3...2.0.0 .. _2.1.0: https://github.com/jakubroztocil/httpie/compare/2.0.0...2.1.0 +.. _2.2.0-dev: https://github.com/jakubroztocil/httpie/compare/2.1.0...master .. _#488:https://github.com/jakubroztocil/httpie/issues/488 diff --git a/httpie/__init__.py b/httpie/__init__.py index 574bf64eba..4b6849296f 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '2.1.0' +__version__ = '2.2.0-dev' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 45b9bae3dc79fa577144c39f29de7283da6794a8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 18 Apr 2020 13:24:25 +0200 Subject: [PATCH 0556/1182] Update brew formula --- extras/httpie.rb | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/extras/httpie.rb b/extras/httpie.rb index 606fa4e5d0..1c40f7f8ad 100644 --- a/extras/httpie.rb +++ b/extras/httpie.rb @@ -9,43 +9,43 @@ class Httpie < Formula desc "User-friendly cURL replacement (command-line HTTP client)" homepage "https://httpie.org/" - url "https://files.pythonhosted.org/packages/35/6c/93da2ebd4eb768c3733437ce01b5fae297522434fdeabeeabdc4f42aabd3/httpie-2.0.0.tar.gz" - sha256 "8c04f9756f1a7eac71a6dfa0834d0f6813dc8a982d8564f3a7418dcd19107c09" + url "https://files.pythonhosted.org/packages/e2/79/da6aec7b4356e8b325561b987c940e5b1e4de1200a5c3db7c57a97d61ca1/httpie-2.1.0.tar.gz" + sha256 "a76f1c72e83bd03cde3478c5f345d5570fdb2967ed19d68d09518088640b9e8e" revision 1 head "https://github.com/jakubroztocil/httpie.git" bottle do cellar :any_skip_relocation - sha256 "19694b5ec311939a8b73cc329ca49386155ed3a17e4eca691779c725d36286b5" => :catalina - sha256 "8c7d93d55ea3351e25fadfdd3748ca0a3ff7dd62ab9dbf31b7243fba76890c4d" => :mojave - sha256 "e0d5269bb5d03a1797c8612005fa46d6a35f2b84eb76e9607ef1169464b566ea" => :high_sierra + sha256 "1fb33d9c85dc462c2549a03cf08670edad8014a5fdf0a7cb26493c64af40283d" => :catalina + sha256 "a22030f0b96c698c90265286ee80ffbb03079d1d008a80c0bdb3ea15a17d3fbb" => :mojave + sha256 "9f994ecf826efe53a3a49d1c3193e271629068d11306df55adeea2842a8afb8c" => :high_sierra end depends_on "python@3.8" resource "Pygments" do - url "https://files.pythonhosted.org/packages/cb/9f/27d4844ac5bf158a33900dbad7985951e2910397998e85712da03ce125f0/Pygments-2.5.2.tar.gz" - sha256 "98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe" + url "https://files.pythonhosted.org/packages/6e/4d/4d2fe93a35dfba417311a4ff627489a947b01dc0cc377a3673c00cf7e4b2/Pygments-2.6.1.tar.gz" + sha256 "647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44" end resource "requests" do - url "https://files.pythonhosted.org/packages/01/62/ddcf76d1d19885e8579acb1b1df26a852b03472c0e46d2b959a714c90608/requests-2.22.0.tar.gz" - sha256 "11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4" + url "https://files.pythonhosted.org/packages/f5/4f/280162d4bd4d8aad241a21aecff7a6e46891b905a4341e7ab549ebaf7915/requests-2.23.0.tar.gz" + sha256 "b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6" end resource "certifi" do - url "https://files.pythonhosted.org/packages/41/bf/9d214a5af07debc6acf7f3f257265618f1db242a3f8e49a9b516f24523a6/certifi-2019.11.28.tar.gz" - sha256 "25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" + url "https://files.pythonhosted.org/packages/b8/e2/a3a86a67c3fc8249ed305fc7b7d290ebe5e4d46ad45573884761ef4dea7b/certifi-2020.4.5.1.tar.gz" + sha256 "51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519" end resource "urllib3" do - url "https://files.pythonhosted.org/packages/ad/fc/54d62fa4fc6e675678f9519e677dfc29b8964278d75333cf142892caf015/urllib3-1.25.7.tar.gz" - sha256 "f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745" + url "https://files.pythonhosted.org/packages/05/8c/40cd6949373e23081b3ea20d5594ae523e681b6f472e600fbc95ed046a36/urllib3-1.25.9.tar.gz" + sha256 "3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527" end resource "idna" do - url "https://files.pythonhosted.org/packages/ad/13/eb56951b6f7950cadb579ca166e448ba77f9d24efc03edd7e55fa57d04b7/idna-2.8.tar.gz" - sha256 "c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407" + url "https://files.pythonhosted.org/packages/cb/19/57503b5de719ee45e83472f339f617b0c01ad75cba44aba1e4c97c2b0abd/idna-2.9.tar.gz" + sha256 "7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb" end resource "chardet" do From 495f67229afc389d9ae705f4345c5e466ae49674 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 18 Apr 2020 13:39:17 +0200 Subject: [PATCH 0557/1182] Fix brew formula --- extras/httpie.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/extras/httpie.rb b/extras/httpie.rb index 1c40f7f8ad..272cf35279 100644 --- a/extras/httpie.rb +++ b/extras/httpie.rb @@ -11,7 +11,6 @@ class Httpie < Formula homepage "https://httpie.org/" url "https://files.pythonhosted.org/packages/e2/79/da6aec7b4356e8b325561b987c940e5b1e4de1200a5c3db7c57a97d61ca1/httpie-2.1.0.tar.gz" sha256 "a76f1c72e83bd03cde3478c5f345d5570fdb2967ed19d68d09518088640b9e8e" - revision 1 head "https://github.com/jakubroztocil/httpie.git" bottle do From 4a994954665a9d7b5d52c8261fc53645d167fdc8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 18 Apr 2020 20:44:40 +0200 Subject: [PATCH 0558/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8dda80c99a..1885593d99 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,7 +14,7 @@ This project adheres to `Semantic Versioning `_. * Added ``--path-as-is`` to bypass dot segment (``/../`` or ``/./``) URL squashing (#895). -* Changed the default value ``Accept`` header value for JSON requests from +* Changed the default ``Accept`` header value for JSON requests from ``application/json, */*`` to ``application/json, */*;q=0.5`` to clearly indicate preference (#488). * Fixed ``--form`` file upload mixed with redirected ``stdin`` error handling From e83e275dffaafc77f2982f24120eac972b6c7873 Mon Sep 17 00:00:00 2001 From: Jakob Krigovsky Date: Mon, 20 Apr 2020 17:45:51 +0200 Subject: [PATCH 0559/1182] =?UTF-8?q?Fix=20spelling=20of=20=E2=80=9CGitHub?= =?UTF-8?q?=E2=80=9D=20(#899)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.rst | 2 +- CONTRIBUTING.rst | 2 +- README.rst | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1885593d99..2b423a70c9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -128,7 +128,7 @@ This project adheres to `Semantic Versioning `_. ``$ alias https='http --default-scheme=https``. * Added ``-I`` as a shortcut for ``--ignore-stdin``. * Added fish shell completion (located in ``extras/httpie-completion.fish`` - in the Github repo). + in the GitHub repo). * Updated ``requests`` to 2.10.0 so that SOCKS support can be added via ``pip install requests[socks]``. * Changed the default JSON ``Accept`` header from ``application/json`` diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 7f959a0ab1..8ecff67ffd 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -115,7 +115,7 @@ Testing & CI Please add tests for any new features and bug fixes. When you open a pull request, -`Github Actions `_ +`GitHub Actions `_ will automatically run HTTPie’s `test suite`_ against your code so please make sure all checks pass. diff --git a/README.rst b/README.rst index 15eeb1e389..ce5259db68 100644 --- a/README.rst +++ b/README.rst @@ -228,7 +228,7 @@ Build and print a request without sending it using `offline mode`_: $ http --offline httpbin.org/post hello=offline -Use `Github API`_ to post a comment on an +Use `GitHub API`_ to post a comment on an `issue `_ with `authentication`_: @@ -1933,7 +1933,7 @@ have contributed. .. _pip: https://pip.pypa.io/en/stable/installing/ -.. _Github API: https://developer.github.com/v3/issues/comments/#create-a-comment +.. _GitHub API: https://developer.github.com/v3/issues/comments/#create-a-comment .. _these fine people: https://github.com/jakubroztocil/httpie/contributors .. _Jakub Roztocil: https://roztocil.co .. _@jakubroztocil: https://twitter.com/jakubroztocil From d9a2d665add9a739990944342500fb0759c46ccc Mon Sep 17 00:00:00 2001 From: Jakob Krigovsky Date: Mon, 20 Apr 2020 17:46:43 +0200 Subject: [PATCH 0560/1182] Fix typo (#898) --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 762a8407da..11d04d10a4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ htmlcov ############################################################################## -# The bellow is GitHub template for Python project. gitignore. +# The below is GitHub template for Python project. gitignore. # ############################################################################## From b2044fc18d3c3d5e927746d4dcf26fee9acbfc3a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 24 Apr 2020 12:15:19 +0200 Subject: [PATCH 0561/1182] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ce5259db68..cabb001cb8 100644 --- a/README.rst +++ b/README.rst @@ -707,7 +707,7 @@ There are a couple of default headers that HTTPie sets: -Any of these except ``Host`` can be overwritten and some of them unset. +Any of these can be overwritten and some of them unset (see bellow). From e11a2d13463a21fcc3d7758eef7cba59fbc24fdd Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 13 May 2020 21:55:24 +0200 Subject: [PATCH 0562/1182] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 80d84ae3c9..6a7b993b01 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,6 @@ # These are supported funding model platforms -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +github: jakubroztocil # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username From 5af0874ed302e9ef79cec97836529ccf353e53f7 Mon Sep 17 00:00:00 2001 From: Ash Holland Date: Thu, 21 May 2020 14:50:00 +0100 Subject: [PATCH 0563/1182] Support (part of) the XDG Base Directory Specification (#920) On Unix-like systems, the configuration file now lives in $XDG_CONFIG_HOME/httpie/ by default, not ~/.httpie/ (the behaviour on Windows is unchanged). The previous location is still checked, in order to support existing installations. Searching $XDG_CONFIG_DIRS is still not supported. Fixes #145; supersedes #436. --- README.rst | 7 +++++-- httpie/config.py | 27 ++++++++++++++++++++++----- tests/test_config.py | 42 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index cabb001cb8..d597302d87 100644 --- a/README.rst +++ b/README.rst @@ -1691,8 +1691,11 @@ but you can create it manually. Config file directory --------------------- -The default location of the configuration file is ``~/.httpie/config.json`` -(or ``%APPDATA%\httpie\config.json`` on Windows). +The default location of the configuration file on most platforms is +``$XDG_CONFIG_HOME/httpie/config.json`` (defaulting to +``~/.config/httpie/config.json``). For backwards compatibility, if the directory +``~/.httpie`` exists, the configuration file there will be used instead. On +Windows, the config file is located at ``%APPDATA%\httpie\config.json``. The config directory can be changed by setting the ``$HTTPIE_CONFIG_DIR`` environment variable: diff --git a/httpie/config.py b/httpie/config.py index 821937437b..d1b7ae75f5 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -8,11 +8,28 @@ from httpie.compat import is_windows -DEFAULT_CONFIG_DIR = Path(os.environ.get( - 'HTTPIE_CONFIG_DIR', - os.path.expanduser('~/.httpie') if not is_windows else - os.path.expandvars(r'%APPDATA%\\httpie') -)) +def get_default_config_dir() -> Path: + """Return the path to the httpie configuration directory. + + This directory isn't guaranteed to exist, and nor are any of its + ancestors. + """ + env_config_dir = os.environ.get('HTTPIE_CONFIG_DIR') + if env_config_dir: + return Path(env_config_dir) + if is_windows: + return Path(os.path.expandvars(r'%APPDATA%\httpie')) + legacy_config_dir = os.path.expanduser('~/.httpie') + if os.path.exists(legacy_config_dir): + return Path(legacy_config_dir) + xdg_config_dir = os.environ.get('XDG_CONFIG_HOME') + if not xdg_config_dir or not os.path.isabs(xdg_config_dir): + xdg_config_dir = os.path.expanduser('~/.config') + httpie_config_dir = os.path.join(xdg_config_dir, 'httpie') + return Path(httpie_config_dir) + + +DEFAULT_CONFIG_DIR = get_default_config_dir() class ConfigFileError(Exception): diff --git a/tests/test_config.py b/tests/test_config.py index 0a33ef6864..3612234da2 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,7 +1,10 @@ +import os.path +from pathlib import Path + import pytest from httpie.compat import is_windows -from httpie.config import Config +from httpie.config import Config, get_default_config_dir from utils import HTTP_OK, MockEnvironment, http @@ -48,3 +51,40 @@ def test_default_options_overwrite(httpbin): assert r.json['json'] == { "foo": "bar" } + + +@pytest.mark.skipif(is_windows, reason='XDG_CONFIG_HOME is only supported on *nix') +def test_config_file_location_xdg(monkeypatch, tmp_path): + monkeypatch.delenv('HTTPIE_CONFIG_DIR', raising=False) + home = tmp_path.absolute().as_posix() + monkeypatch.setenv('HOME', home) + xdg_config_home = tmp_path.joinpath("different_config") + os.mkdir(xdg_config_home) + monkeypatch.setenv('XDG_CONFIG_HOME', xdg_config_home.absolute().as_posix()) + assert get_default_config_dir() == xdg_config_home.joinpath('httpie') + monkeypatch.delenv('XDG_CONFIG_HOME') + # NB: this should be true even though .config doesn't exist. + assert get_default_config_dir() == tmp_path.joinpath('.config', 'httpie') + monkeypatch.setenv('XDG_CONFIG_HOME', 'some/nonabsolute/path') + assert get_default_config_dir() == tmp_path.joinpath('.config', 'httpie') + + +@pytest.mark.skipif(is_windows, reason='legacy config file location is only checked on *nix') +def test_config_file_location_legacy(monkeypatch, tmp_path): + monkeypatch.delenv('HTTPIE_CONFIG_DIR', raising=False) + home = tmp_path.absolute().as_posix() + monkeypatch.setenv('HOME', home) + os.mkdir(tmp_path.joinpath('.httpie')) + assert get_default_config_dir() == tmp_path.joinpath('.httpie') + + +@pytest.mark.skipif(not is_windows, reason='windows-only') +def test_config_file_location_windows(monkeypatch): + monkeypatch.delenv('HTTPIE_CONFIG_DIR', raising=False) + assert get_default_config_dir() == Path(os.path.expandvars(r'%APPDATA%\httpie')) + + +def test_config_file_location_custom(monkeypatch, tmp_path): + httpie_config_dir = tmp_path.joinpath('custom', 'directory') + monkeypatch.setenv('HTTPIE_CONFIG_DIR', str(httpie_config_dir.absolute())) + assert get_default_config_dir() == httpie_config_dir From 7b676dd58382f3ab97b821bea67280c46c5a52c4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 21 May 2020 15:56:53 +0200 Subject: [PATCH 0564/1182] Update ~/.httpie references to ~/.config/httpie --- README.rst | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index d597302d87..e0c1f6c3fd 100644 --- a/README.rst +++ b/README.rst @@ -1621,9 +1621,9 @@ To create or reuse a different session, simple specify a different name: $ http --session=user2 -a user2:password httpbin.org/get X-Bar:Foo -Named sessions’s data is stored in JSON files in the the ``sessions`` -subdirectory of the `config`_ directory: -``~/.httpie/sessions//.json`` +Named sessions’s data is stored in JSON files inside the ``sessions`` +subdirectory of the `config`_ directory, typically: +``~/.config/httpie/sessions//.json`` (``%APPDATA%\httpie\sessions\\.json`` on Windows). If you have executed the above commands on a unix machine, @@ -1632,7 +1632,7 @@ you should be able list the generated sessions files using: .. code-block:: bash - $ ls -l ~/.httpie/sessions/httpbin.org + $ ls -l ~/.config/httpie/sessions/httpbin.org Anonymous sessions @@ -1655,7 +1655,7 @@ allows for sessions to be re-used across multiple hosts: .. code-block:: bash # You can also refer to a previously created named session: - $ http --session=~/.httpie/sessions/another.example.org/test.json example.org + $ http --session=~/.config/httpie/sessions/another.example.org/test.json example.org When creating anonymous sessions, please remember to always include at least @@ -1693,9 +1693,12 @@ Config file directory The default location of the configuration file on most platforms is ``$XDG_CONFIG_HOME/httpie/config.json`` (defaulting to -``~/.config/httpie/config.json``). For backwards compatibility, if the directory -``~/.httpie`` exists, the configuration file there will be used instead. On -Windows, the config file is located at ``%APPDATA%\httpie\config.json``. +``~/.config/httpie/config.json``). + +For backwards compatibility, if the directory ``~/.httpie`` exists, +the configuration file there will be used instead. + +On Windows, the config file is located at ``%APPDATA%\httpie\config.json``. The config directory can be changed by setting the ``$HTTPIE_CONFIG_DIR`` environment variable: @@ -1725,7 +1728,7 @@ For instance, you can use this config option to change your default color theme: .. code-block:: bash - $ cat ~/.httpie/config.json + $ cat ~/.config/httpie/config.json .. code-block:: json From afee6a797010fdc7a484aca387bdd635560f97e5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 21 May 2020 15:59:03 +0200 Subject: [PATCH 0565/1182] Added changelog entry for $XDG_CONFIG_HOME support --- CHANGELOG.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2b423a70c9..48390f8d78 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,16 +9,19 @@ This project adheres to `Semantic Versioning `_. `2.2.0-dev`_ (unreleased) ------------------------- +* Added support ``$XDG_CONFIG_HOME`` (`#920`_). + + `2.1.0`_ (2020-04-18) --------------------- * Added ``--path-as-is`` to bypass dot segment (``/../`` or ``/./``) - URL squashing (#895). + URL squashing (`#895`_). * Changed the default ``Accept`` header value for JSON requests from ``application/json, */*`` to ``application/json, */*;q=0.5`` - to clearly indicate preference (#488). + to clearly indicate preference (`#488`_). * Fixed ``--form`` file upload mixed with redirected ``stdin`` error handling - (#840). + (`#840`_). `2.0.0`_ (2020-01-12) @@ -431,3 +434,4 @@ This project adheres to `Semantic Versioning `_. .. _#488:https://github.com/jakubroztocil/httpie/issues/488 .. _#840:https://github.com/jakubroztocil/httpie/issues/840 .. _#895:https://github.com/jakubroztocil/httpie/issues/895 +.. _#920:https://github.com/jakubroztocil/httpie/issues/920 From defe4bc76d1af914d30bb9124e83a093d5ec6f80 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 21 May 2020 16:03:40 +0200 Subject: [PATCH 0566/1182] Fix issue links --- CHANGELOG.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 48390f8d78..92efcb84cb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -431,7 +431,7 @@ This project adheres to `Semantic Versioning `_. .. _2.2.0-dev: https://github.com/jakubroztocil/httpie/compare/2.1.0...master -.. _#488:https://github.com/jakubroztocil/httpie/issues/488 -.. _#840:https://github.com/jakubroztocil/httpie/issues/840 -.. _#895:https://github.com/jakubroztocil/httpie/issues/895 -.. _#920:https://github.com/jakubroztocil/httpie/issues/920 +.. _#488: https://github.com/jakubroztocil/httpie/issues/488 +.. _#840: https://github.com/jakubroztocil/httpie/issues/840 +.. _#895: https://github.com/jakubroztocil/httpie/issues/895 +.. _#920: https://github.com/jakubroztocil/httpie/issues/920 From 0c4709410955e6bb4ae6b91c08d1d617def752df Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 22 May 2020 12:38:42 +0200 Subject: [PATCH 0567/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 92efcb84cb..013cadcec4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,7 +9,7 @@ This project adheres to `Semantic Versioning `_. `2.2.0-dev`_ (unreleased) ------------------------- -* Added support ``$XDG_CONFIG_HOME`` (`#920`_). +* Added support for ``$XDG_CONFIG_HOME`` (`#920`_). `2.1.0`_ (2020-04-18) From 3e20ade6457eea46345b89994c0f9391dd9fd04a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 23 May 2020 12:12:15 +0200 Subject: [PATCH 0568/1182] Cleanup & refactor XDG_CONFIG_HOME support --- httpie/config.py | 50 ++++++++++++++++++++------- tests/test_config.py | 82 ++++++++++++++++++++++++++------------------ 2 files changed, 86 insertions(+), 46 deletions(-) diff --git a/httpie/config.py b/httpie/config.py index d1b7ae75f5..78adf13bf2 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -8,25 +8,51 @@ from httpie.compat import is_windows +ENV_XDG_CONFIG_HOME = 'XDG_CONFIG_HOME' +ENV_HTTPIE_CONFIG_DIR = 'HTTPIE_CONFIG_DIR' +DEFAULT_CONFIG_DIRNAME = 'httpie' +DEFAULT_RELATIVE_XDG_CONFIG_HOME = Path('.config') +DEFAULT_RELATIVE_LEGACY_CONFIG_DIR = Path('.httpie') +DEFAULT_WINDOWS_CONFIG_DIR = Path( + os.path.expandvars('%APPDATA%')) / DEFAULT_CONFIG_DIRNAME + + def get_default_config_dir() -> Path: - """Return the path to the httpie configuration directory. + """ + Return the path to the httpie configuration directory. This directory isn't guaranteed to exist, and nor are any of its - ancestors. + ancestors (only the legacy ~/.httpie, if returned, is guaranteed to exist). + + XDG Base Directory Specification support: + + + + $XDG_CONFIG_HOME is supported; $XDG_CONFIG_DIRS is not + """ - env_config_dir = os.environ.get('HTTPIE_CONFIG_DIR') + # 1. explicitly set through env + env_config_dir = os.environ.get(ENV_HTTPIE_CONFIG_DIR) if env_config_dir: return Path(env_config_dir) + + # 2. Windows if is_windows: - return Path(os.path.expandvars(r'%APPDATA%\httpie')) - legacy_config_dir = os.path.expanduser('~/.httpie') - if os.path.exists(legacy_config_dir): - return Path(legacy_config_dir) - xdg_config_dir = os.environ.get('XDG_CONFIG_HOME') - if not xdg_config_dir or not os.path.isabs(xdg_config_dir): - xdg_config_dir = os.path.expanduser('~/.config') - httpie_config_dir = os.path.join(xdg_config_dir, 'httpie') - return Path(httpie_config_dir) + return DEFAULT_WINDOWS_CONFIG_DIR + + home_dir = Path.home() + + # 3. legacy ~/.httpie + legacy_config_dir = home_dir / DEFAULT_RELATIVE_LEGACY_CONFIG_DIR + if legacy_config_dir.exists(): + return legacy_config_dir + + # 4. XDG + xdg_config_home_dir = os.environ.get( + ENV_XDG_CONFIG_HOME, # 4.1. explicit + home_dir / DEFAULT_RELATIVE_XDG_CONFIG_HOME # 4.2. default + ) + return Path(xdg_config_home_dir) / DEFAULT_CONFIG_DIRNAME DEFAULT_CONFIG_DIR = get_default_config_dir() diff --git a/tests/test_config.py b/tests/test_config.py index 3612234da2..32106c79e9 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,10 +1,14 @@ -import os.path from pathlib import Path import pytest +from _pytest.monkeypatch import MonkeyPatch from httpie.compat import is_windows -from httpie.config import Config, get_default_config_dir +from httpie.config import ( + Config, DEFAULT_CONFIG_DIRNAME, DEFAULT_RELATIVE_LEGACY_CONFIG_DIR, + DEFAULT_RELATIVE_XDG_CONFIG_HOME, DEFAULT_WINDOWS_CONFIG_DIR, + ENV_HTTPIE_CONFIG_DIR, ENV_XDG_CONFIG_HOME, get_default_config_dir, +) from utils import HTTP_OK, MockEnvironment, http @@ -53,38 +57,48 @@ def test_default_options_overwrite(httpbin): } -@pytest.mark.skipif(is_windows, reason='XDG_CONFIG_HOME is only supported on *nix') -def test_config_file_location_xdg(monkeypatch, tmp_path): - monkeypatch.delenv('HTTPIE_CONFIG_DIR', raising=False) - home = tmp_path.absolute().as_posix() - monkeypatch.setenv('HOME', home) - xdg_config_home = tmp_path.joinpath("different_config") - os.mkdir(xdg_config_home) - monkeypatch.setenv('XDG_CONFIG_HOME', xdg_config_home.absolute().as_posix()) - assert get_default_config_dir() == xdg_config_home.joinpath('httpie') - monkeypatch.delenv('XDG_CONFIG_HOME') - # NB: this should be true even though .config doesn't exist. - assert get_default_config_dir() == tmp_path.joinpath('.config', 'httpie') - monkeypatch.setenv('XDG_CONFIG_HOME', 'some/nonabsolute/path') - assert get_default_config_dir() == tmp_path.joinpath('.config', 'httpie') - - -@pytest.mark.skipif(is_windows, reason='legacy config file location is only checked on *nix') -def test_config_file_location_legacy(monkeypatch, tmp_path): - monkeypatch.delenv('HTTPIE_CONFIG_DIR', raising=False) - home = tmp_path.absolute().as_posix() - monkeypatch.setenv('HOME', home) - os.mkdir(tmp_path.joinpath('.httpie')) - assert get_default_config_dir() == tmp_path.joinpath('.httpie') +@pytest.mark.skipif(is_windows, reason='XDG_CONFIG_HOME needs *nix') +def test_explicit_xdg_config_home(monkeypatch: MonkeyPatch, tmp_path: Path): + home_dir = tmp_path + monkeypatch.delenv(ENV_HTTPIE_CONFIG_DIR, raising=False) + monkeypatch.setenv('HOME', home_dir) + custom_xdg_config_home = home_dir / 'custom_xdg_config_home' + monkeypatch.setenv(ENV_XDG_CONFIG_HOME, str(custom_xdg_config_home)) + expected_config_dir = custom_xdg_config_home / DEFAULT_CONFIG_DIRNAME + assert get_default_config_dir() == expected_config_dir + + +@pytest.mark.skipif(is_windows, reason='XDG_CONFIG_HOME needs *nix') +def test_default_xdg_config_home(monkeypatch: MonkeyPatch, tmp_path: Path): + home_dir = tmp_path + monkeypatch.delenv(ENV_HTTPIE_CONFIG_DIR, raising=False) + monkeypatch.delenv(ENV_XDG_CONFIG_HOME, raising=False) + monkeypatch.setenv('HOME', home_dir) + expected_config_dir = ( + home_dir + / DEFAULT_RELATIVE_XDG_CONFIG_HOME + / DEFAULT_CONFIG_DIRNAME + ) + assert get_default_config_dir() == expected_config_dir + + +@pytest.mark.skipif(is_windows, reason='legacy config dir needs *nix') +def test_legacy_config_dir(monkeypatch: MonkeyPatch, tmp_path: Path): + home_dir = tmp_path + monkeypatch.delenv(ENV_HTTPIE_CONFIG_DIR, raising=False) + monkeypatch.setenv('HOME', home_dir) + legacy_config_dir = home_dir / DEFAULT_RELATIVE_LEGACY_CONFIG_DIR + legacy_config_dir.mkdir() + assert get_default_config_dir() == legacy_config_dir + + +def test_custom_config_dir(monkeypatch: MonkeyPatch, tmp_path: Path): + httpie_config_dir = tmp_path / 'custom/directory' + monkeypatch.setenv(ENV_HTTPIE_CONFIG_DIR, str(httpie_config_dir)) + assert get_default_config_dir() == httpie_config_dir @pytest.mark.skipif(not is_windows, reason='windows-only') -def test_config_file_location_windows(monkeypatch): - monkeypatch.delenv('HTTPIE_CONFIG_DIR', raising=False) - assert get_default_config_dir() == Path(os.path.expandvars(r'%APPDATA%\httpie')) - - -def test_config_file_location_custom(monkeypatch, tmp_path): - httpie_config_dir = tmp_path.joinpath('custom', 'directory') - monkeypatch.setenv('HTTPIE_CONFIG_DIR', str(httpie_config_dir.absolute())) - assert get_default_config_dir() == httpie_config_dir +def test_windows_config_dir(monkeypatch: MonkeyPatch): + monkeypatch.delenv(ENV_HTTPIE_CONFIG_DIR, raising=False) + assert get_default_config_dir() == DEFAULT_WINDOWS_CONFIG_DIR From 0a81facccfdac1229f25db585bbcd4d3d8a7de92 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 23 May 2020 12:14:09 +0200 Subject: [PATCH 0569/1182] Str env vars --- tests/test_config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_config.py b/tests/test_config.py index 32106c79e9..cdfbe8d6d9 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -61,7 +61,7 @@ def test_default_options_overwrite(httpbin): def test_explicit_xdg_config_home(monkeypatch: MonkeyPatch, tmp_path: Path): home_dir = tmp_path monkeypatch.delenv(ENV_HTTPIE_CONFIG_DIR, raising=False) - monkeypatch.setenv('HOME', home_dir) + monkeypatch.setenv('HOME', str(home_dir)) custom_xdg_config_home = home_dir / 'custom_xdg_config_home' monkeypatch.setenv(ENV_XDG_CONFIG_HOME, str(custom_xdg_config_home)) expected_config_dir = custom_xdg_config_home / DEFAULT_CONFIG_DIRNAME @@ -73,7 +73,7 @@ def test_default_xdg_config_home(monkeypatch: MonkeyPatch, tmp_path: Path): home_dir = tmp_path monkeypatch.delenv(ENV_HTTPIE_CONFIG_DIR, raising=False) monkeypatch.delenv(ENV_XDG_CONFIG_HOME, raising=False) - monkeypatch.setenv('HOME', home_dir) + monkeypatch.setenv('HOME', str(home_dir)) expected_config_dir = ( home_dir / DEFAULT_RELATIVE_XDG_CONFIG_HOME @@ -86,7 +86,7 @@ def test_default_xdg_config_home(monkeypatch: MonkeyPatch, tmp_path: Path): def test_legacy_config_dir(monkeypatch: MonkeyPatch, tmp_path: Path): home_dir = tmp_path monkeypatch.delenv(ENV_HTTPIE_CONFIG_DIR, raising=False) - monkeypatch.setenv('HOME', home_dir) + monkeypatch.setenv('HOME', str(home_dir)) legacy_config_dir = home_dir / DEFAULT_RELATIVE_LEGACY_CONFIG_DIR legacy_config_dir.mkdir() assert get_default_config_dir() == legacy_config_dir From d62d6a77d1c00dfa4052adc85ebcb109e84c2e2c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 23 May 2020 13:26:06 +0200 Subject: [PATCH 0570/1182] Add support for --ciphers (#870) --- CHANGELOG.rst | 2 ++ README.rst | 32 +++++++++++++++++++++++++++----- httpie/cli/constants.py | 14 -------------- httpie/cli/definition.py | 16 ++++++++++++++-- httpie/client.py | 20 ++++++-------------- httpie/ssl.py | 38 ++++++++++++++++++++++++++++++++++++++ tests/test_ssl.py | 35 ++++++++++++++++++++++++++++------- 7 files changed, 115 insertions(+), 42 deletions(-) create mode 100644 httpie/ssl.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 013cadcec4..d2023b4f22 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,7 @@ This project adheres to `Semantic Versioning `_. `2.2.0-dev`_ (unreleased) ------------------------- +* Added support for ``--ciphers`` (`#870`_). * Added support for ``$XDG_CONFIG_HOME`` (`#920`_). @@ -433,5 +434,6 @@ This project adheres to `Semantic Versioning `_. .. _#488: https://github.com/jakubroztocil/httpie/issues/488 .. _#840: https://github.com/jakubroztocil/httpie/issues/840 +.. _#870: https://github.com/jakubroztocil/httpie/issues/870 .. _#895: https://github.com/jakubroztocil/httpie/issues/895 .. _#920: https://github.com/jakubroztocil/httpie/issues/920 diff --git a/README.rst b/README.rst index e0c1f6c3fd..da7d6570cf 100644 --- a/README.rst +++ b/README.rst @@ -1092,11 +1092,13 @@ path of the key file with ``--cert-key``: SSL version ----------- -Use the ``--ssl=`` 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``, ``tls1.3``. (The actually -available set of protocols may vary depending on your OpenSSL installation.) +Use the ``--ssl=`` option 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``, ``tls1.3``. +(The actually available set of protocols may vary depending on your OpenSSL +installation.) .. code-block:: bash @@ -1104,6 +1106,26 @@ available set of protocols may vary depending on your OpenSSL installation.) $ http --ssl=ssl3 https://vulnerable.example.org + +SSL ciphers +----------- + +You can specify the available ciphers with ``--ciphers``. +It should be a string in the +`OpenSSL cipher list format `_. + +.. code-block:: bash + + $ http --ciphers=ECDHE-RSA-AES128-GCM-SHA256 https://httpbin.org/get + +Note: these cipher strings do not change the negotiated version of SSL or TLS, +they only affect the list of available cipher suites. + +To see the default cipher string, run ``http --help`` and see +the ``--ciphers`` section under SSL. + + + Output options ============== diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index ba34dcc9d6..5865d5c5dd 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -87,17 +87,3 @@ OUTPUT_OPTIONS_DEFAULT = OUT_RESP_HEAD + OUT_RESP_BODY OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED = OUT_RESP_BODY OUTPUT_OPTIONS_DEFAULT_OFFLINE = OUT_REQ_HEAD + OUT_REQ_BODY - -SSL_VERSION_ARG_MAPPING = { - 'ssl2.3': 'PROTOCOL_SSLv23', - 'ssl3': 'PROTOCOL_SSLv3', - 'tls1': 'PROTOCOL_TLSv1', - 'tls1.1': 'PROTOCOL_TLSv1_1', - 'tls1.2': 'PROTOCOL_TLSv1_2', - 'tls1.3': 'PROTOCOL_TLSv1_3', -} -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) -} diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 43fb5348b5..bcd8dbc520 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -13,7 +13,7 @@ from httpie.cli.constants import ( OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_BODY, OUT_RESP_HEAD, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, - SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY, SSL_VERSION_ARG_MAPPING, + SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY, ) from httpie.output.formatters.colors import ( AUTO_STYLE, AVAILABLE_STYLES, DEFAULT_STYLE, @@ -21,6 +21,7 @@ from httpie.plugins import plugin_manager from httpie.plugins.builtin import BuiltinAuthPlugin from httpie.sessions import DEFAULT_SESSIONS_DIR +from httpie.ssl import DEFAULT_SSL_CIPHERS, AVAILABLE_SSL_VERSION_ARG_MAPPING parser = HTTPieArgumentParser( @@ -580,7 +581,7 @@ def __iter__(self): ssl.add_argument( '--ssl', # TODO: Maybe something more general, such as --secure-protocol? dest='ssl_version', - choices=list(sorted(SSL_VERSION_ARG_MAPPING.keys())), + choices=list(sorted(AVAILABLE_SSL_VERSION_ARG_MAPPING.keys())), help=""" The desired protocol version to use. This will default to SSL v2.3 which will negotiate the highest protocol that both @@ -590,6 +591,17 @@ def __iter__(self): """ ) +ssl.add_argument( + '--ciphers', + help=f""" + + A string in the OpenSSL cipher list format. By default, the following + is used: + + {DEFAULT_SSL_CIPHERS} + + """ +) ssl.add_argument( '--cert', default=None, diff --git a/httpie/client.py b/httpie/client.py index e3c6fa3982..991d575530 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -9,13 +9,12 @@ from urllib.parse import urlparse, urlunparse import requests -from requests.adapters import HTTPAdapter from httpie import __version__ -from httpie.cli.constants import SSL_VERSION_ARG_MAPPING from httpie.cli.dicts import RequestHeadersDict from httpie.plugins import plugin_manager from httpie.sessions import get_httpie_session +from httpie.ssl import HTTPieHTTPSAdapter, AVAILABLE_SSL_VERSION_ARG_MAPPING from httpie.utils import repr_dict @@ -57,6 +56,7 @@ def collect_messages( send_kwargs_mergeable_from_env = make_send_kwargs_mergeable_from_env(args) requests_session = build_requests_session( ssl_version=args.ssl_version, + ciphers=args.ciphers, ) if httpie_session: @@ -121,6 +121,7 @@ def collect_messages( @contextmanager def max_headers(limit): # + # noinspection PyUnresolvedReferences orig = http.client._MAXHEADERS http.client._MAXHEADERS = limit or float('Inf') try: @@ -145,26 +146,17 @@ def compress_body(request: requests.PreparedRequest, always: bool): request.headers['Content-Length'] = str(len(deflated_data)) -class HTTPieHTTPSAdapter(HTTPAdapter): - - def __init__(self, ssl_version=None, **kwargs): - self._ssl_version = ssl_version - super().__init__(**kwargs) - - def init_poolmanager(self, *args, **kwargs): - kwargs['ssl_version'] = self._ssl_version - super().init_poolmanager(*args, **kwargs) - - def build_requests_session( ssl_version: str = None, + ciphers: str = None, ) -> requests.Session: requests_session = requests.Session() # Install our adapter. requests_session.mount('https://', HTTPieHTTPSAdapter( + ciphers=ciphers, ssl_version=( - SSL_VERSION_ARG_MAPPING[ssl_version] + AVAILABLE_SSL_VERSION_ARG_MAPPING[ssl_version] if ssl_version else None ) )) diff --git a/httpie/ssl.py b/httpie/ssl.py new file mode 100644 index 0000000000..9f8e58ec88 --- /dev/null +++ b/httpie/ssl.py @@ -0,0 +1,38 @@ +import ssl + +from requests.adapters import HTTPAdapter +# noinspection PyPackageRequirements +from urllib3.util.ssl_ import DEFAULT_CIPHERS, create_urllib3_context + + +DEFAULT_SSL_CIPHERS = DEFAULT_CIPHERS +SSL_VERSION_ARG_MAPPING = { + 'ssl2.3': 'PROTOCOL_SSLv23', + 'ssl3': 'PROTOCOL_SSLv3', + 'tls1': 'PROTOCOL_TLSv1', + 'tls1.1': 'PROTOCOL_TLSv1_1', + 'tls1.2': 'PROTOCOL_TLSv1_2', + 'tls1.3': 'PROTOCOL_TLSv1_3', +} +AVAILABLE_SSL_VERSION_ARG_MAPPING = { + arg: getattr(ssl, constant_name) + for arg, constant_name in SSL_VERSION_ARG_MAPPING.items() + if hasattr(ssl, constant_name) +} + + +class HTTPieHTTPSAdapter(HTTPAdapter): + def __init__(self, ssl_version: str = None, ciphers: str = None, **kwargs): + self._ssl_context: ssl.SSLContext = create_urllib3_context( + ciphers=ciphers, + ssl_version=ssl_version + ) + super().__init__(**kwargs) + + def init_poolmanager(self, *args, **kwargs): + kwargs['ssl_context'] = self._ssl_context + return super().init_poolmanager(*args, **kwargs) + + def proxy_manager_for(self, *args, **kwargs): + kwargs['ssl_context'] = self._ssl_context + return super().proxy_manager_for(*args, **kwargs) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 051532f87d..31e0d534d0 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -1,11 +1,9 @@ -import os - import pytest import pytest_httpbin.certs import requests.exceptions +from httpie.ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS from httpie.status import ExitStatus -from httpie.cli.constants import SSL_VERSION_ARG_MAPPING from utils import HTTP_OK, TESTS_ROOT, http @@ -23,10 +21,12 @@ requests.exceptions.SSLError, ) +CERTS_ROOT = TESTS_ROOT / 'client_certs' +CLIENT_CERT = str(CERTS_ROOT / 'client.crt') +CLIENT_KEY = str(CERTS_ROOT / 'client.key') +CLIENT_PEM = str(CERTS_ROOT / 'client.pem') + -CLIENT_CERT = os.path.join(TESTS_ROOT, 'client_certs', 'client.crt') -CLIENT_KEY = os.path.join(TESTS_ROOT, 'client_certs', 'client.key') -CLIENT_PEM = os.path.join(TESTS_ROOT, 'client_certs', 'client.pem') # FIXME: # We test against a local httpbin instance which uses a self-signed cert. # Requests without --verify= will fail with a verification error. @@ -34,7 +34,8 @@ CA_BUNDLE = pytest_httpbin.certs.where() -@pytest.mark.parametrize('ssl_version', SSL_VERSION_ARG_MAPPING.keys()) +@pytest.mark.parametrize('ssl_version', + AVAILABLE_SSL_VERSION_ARG_MAPPING.keys()) def test_ssl_version(httpbin_secure, ssl_version): try: r = http( @@ -113,3 +114,23 @@ def test_verify_custom_ca_bundle_invalid_path(self, httpbin_secure): def test_verify_custom_ca_bundle_invalid_bundle(self, httpbin_secure): with pytest.raises(ssl_errors): http(httpbin_secure.url + '/get', '--verify', __file__) + + +def test_ciphers(httpbin_secure): + r = http( + httpbin_secure.url + '/get', + '--ciphers', + DEFAULT_SSL_CIPHERS, + ) + assert HTTP_OK in r + + +def test_ciphers_none_can_be_selected(httpbin_secure): + r = http( + httpbin_secure.url + '/get', + '--ciphers', + '__FOO__', + tolerate_error_exit_status=True, + ) + assert r.exit_status == ExitStatus.ERROR + assert 'No cipher can be selected.' in r.stderr From 7dbceafc01c2eb6d4905698cef99aa7da7bd11d8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 23 May 2020 13:34:59 +0200 Subject: [PATCH 0571/1182] Add docs for the `https` command alias --- README.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.rst b/README.rst index da7d6570cf..ba2829f52e 100644 --- a/README.rst +++ b/README.rst @@ -305,9 +305,14 @@ Request URL =========== The only information HTTPie needs to perform a request is a URL. + The default scheme is, somewhat unsurprisingly, ``http://``, and can be omitted from the argument – ``http example.org`` works just fine. +HTTPie also installs an ``https`` executable, where the default +scheme is ``https://``: ``https example.org`` (that is the only difference +between the ``http`` and ``https`` commands). + Querystring parameters ---------------------- From 5df3a916190d66c1cf916884204801651547927e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 23 May 2020 13:37:47 +0200 Subject: [PATCH 0572/1182] Add examples --- README.rst | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index ba2829f52e..5b6aa6fe72 100644 --- a/README.rst +++ b/README.rst @@ -306,12 +306,22 @@ Request URL The only information HTTPie needs to perform a request is a URL. -The default scheme is, somewhat unsurprisingly, ``http://``, -and can be omitted from the argument – ``http example.org`` works just fine. +The default scheme is ``http://`` and can be omitted from the argument: + +.. code-block:: bash + + # => http://example.org + $ http example.org + HTTPie also installs an ``https`` executable, where the default -scheme is ``https://``: ``https example.org`` (that is the only difference -between the ``http`` and ``https`` commands). +scheme is ``https://``: + + +.. code-block:: bash + + # => https://example.org + $ https example.org Querystring parameters From 165dc36f8d350549c56c12907af669ae0589d68c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 23 May 2020 13:38:28 +0200 Subject: [PATCH 0573/1182] Add examples --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 5b6aa6fe72..865352b16e 100644 --- a/README.rst +++ b/README.rst @@ -310,8 +310,8 @@ The default scheme is ``http://`` and can be omitted from the argument: .. code-block:: bash - # => http://example.org $ http example.org + # => http://example.org HTTPie also installs an ``https`` executable, where the default @@ -320,8 +320,8 @@ scheme is ``https://``: .. code-block:: bash - # => https://example.org $ https example.org + # => https://example.org Querystring parameters From a53505f26edcc9c2534a07aedc3858588506d285 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 23 May 2020 15:01:33 +0200 Subject: [PATCH 0574/1182] Fix SSL context --- httpie/ssl.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/httpie/ssl.py b/httpie/ssl.py index 9f8e58ec88..53e3878234 100644 --- a/httpie/ssl.py +++ b/httpie/ssl.py @@ -2,7 +2,10 @@ from requests.adapters import HTTPAdapter # noinspection PyPackageRequirements -from urllib3.util.ssl_ import DEFAULT_CIPHERS, create_urllib3_context +from urllib3.util.ssl_ import ( + DEFAULT_CIPHERS, create_urllib3_context, + resolve_ssl_version, +) DEFAULT_SSL_CIPHERS = DEFAULT_CIPHERS @@ -23,9 +26,9 @@ class HTTPieHTTPSAdapter(HTTPAdapter): def __init__(self, ssl_version: str = None, ciphers: str = None, **kwargs): - self._ssl_context: ssl.SSLContext = create_urllib3_context( + self._ssl_context = create_urllib3_context( ciphers=ciphers, - ssl_version=ssl_version + ssl_version=resolve_ssl_version(ssl_version), ) super().__init__(**kwargs) From 4c4efff56ad9b0df356fafa3267c2f39135f17c8 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 23 May 2020 20:19:16 +0200 Subject: [PATCH 0575/1182] Pass cert_reqs to context --- httpie/client.py | 15 ++++++++++----- httpie/ssl.py | 10 +++++++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 991d575530..cd1ec417be 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -14,19 +14,20 @@ from httpie.cli.dicts import RequestHeadersDict from httpie.plugins import plugin_manager from httpie.sessions import get_httpie_session -from httpie.ssl import HTTPieHTTPSAdapter, AVAILABLE_SSL_VERSION_ARG_MAPPING +from httpie.ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter from httpie.utils import repr_dict try: # noinspection PyPackageRequirements import urllib3 + + # urllib3.disable_warnings() except (ImportError, AttributeError): pass - FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8' JSON_CONTENT_TYPE = 'application/json' JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*;q=0.5' @@ -57,6 +58,7 @@ def collect_messages( requests_session = build_requests_session( ssl_version=args.ssl_version, ciphers=args.ciphers, + verify=bool(send_kwargs_mergeable_from_env['verify']) ) if httpie_session: @@ -147,19 +149,22 @@ def compress_body(request: requests.PreparedRequest, always: bool): def build_requests_session( + verify: bool, ssl_version: str = None, ciphers: str = None, ) -> requests.Session: requests_session = requests.Session() # Install our adapter. - requests_session.mount('https://', HTTPieHTTPSAdapter( + https_adapter = HTTPieHTTPSAdapter( ciphers=ciphers, + verify=verify, ssl_version=( AVAILABLE_SSL_VERSION_ARG_MAPPING[ssl_version] if ssl_version else None - ) - )) + ), + ) + requests_session.mount('https://', https_adapter) # Install adapters from plugins. for plugin_cls in plugin_manager.get_transport_plugins(): diff --git a/httpie/ssl.py b/httpie/ssl.py index 53e3878234..3390bb603e 100644 --- a/httpie/ssl.py +++ b/httpie/ssl.py @@ -25,11 +25,19 @@ class HTTPieHTTPSAdapter(HTTPAdapter): - def __init__(self, ssl_version: str = None, ciphers: str = None, **kwargs): + def __init__( + self, + verify: bool, + ssl_version: str = None, + ciphers: str = None, + **kwargs + ): self._ssl_context = create_urllib3_context( ciphers=ciphers, ssl_version=resolve_ssl_version(ssl_version), + cert_reqs=ssl.CERT_REQUIRED if verify else ssl.CERT_NONE ) + super().__init__(**kwargs) def init_poolmanager(self, *args, **kwargs): From 27d57ce77356de8bedb73b7f957df862234b8a0d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 23 May 2020 20:30:25 +0200 Subject: [PATCH 0576/1182] Cleanup --- httpie/client.py | 12 +++--------- httpie/ssl.py | 22 ++++++++++++++++++---- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index cd1ec417be..8a6e6f0520 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -9,6 +9,8 @@ from urllib.parse import urlparse, urlunparse import requests +# noinspection PyPackageRequirements +import urllib3 from httpie import __version__ from httpie.cli.dicts import RequestHeadersDict @@ -18,15 +20,7 @@ from httpie.utils import repr_dict -try: - # noinspection PyPackageRequirements - import urllib3 - - - # - urllib3.disable_warnings() -except (ImportError, AttributeError): - pass +urllib3.disable_warnings() FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8' JSON_CONTENT_TYPE = 'application/json' diff --git a/httpie/ssl.py b/httpie/ssl.py index 3390bb603e..8450438062 100644 --- a/httpie/ssl.py +++ b/httpie/ssl.py @@ -32,12 +32,11 @@ def __init__( ciphers: str = None, **kwargs ): - self._ssl_context = create_urllib3_context( + self._ssl_context = self._create_ssl_context( + verify=verify, + ssl_version=ssl_version, ciphers=ciphers, - ssl_version=resolve_ssl_version(ssl_version), - cert_reqs=ssl.CERT_REQUIRED if verify else ssl.CERT_NONE ) - super().__init__(**kwargs) def init_poolmanager(self, *args, **kwargs): @@ -47,3 +46,18 @@ def init_poolmanager(self, *args, **kwargs): def proxy_manager_for(self, *args, **kwargs): kwargs['ssl_context'] = self._ssl_context return super().proxy_manager_for(*args, **kwargs) + + @staticmethod + def _create_ssl_context( + verify: bool, + ssl_version: str = None, + ciphers: str = None, + ) -> ssl.SSLContext: + return create_urllib3_context( + ciphers=ciphers, + ssl_version=resolve_ssl_version(ssl_version), + # Since we are using a custom SSL context, we need to pass this + # here manually, even though it’s also passed to the connection + # in `super().cert_verify()`. + cert_reqs=ssl.CERT_REQUIRED if verify else ssl.CERT_NONE + ) From cd085cbc0d8ce5fd659ccc01996551dcfc149b13 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 26 May 2020 10:07:34 +0200 Subject: [PATCH 0577/1182] Refactor built-in plugin registry to avoid circular imports Fix #925 --- httpie/cli/argparser.py | 2 +- httpie/cli/definition.py | 2 +- httpie/client.py | 2 +- httpie/core.py | 3 ++- httpie/output/processing.py | 3 ++- httpie/plugins/__init__.py | 15 --------------- httpie/plugins/registry.py | 18 ++++++++++++++++++ httpie/sessions.py | 2 +- tests/test_auth_plugins.py | 4 +++- 9 files changed, 29 insertions(+), 22 deletions(-) create mode 100644 httpie/plugins/registry.py diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 835df376e1..87e6a1bf8c 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -18,7 +18,7 @@ from httpie.cli.exceptions import ParseError from httpie.cli.requestitems import RequestItems from httpie.context import Environment -from httpie.plugins import plugin_manager +from httpie.plugins.registry import plugin_manager from httpie.utils import ExplicitNullAuth, get_content_type diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index bcd8dbc520..23b59106bb 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -18,7 +18,7 @@ from httpie.output.formatters.colors import ( AUTO_STYLE, AVAILABLE_STYLES, DEFAULT_STYLE, ) -from httpie.plugins import plugin_manager +from httpie.plugins.registry import plugin_manager from httpie.plugins.builtin import BuiltinAuthPlugin from httpie.sessions import DEFAULT_SESSIONS_DIR from httpie.ssl import DEFAULT_SSL_CIPHERS, AVAILABLE_SSL_VERSION_ARG_MAPPING diff --git a/httpie/client.py b/httpie/client.py index 8a6e6f0520..71a95213c7 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -14,7 +14,7 @@ from httpie import __version__ from httpie.cli.dicts import RequestHeadersDict -from httpie.plugins import plugin_manager +from httpie.plugins.registry import plugin_manager from httpie.sessions import get_httpie_session from httpie.ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter from httpie.utils import repr_dict diff --git a/httpie/core.py b/httpie/core.py index 7c955e7e6f..4f85de75f9 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -13,10 +13,11 @@ from httpie.context import Environment from httpie.downloads import Downloader from httpie.output.writer import write_message, write_stream -from httpie.plugins import plugin_manager +from httpie.plugins.registry import plugin_manager from httpie.status import ExitStatus, http_status_to_exit_status +# noinspection PyDefaultArgument def main( args: List[Union[str, bytes]] = sys.argv, env=Environment(), diff --git a/httpie/output/processing.py b/httpie/output/processing.py index 9bee26217a..263bbc0e63 100644 --- a/httpie/output/processing.py +++ b/httpie/output/processing.py @@ -1,7 +1,8 @@ import re from typing import Optional, List -from httpie.plugins import plugin_manager, ConverterPlugin +from httpie.plugins import ConverterPlugin +from httpie.plugins.registry import plugin_manager from httpie.context import Environment diff --git a/httpie/plugins/__init__.py b/httpie/plugins/__init__.py index 38c2a66ccc..9386ca30cf 100644 --- a/httpie/plugins/__init__.py +++ b/httpie/plugins/__init__.py @@ -7,18 +7,3 @@ AuthPlugin, FormatterPlugin, ConverterPlugin, TransportPlugin ) -from httpie.plugins.manager import PluginManager -from httpie.plugins.builtin import BasicAuthPlugin, DigestAuthPlugin -from httpie.output.formatters.headers import HeadersFormatter -from httpie.output.formatters.json import JSONFormatter -from httpie.output.formatters.colors import ColorFormatter - - -plugin_manager = PluginManager() -plugin_manager.register( - BasicAuthPlugin, - DigestAuthPlugin, - HeadersFormatter, - JSONFormatter, - ColorFormatter, -) diff --git a/httpie/plugins/registry.py b/httpie/plugins/registry.py new file mode 100644 index 0000000000..aeb11280f3 --- /dev/null +++ b/httpie/plugins/registry.py @@ -0,0 +1,18 @@ +from httpie.plugins.manager import PluginManager +from httpie.plugins.builtin import BasicAuthPlugin, DigestAuthPlugin +from httpie.output.formatters.headers import HeadersFormatter +from httpie.output.formatters.json import JSONFormatter +from httpie.output.formatters.colors import ColorFormatter + + +plugin_manager = PluginManager() + + +# Register all built-in plugins. +plugin_manager.register( + BasicAuthPlugin, + DigestAuthPlugin, + HeadersFormatter, + JSONFormatter, + ColorFormatter, +) diff --git a/httpie/sessions.py b/httpie/sessions.py index 7ed7331e1e..948ce324f5 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -13,7 +13,7 @@ from httpie.cli.dicts import RequestHeadersDict from httpie.config import BaseConfigDict, DEFAULT_CONFIG_DIR -from httpie.plugins import plugin_manager +from httpie.plugins.registry import plugin_manager SESSIONS_DIR_NAME = 'sessions' diff --git a/tests/test_auth_plugins.py b/tests/test_auth_plugins.py index 434d7024b7..b21d813ed3 100644 --- a/tests/test_auth_plugins.py +++ b/tests/test_auth_plugins.py @@ -1,9 +1,11 @@ from mock import mock from httpie.cli.constants import SEPARATOR_CREDENTIALS -from httpie.plugins import AuthPlugin, plugin_manager +from httpie.plugins import AuthPlugin +from httpie.plugins.registry import plugin_manager from utils import http, HTTP_OK + # TODO: run all these tests in session mode as well USERNAME = 'user' From ca02e51420be547c38408040ee8ac9755c09c53f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 26 May 2020 10:07:53 +0200 Subject: [PATCH 0578/1182] Improve plugin API docs --- httpie/plugins/base.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index ff8dda0995..e1845f7972 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -3,7 +3,7 @@ class BasePlugin: # The name of the plugin, eg. "My auth". name = None - # Optional short description. Will be be shown in the help + # Optional short description. It will be shown in the help # under --auth-type. description = None @@ -15,7 +15,9 @@ class AuthPlugin(BasePlugin): """ Base auth plugin class. - See for an example auth plugin. + See httpie-ntlm for an example auth plugin: + + See also `test_auth_plugins.py` @@ -58,8 +60,13 @@ def get_auth(self, username=None, password=None): class TransportPlugin(BasePlugin): """ + Requests transport adapter docs: + + + + See httpie-unixsocket for an example transport plugin: - https://2.python-requests.org/en/latest/user/advanced/#transport-adapters + """ @@ -76,6 +83,14 @@ def get_adapter(self): class ConverterPlugin(BasePlugin): + """ + Possibly converts response data for prettified terminal display. + + See httpie-msgpack for an example converter plugin: + + . + + """ def __init__(self, mime): self.mime = mime @@ -89,13 +104,17 @@ def supports(cls, mime): class FormatterPlugin(BasePlugin): + """ + Possibly formats response body & headers for prettified terminal display. + + """ group_name = 'format' def __init__(self, **kwargs): """ :param env: an class:`Environment` instance :param kwargs: additional keyword argument that some - processor might require. + formatters might require. """ self.enabled = True From 493e98c8332c260006064fd3efa9dc42232b9737 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 26 May 2020 10:15:33 +0200 Subject: [PATCH 0579/1182] Update CHANGELOG --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d2023b4f22..59c61b8c69 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,7 @@ This project adheres to `Semantic Versioning `_. * Added support for ``--ciphers`` (`#870`_). * Added support for ``$XDG_CONFIG_HOME`` (`#920`_). +* Fixed built-in plugins-related circular imports (`#925`_). `2.1.0`_ (2020-04-18) @@ -437,3 +438,4 @@ This project adheres to `Semantic Versioning `_. .. _#870: https://github.com/jakubroztocil/httpie/issues/870 .. _#895: https://github.com/jakubroztocil/httpie/issues/895 .. _#920: https://github.com/jakubroztocil/httpie/issues/920 +.. _#925: https://github.com/jakubroztocil/httpie/issues/925 From c2a0cef76e0613de028d5ff982bd862206439a0f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 27 May 2020 15:58:15 +0200 Subject: [PATCH 0580/1182] Add --format-options to allow disabling sorting, etc. #128 --- CHANGELOG.rst | 4 +- README.rst | 14 ++++ httpie/cli/argtypes.py | 67 +++++++++++++++++- httpie/cli/constants.py | 9 +++ httpie/cli/definition.py | 44 ++++++++++-- httpie/output/formatters/headers.py | 4 ++ httpie/output/formatters/json.py | 11 +-- httpie/output/writer.py | 1 + httpie/plugins/base.py | 1 + setup.cfg | 1 + tests/test_output.py | 102 ++++++++++++++++++++++++---- 11 files changed, 231 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 59c61b8c69..a68baa71ff 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,7 +9,8 @@ This project adheres to `Semantic Versioning `_. `2.2.0-dev`_ (unreleased) ------------------------- -* Added support for ``--ciphers`` (`#870`_). +* Added ``--format-options`` to allow disabling sorting, etc. (`#128`_) +* Added ``--ciphers`` to allow configuring OpenSSL ciphers (`#870`_). * Added support for ``$XDG_CONFIG_HOME`` (`#920`_). * Fixed built-in plugins-related circular imports (`#925`_). @@ -433,6 +434,7 @@ This project adheres to `Semantic Versioning `_. .. _2.2.0-dev: https://github.com/jakubroztocil/httpie/compare/2.1.0...master +.. _#128: https://github.com/jakubroztocil/httpie/issues/128 .. _#488: https://github.com/jakubroztocil/httpie/issues/488 .. _#840: https://github.com/jakubroztocil/httpie/issues/840 .. _#870: https://github.com/jakubroztocil/httpie/issues/870 diff --git a/README.rst b/README.rst index 865352b16e..572b1c4286 100644 --- a/README.rst +++ b/README.rst @@ -1395,6 +1395,20 @@ One of these options can be used to control output processing: Default for redirected output. ==================== ======================================================== + +You can control the applied formatting via the ``--format-options`` option. +For example, this is how you would disable the default header and JSON key +sorting, and specify a custom JSON indent size: + + +.. code-block:: bash + + $ http --format-options headers.sort=false,json.sort_keys=false,json.indent=2 httpbin.org/get + +This is something you will typically store as one of the default options in your +`config`_ file. See ``http --help`` for all the available formatting options. + + Binary data ----------- diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index 20e83897c9..b3c4716993 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -2,9 +2,10 @@ import getpass import os import sys -from typing import Union, List, Optional +from copy import deepcopy +from typing import List, Optional, Union -from httpie.cli.constants import SEPARATOR_CREDENTIALS +from httpie.cli.constants import DEFAULT_FORMAT_OPTIONS, SEPARATOR_CREDENTIALS from httpie.sessions import VALID_SESSION_NAME_PATTERN @@ -181,3 +182,65 @@ def readable_file_arg(filename): return filename except IOError as ex: raise argparse.ArgumentTypeError(f'{filename}: {ex.args[1]}') + + + +def parse_format_options(s: str, defaults: Optional[dict]) -> dict: + """ + Parse `s` and update `defaults` with the parsed values. + + >>> parse_format_options( + ... defaults={'json': {'indent': 4, 'sort_keys': True}}, + ... s='json.indent=2,json.sort_keys=False', + ... ) + {'json': {'indent': 2, 'sort_keys': False}} + + """ + value_map = { + 'true': True, + 'false': False, + } + options = deepcopy(defaults or {}) + for option in s.split(','): + try: + path, value = option.lower().split('=') + section, key = path.split('.') + except ValueError: + raise argparse.ArgumentTypeError( + f'--format-options: invalid option: {option!r}') + + if value in value_map: + parsed_value = value_map[value] + else: + if value.isnumeric(): + parsed_value = int(value) + else: + parsed_value = value + + if defaults is None: + options.setdefault(section, {}) + else: + try: + default_value = defaults[section][key] + except KeyError: + raise argparse.ArgumentTypeError( + f'--format-options: invalid key: {path!r} in {option!r}') + + default_type, parsed_type = type(default_value), type(parsed_value) + if parsed_type is not default_type: + raise argparse.ArgumentTypeError( + '--format-options: invalid value type:' + f' {value!r} in {option!r}' + f' (expected {default_type.__name__}' + f' got {parsed_type.__name__})' + ) + + options[section][key] = parsed_value + + return options + + +PARSED_DEFAULT_FORMAT_OPTIONS = parse_format_options( + s=','.join(DEFAULT_FORMAT_OPTIONS), + defaults=None, +) diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index 5865d5c5dd..c8d7b7c835 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -83,6 +83,15 @@ } PRETTY_STDOUT_TTY_ONLY = object() + +DEFAULT_FORMAT_OPTIONS = [ + 'headers.sort=true', + 'json.format=true', + 'json.indent=4', + 'json.sort_keys=true', +] + + # Defaults OUTPUT_OPTIONS_DEFAULT = OUT_RESP_HEAD + OUT_RESP_BODY OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED = OUT_RESP_BODY diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 23b59106bb..9adffc5766 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -8,20 +8,23 @@ from httpie import __doc__, __version__ from httpie.cli.argparser import HTTPieArgumentParser from httpie.cli.argtypes import ( - KeyValueArgType, SessionNameValidator, readable_file_arg, + KeyValueArgType, PARSED_DEFAULT_FORMAT_OPTIONS, SessionNameValidator, + parse_format_options, + readable_file_arg, ) from httpie.cli.constants import ( - OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, OUT_REQ_BODY, OUT_REQ_HEAD, + DEFAULT_FORMAT_OPTIONS, OUTPUT_OPTIONS, + OUTPUT_OPTIONS_DEFAULT, OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_BODY, OUT_RESP_HEAD, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY, ) from httpie.output.formatters.colors import ( AUTO_STYLE, AVAILABLE_STYLES, DEFAULT_STYLE, ) -from httpie.plugins.registry import plugin_manager from httpie.plugins.builtin import BuiltinAuthPlugin +from httpie.plugins.registry import plugin_manager from httpie.sessions import DEFAULT_SESSIONS_DIR -from httpie.ssl import DEFAULT_SSL_CIPHERS, AVAILABLE_SSL_VERSION_ARG_MAPPING +from httpie.ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS parser = HTTPieArgumentParser( @@ -206,9 +209,9 @@ default=DEFAULT_STYLE, choices=AVAILABLE_STYLES, help=""" - Output coloring style (default is "{default}"). One of: + Output coloring style (default is "{default}"). It can be One of: -{available_styles} + {available_styles} The "{auto_style}" style follows your terminal's ANSI color styles. @@ -221,11 +224,38 @@ available_styles='\n'.join( '{0}{1}'.format(8 * ' ', line.strip()) for line in wrap(', '.join(sorted(AVAILABLE_STYLES)), 60) - ).rstrip(), + ).strip(), auto_style=AUTO_STYLE, ) ) +output_processing.add_argument( + '--format-options', + type=lambda s: parse_format_options( + s=s, + defaults=PARSED_DEFAULT_FORMAT_OPTIONS + ), + default=PARSED_DEFAULT_FORMAT_OPTIONS, + help=""" + Controls output formatting. Only relevant when formatting is enabled + through (explicit or implied) --pretty=all or --pretty=format. + The following are the default options: + + {option_list} + + You can specify multiple comma-separated options. For example, this modifies + the settings to disable the sorting of JSON keys and headers: + + --format-options json.sort_keys=false,headers.sort=false + + This is something you will typically put into your config file. + + """.format( + option_list='\n'.join( + (8 * ' ') + option for option in DEFAULT_FORMAT_OPTIONS).strip() + ) +) + ####################################################################### # Output options ####################################################################### diff --git a/httpie/output/formatters/headers.py b/httpie/output/formatters/headers.py index 486f09f6e2..76b82c45ce 100644 --- a/httpie/output/formatters/headers.py +++ b/httpie/output/formatters/headers.py @@ -3,6 +3,10 @@ class HeadersFormatter(FormatterPlugin): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.enabled = self.format_options['headers']['sort'] + def format_headers(self, headers: str) -> str: """ Sorts headers by name while retaining relative diff --git a/httpie/output/formatters/json.py b/httpie/output/formatters/json.py index d2eb52d362..3cfb9334b5 100644 --- a/httpie/output/formatters/json.py +++ b/httpie/output/formatters/json.py @@ -4,11 +4,12 @@ from httpie.plugins import FormatterPlugin -DEFAULT_INDENT = 4 - - class JSONFormatter(FormatterPlugin): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.enabled = self.format_options['json']['format'] + def format_body(self, body: str, mime: str) -> str: maybe_json = [ 'json', @@ -26,8 +27,8 @@ def format_body(self, body: str, mime: str) -> str: # unicode escapes to improve readability. body = json.dumps( obj=obj, - sort_keys=True, + sort_keys=self.format_options['json']['sort_keys'], ensure_ascii=False, - indent=DEFAULT_INDENT + indent=self.format_options['json']['indent'] ) return body diff --git a/httpie/output/writer.py b/httpie/output/writer.py index b9e219f97a..ee5acf4893 100644 --- a/httpie/output/writer.py +++ b/httpie/output/writer.py @@ -152,6 +152,7 @@ def get_stream_type_and_kwargs( groups=args.prettify, color_scheme=args.style, explicit_json=args.json, + format_options=args.format_options, ) } else: diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index e1845f7972..80835da05c 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -119,6 +119,7 @@ def __init__(self, **kwargs): """ self.enabled = True self.kwargs = kwargs + self.format_options = kwargs['format_options'] def format_headers(self, headers: str) -> str: """Return processed `headers` diff --git a/setup.cfg b/setup.cfg index 2b20304218..7ae337612a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,7 @@ [tool:pytest] # norecursedirs = tests/fixtures +addopts = --tb=native [pycodestyle] diff --git a/tests/test_output.py b/tests/test_output.py index cbbf8b7325..3dcbf161bb 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -1,12 +1,15 @@ +import argparse +import json import os from tempfile import gettempdir from urllib.request import urlopen import pytest -from utils import MockEnvironment, http, HTTP_OK, COLOR, CRLF -from httpie.status import ExitStatus +from httpie.cli.argtypes import parse_format_options from httpie.output.formatters.colors import get_lexer +from httpie.status import ExitStatus +from utils import COLOR, CRLF, HTTP_OK, MockEnvironment, http @pytest.mark.parametrize('stdout_isatty', [True, False]) @@ -58,19 +61,19 @@ class TestColors: @pytest.mark.parametrize( argnames=['mime', 'explicit_json', 'body', 'expected_lexer_name'], argvalues=[ - ('application/json', False, None, 'JSON'), + ('application/json', False, None, 'JSON'), ('application/json+foo', False, None, 'JSON'), ('application/foo+json', False, None, 'JSON'), ('application/json-foo', False, None, 'JSON'), - ('application/x-json', False, None, 'JSON'), - ('foo/json', False, None, 'JSON'), - ('foo/json+bar', False, None, 'JSON'), - ('foo/bar+json', False, None, 'JSON'), - ('foo/json-foo', False, None, 'JSON'), - ('foo/x-json', False, None, 'JSON'), + ('application/x-json', False, None, 'JSON'), + ('foo/json', False, None, 'JSON'), + ('foo/json+bar', False, None, 'JSON'), + ('foo/bar+json', False, None, 'JSON'), + ('foo/json-foo', False, None, 'JSON'), + ('foo/x-json', False, None, 'JSON'), ('application/vnd.comverge.grid+hal+json', False, None, 'JSON'), - ('text/plain', True, '{}', 'JSON'), - ('text/plain', True, 'foo', 'Text only'), + ('text/plain', True, '{}', 'JSON'), + ('text/plain', True, 'foo', 'Text only'), ] ) def test_get_lexer(self, mime, explicit_json, body, expected_lexer_name): @@ -83,7 +86,7 @@ def test_get_lexer_not_found(self): class TestPrettyOptions: - """Test the --pretty flag handling.""" + """Test the --pretty handling.""" def test_pretty_enabled_by_default(self, httpbin): env = MockEnvironment(colors=256) @@ -138,6 +141,7 @@ class TestLineEndings: and as the headers/body separator. """ + def _validate_crlf(self, msg): lines = iter(msg.splitlines(True)) for header in lines: @@ -171,3 +175,77 @@ def test_CRLF_ugly_request(self, httpbin): def test_CRLF_formatted_request(self, httpbin): r = http('--pretty=format', '--print=HB', 'GET', httpbin.url + '/get') self._validate_crlf(r) + + +class TestFormatOptions: + def test_header_formatting_options(self): + def get_headers(sort): + return http( + '--offline', '--print=H', + '--format-options', 'headers.sort=' + sort, + 'example.org', 'ZZZ:foo', 'XXX:foo', + ) + + r_sorted = get_headers('true') + r_unsorted = get_headers('false') + assert r_sorted != r_unsorted + assert f'XXX: foo{CRLF}ZZZ: foo' in r_sorted + assert f'ZZZ: foo{CRLF}XXX: foo' in r_unsorted + + @pytest.mark.parametrize( + argnames=['options', 'expected_json'], + argvalues=[ + # @formatter:off + ( + 'json.sort_keys=true,json.indent=4', + json.dumps({'a': 0, 'b': 0}, indent=4), + ), + ( + 'json.sort_keys=false,json.indent=2', + json.dumps({'b': 0, 'a': 0}, indent=2), + ), + ( + 'json.format=false', + json.dumps({'b': 0, 'a': 0}), + ), + # @formatter:on + ] + ) + def test_json_formatting_options(self, options: str, expected_json: str): + r = http( + '--offline', '--print=B', + '--format-options', options, + 'example.org', 'b:=0', 'a:=0', + ) + assert expected_json in r + + @pytest.mark.parametrize( + argnames=['defaults', 'options_string', 'expected'], + argvalues=[ + # @formatter:off + ({'foo': {'bar': 1}}, 'foo.bar=2', {'foo': {'bar': 2}}), + ({'foo': {'bar': True}}, 'foo.bar=false', {'foo': {'bar': False}}), + ({'foo': {'bar': 'a'}}, 'foo.bar=b', {'foo': {'bar': 'b'}}), + # @formatter:on + ] + ) + def test_parse_format_options(self, defaults, options_string, expected): + actual = parse_format_options(s=options_string, defaults=defaults) + assert expected == actual + + @pytest.mark.parametrize( + argnames=['options_string', 'expected_error'], + argvalues=[ + ('foo=2', 'invalid option'), + ('foo.baz=2', 'invalid key'), + ('foo.bar=false', 'expected int got bool'), + ] + ) + def test_parse_format_options_errors(self, options_string, expected_error): + defaults = { + 'foo': { + 'bar': 1 + } + } + with pytest.raises(argparse.ArgumentTypeError, match=expected_error): + parse_format_options(s=options_string, defaults=defaults) From cb51faec518d9dd634654e534cc5d473a07af1f6 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 27 May 2020 16:12:31 +0200 Subject: [PATCH 0581/1182] pep8 --- httpie/cli/argtypes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index b3c4716993..21d4402275 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -184,7 +184,6 @@ def readable_file_arg(filename): raise argparse.ArgumentTypeError(f'{filename}: {ex.args[1]}') - def parse_format_options(s: str, defaults: Optional[dict]) -> dict: """ Parse `s` and update `defaults` with the parsed values. From aae596d4724b39d3ad0da0ef4d6a5e7eb98ae418 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 27 May 2020 16:19:32 +0200 Subject: [PATCH 0582/1182] Improve --format-options error messages --- httpie/cli/argtypes.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index 21d4402275..3c967cbffe 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -205,8 +205,7 @@ def parse_format_options(s: str, defaults: Optional[dict]) -> dict: path, value = option.lower().split('=') section, key = path.split('.') except ValueError: - raise argparse.ArgumentTypeError( - f'--format-options: invalid option: {option!r}') + raise argparse.ArgumentTypeError(f'invalid option {option!r}') if value in value_map: parsed_value = value_map[value] @@ -223,12 +222,12 @@ def parse_format_options(s: str, defaults: Optional[dict]) -> dict: default_value = defaults[section][key] except KeyError: raise argparse.ArgumentTypeError( - f'--format-options: invalid key: {path!r} in {option!r}') + f'invalid key {path!r}') default_type, parsed_type = type(default_value), type(parsed_value) if parsed_type is not default_type: raise argparse.ArgumentTypeError( - '--format-options: invalid value type:' + 'invalid value' f' {value!r} in {option!r}' f' (expected {default_type.__name__}' f' got {parsed_type.__name__})' From caeef2fb7c69c21f4a3ca4c59082c3f81b0fc9bf Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 28 May 2020 12:26:06 +0200 Subject: [PATCH 0583/1182] Use `:` instead of `=` in ``--format-options` --- README.rst | 2 +- httpie/cli/argtypes.py | 4 ++-- httpie/cli/constants.py | 8 ++++---- httpie/cli/definition.py | 2 +- tests/test_output.py | 20 ++++++++++---------- tests/utils.py | 1 + 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/README.rst b/README.rst index 572b1c4286..e7112a7c94 100644 --- a/README.rst +++ b/README.rst @@ -1403,7 +1403,7 @@ sorting, and specify a custom JSON indent size: .. code-block:: bash - $ http --format-options headers.sort=false,json.sort_keys=false,json.indent=2 httpbin.org/get + $ http --format-options headers.sort:false,json.sort_keys:false,json.indent:2 httpbin.org/get This is something you will typically store as one of the default options in your `config`_ file. See ``http --help`` for all the available formatting options. diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index 3c967cbffe..0d4f9eb244 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -190,7 +190,7 @@ def parse_format_options(s: str, defaults: Optional[dict]) -> dict: >>> parse_format_options( ... defaults={'json': {'indent': 4, 'sort_keys': True}}, - ... s='json.indent=2,json.sort_keys=False', + ... s='json.indent:2,json.sort_keys:False', ... ) {'json': {'indent': 2, 'sort_keys': False}} @@ -202,7 +202,7 @@ def parse_format_options(s: str, defaults: Optional[dict]) -> dict: options = deepcopy(defaults or {}) for option in s.split(','): try: - path, value = option.lower().split('=') + path, value = option.lower().split(':') section, key = path.split('.') except ValueError: raise argparse.ArgumentTypeError(f'invalid option {option!r}') diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index c8d7b7c835..27d0eb259e 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -85,10 +85,10 @@ DEFAULT_FORMAT_OPTIONS = [ - 'headers.sort=true', - 'json.format=true', - 'json.indent=4', - 'json.sort_keys=true', + 'headers.sort:true', + 'json.format:true', + 'json.indent:4', + 'json.sort_keys:true', ] diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 9adffc5766..2d429260c8 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -246,7 +246,7 @@ You can specify multiple comma-separated options. For example, this modifies the settings to disable the sorting of JSON keys and headers: - --format-options json.sort_keys=false,headers.sort=false + --format-options json.sort_keys:false,headers.sort:false This is something you will typically put into your config file. diff --git a/tests/test_output.py b/tests/test_output.py index 3dcbf161bb..e0438c10f2 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -182,7 +182,7 @@ def test_header_formatting_options(self): def get_headers(sort): return http( '--offline', '--print=H', - '--format-options', 'headers.sort=' + sort, + '--format-options', 'headers.sort:' + sort, 'example.org', 'ZZZ:foo', 'XXX:foo', ) @@ -197,15 +197,15 @@ def get_headers(sort): argvalues=[ # @formatter:off ( - 'json.sort_keys=true,json.indent=4', + 'json.sort_keys:true,json.indent:4', json.dumps({'a': 0, 'b': 0}, indent=4), ), ( - 'json.sort_keys=false,json.indent=2', + 'json.sort_keys:false,json.indent:2', json.dumps({'b': 0, 'a': 0}, indent=2), ), ( - 'json.format=false', + 'json.format:false', json.dumps({'b': 0, 'a': 0}), ), # @formatter:on @@ -223,9 +223,9 @@ def test_json_formatting_options(self, options: str, expected_json: str): argnames=['defaults', 'options_string', 'expected'], argvalues=[ # @formatter:off - ({'foo': {'bar': 1}}, 'foo.bar=2', {'foo': {'bar': 2}}), - ({'foo': {'bar': True}}, 'foo.bar=false', {'foo': {'bar': False}}), - ({'foo': {'bar': 'a'}}, 'foo.bar=b', {'foo': {'bar': 'b'}}), + ({'foo': {'bar': 1}}, 'foo.bar:2', {'foo': {'bar': 2}}), + ({'foo': {'bar': True}}, 'foo.bar:false', {'foo': {'bar': False}}), + ({'foo': {'bar': 'a'}}, 'foo.bar:b', {'foo': {'bar': 'b'}}), # @formatter:on ] ) @@ -236,9 +236,9 @@ def test_parse_format_options(self, defaults, options_string, expected): @pytest.mark.parametrize( argnames=['options_string', 'expected_error'], argvalues=[ - ('foo=2', 'invalid option'), - ('foo.baz=2', 'invalid key'), - ('foo.bar=false', 'expected int got bool'), + ('foo:2', 'invalid option'), + ('foo.baz:2', 'invalid key'), + ('foo.bar:false', 'expected int got bool'), ] ) def test_parse_format_options_errors(self, options_string, expected_error): diff --git a/tests/utils.py b/tests/utils.py index 690765af5b..03c948c313 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -216,6 +216,7 @@ def http( add_to_args.append('--timeout=3') complete_args = [program_name, *add_to_args, *args] + # print(' '.join(complete_args)) def dump_stderr(): stderr.seek(0) From 492687b0dafb7bec0d6281d019bb5f4f60439346 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 28 May 2020 14:30:56 +0200 Subject: [PATCH 0584/1182] Add stable docs link icon --- README.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e7112a7c94..b287c9e2c5 100644 --- a/README.rst +++ b/README.rst @@ -11,7 +11,7 @@ generally interacting with HTTP servers. .. class:: no-web no-pdf - |pypi| |build| |coverage| |downloads| |gitter| + |docs| |pypi| |build| |coverage| |downloads| |gitter| .. class:: no-web no-pdf @@ -1996,6 +1996,10 @@ have contributed. .. _@jakubroztocil: https://twitter.com/jakubroztocil +.. |docs| image:: https://img.shields.io/badge/stable%20docs-httpie.org%2Fdocs-brightgreen?style=flat-square + :target: https://httpie.org/docs + :alt: Stable documentation + .. |pypi| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square&label=latest%20stable%20version :target: https://pypi.python.org/pypi/httpie :alt: Latest version released on PyPi From c4627cc882d11bf26b52baee4bfdbf9edd3d09ed Mon Sep 17 00:00:00 2001 From: Carlo Sciolla Date: Mon, 8 Jun 2020 17:59:41 +0200 Subject: [PATCH 0585/1182] Custom file upload MIME type (#927) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Support curl-like syntax for custom MIME type for files In order to specify a custom MIME type for file uploads, a syntax similar to that used by cURL is used so that http -F test_file@/path/to/file.bin;type=application/zip https://... forwards the user-provided file type if provided, otherwise falling back to the usual guesswork out of the file extension. --- CHANGELOG.rst | 2 ++ README.rst | 7 +++++++ httpie/cli/constants.py | 1 + httpie/cli/definition.py | 1 + httpie/cli/requestitems.py | 10 +++++++--- tests/test_uploads.py | 20 +++++++++++++++----- 6 files changed, 33 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a68baa71ff..c5927c4073 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,6 +13,7 @@ This project adheres to `Semantic Versioning `_. * Added ``--ciphers`` to allow configuring OpenSSL ciphers (`#870`_). * Added support for ``$XDG_CONFIG_HOME`` (`#920`_). * Fixed built-in plugins-related circular imports (`#925`_). +* Fixed custom content types for each multipart uploaded file (`#668`_). `2.1.0`_ (2020-04-18) @@ -441,3 +442,4 @@ This project adheres to `Semantic Versioning `_. .. _#895: https://github.com/jakubroztocil/httpie/issues/895 .. _#920: https://github.com/jakubroztocil/httpie/issues/920 .. _#925: https://github.com/jakubroztocil/httpie/issues/925 +.. _#668: https://github.com/jakubroztocil/httpie/issues/668 diff --git a/README.rst b/README.rst index b287c9e2c5..2168855200 100644 --- a/README.rst +++ b/README.rst @@ -683,6 +683,13 @@ submitted: Note that ``@`` is used to simulate a file upload form field, whereas ``=@`` just embeds the file content as a regular text field value. +When uploading files, their content type is inferred from the file name. You can manually +override the inferred content type: + +.. code-block:: bash + + $ http -f POST httpbin.org/post name='John Smith' cv@'~/files/data.bin;type=application/pdf' + HTTP headers ============ diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index 27d0eb259e..ea8036fe24 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -24,6 +24,7 @@ SEPARATOR_DATA_STRING = '=' SEPARATOR_DATA_RAW_JSON = ':=' SEPARATOR_FILE_UPLOAD = '@' +SEPARATOR_FILE_UPLOAD_TYPE = ';type=' # in already parsed file upload path only SEPARATOR_DATA_EMBED_FILE_CONTENTS = '=@' SEPARATOR_DATA_EMBED_RAW_JSON_FILE = ':=@' SEPARATOR_QUERY_PARAM = '==' diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 2d429260c8..93fef94e86 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -113,6 +113,7 @@ '@' Form file fields (only with --form, -f): cs@~/Documents/CV.pdf + cv@'~/Documents/CV.pdf;type=application/pdf' '=@' A data field like '=', but takes a file path and embeds its content: diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index ec8e6c1ef1..a812d65174 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -6,7 +6,8 @@ from httpie.cli.constants import ( SEPARATOR_DATA_EMBED_FILE_CONTENTS, SEPARATOR_DATA_EMBED_RAW_JSON_FILE, SEPARATOR_DATA_RAW_JSON, SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD, - SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY, SEPARATOR_QUERY_PARAM, + SEPARATOR_FILE_UPLOAD_TYPE, SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY, + SEPARATOR_QUERY_PARAM, ) from httpie.cli.dicts import ( RequestDataDict, RequestFilesDict, RequestHeadersDict, RequestJSONDataDict, @@ -95,7 +96,10 @@ def process_query_param_arg(arg: KeyValueArg) -> str: def process_file_upload_arg(arg: KeyValueArg) -> Tuple[str, IO, str]: - filename = arg.value + parts = arg.value.split(SEPARATOR_FILE_UPLOAD_TYPE) + filename = parts[0] + mime_type = parts[1] if len(parts) > 1 else None + try: with open(os.path.expanduser(filename), 'rb') as f: contents = f.read() @@ -104,7 +108,7 @@ def process_file_upload_arg(arg: KeyValueArg) -> Tuple[str, IO, str]: return ( os.path.basename(filename), BytesIO(contents), - get_content_type(filename), + mime_type or get_content_type(filename), ) diff --git a/tests/test_uploads.py b/tests/test_uploads.py index b0c7fc5d5a..d2bab00658 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -17,27 +17,37 @@ def test_non_existent_file_raises_parse_error(self, httpbin): def test_upload_ok(self, httpbin): r = http('--form', '--verbose', 'POST', httpbin.url + '/post', - 'test-file@%s' % FILE_PATH_ARG, 'foo=bar') + f'test-file@{FILE_PATH_ARG}', 'foo=bar') assert HTTP_OK in r assert 'Content-Disposition: form-data; name="foo"' in r assert 'Content-Disposition: form-data; name="test-file";' \ - ' filename="%s"' % os.path.basename(FILE_PATH) in r + f' filename="{os.path.basename(FILE_PATH)}"' in r assert FILE_CONTENT in r assert '"foo": "bar"' in r assert 'Content-Type: text/plain' in r def test_upload_multiple_fields_with_the_same_name(self, httpbin): r = http('--form', '--verbose', 'POST', httpbin.url + '/post', - 'test-file@%s' % FILE_PATH_ARG, - 'test-file@%s' % FILE_PATH_ARG) + f'test-file@{FILE_PATH_ARG}', + f'test-file@{FILE_PATH_ARG}') assert HTTP_OK in r assert r.count('Content-Disposition: form-data; name="test-file";' - ' filename="%s"' % os.path.basename(FILE_PATH)) == 2 + f' filename="{os.path.basename(FILE_PATH)}"') == 2 # Should be 4, but is 3 because httpbin # doesn't seem to support filed field lists assert r.count(FILE_CONTENT) in [3, 4] assert r.count('Content-Type: text/plain') == 2 + def test_upload_custom_content_type(self, httpbin): + r = http('--form', '--verbose', 'POST', httpbin.url + '/post', + f'test-file@{FILE_PATH_ARG};type=image/vnd.microsoft.icon') + assert HTTP_OK in r + # Content type is stripped from the filename + assert 'Content-Disposition: form-data; name="test-file";' \ + f' filename="{os.path.basename(FILE_PATH)}"' in r + assert FILE_CONTENT in r + assert 'Content-Type: image/vnd.microsoft.icon' in r + class TestRequestBodyFromFilePath: """ From 7ee519ef46ed0a4280f431d0c14745ed8244621f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 8 Jun 2020 18:02:04 +0200 Subject: [PATCH 0586/1182] Update CHANGELOG --- CHANGELOG.rst | 4 ++-- httpie/cli/definition.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c5927c4073..46dd453b29 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,11 +9,11 @@ This project adheres to `Semantic Versioning `_. `2.2.0-dev`_ (unreleased) ------------------------- +* Fixed built-in plugins-related circular imports (`#925`_). * Added ``--format-options`` to allow disabling sorting, etc. (`#128`_) * Added ``--ciphers`` to allow configuring OpenSSL ciphers (`#870`_). * Added support for ``$XDG_CONFIG_HOME`` (`#920`_). -* Fixed built-in plugins-related circular imports (`#925`_). -* Fixed custom content types for each multipart uploaded file (`#668`_). +* Added support for custom content types for uploaded files (`#668`_). `2.1.0`_ (2020-04-18) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 93fef94e86..b3b5f3887c 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -112,7 +112,7 @@ '@' Form file fields (only with --form, -f): - cs@~/Documents/CV.pdf + cv@~/Documents/CV.pdf cv@'~/Documents/CV.pdf;type=application/pdf' '=@' A data field like '=', but takes a file path and embeds its content: From 9c68d7dd8721705be257791dc1a3c36dc31dbc8b Mon Sep 17 00:00:00 2001 From: Eyitayo Ogunbiyi Date: Mon, 15 Jun 2020 21:28:04 +0100 Subject: [PATCH 0587/1182] Remove expired cookies (#929) * added a test for expiring cookies * updated tests * set up util for extracting expired cookies from response header * Revert "updated tests" This reverts commit a4eb5c4498d24816c971578216d351d892293549. * Revert "Revert "updated tests"" This reverts commit d242e21bce8101dab03fa52810bc5d2789c9307e. * added more functionality to get-expired-cookies * add 'clear expired cookies' from session.json files * refactored get_expired_cookies * fixed formatting issues * ensured key exists in cookie_header dict * fixed linting errors * removed unused import * Added tests for get_expired_cookies util * Added additional test for get_expired_cookies * added remove_expired_cookies method directly to sessions class * extracted logic to clear cookies to sessions.py * refactored utils * added tests to check expired cookies being removed from session obj * added type annotations for methods * Refactored test_sessions * Seperated out expiry related tests into own class * Refactored get_expired_cookies in utils * Refactored remove cookie methods * fixed linting errors * fixed indentation and also pluralized test class name * removed inheritance from SessionTestbase class * Moved related test to TestExpiredCookies class Co-authored-by: kbanc --- httpie/client.py | 12 +++++- httpie/sessions.py | 9 +++- httpie/utils.py | 28 ++++++++++++ tests/test_sessions.py | 97 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 140 insertions(+), 6 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 71a95213c7..65f88e43eb 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -11,14 +11,14 @@ import requests # noinspection PyPackageRequirements import urllib3 +from requests.cookies import remove_cookie_by_name from httpie import __version__ from httpie.cli.dicts import RequestHeadersDict from httpie.plugins.registry import plugin_manager from httpie.sessions import get_httpie_session from httpie.ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter -from httpie.utils import repr_dict - +from httpie.utils import get_expired_cookies, repr_dict urllib3.disable_warnings() @@ -82,6 +82,7 @@ def collect_messages( if args.compress and prepared_request.body: compress_body(prepared_request, always=args.compress > 1) response_count = 0 + expired_cookies = [] while prepared_request: yield prepared_request if not args.offline: @@ -95,6 +96,10 @@ def collect_messages( **send_kwargs_merged, **send_kwargs, ) + expired_cookies += get_expired_cookies( + headers=response.raw._original_response.msg._headers + ) + response_count += 1 if response.next: if args.max_redirects and response_count == args.max_redirects: @@ -110,6 +115,9 @@ def collect_messages( if httpie_session: if httpie_session.is_new() or not args.session_read_only: httpie_session.cookies = requests_session.cookies + httpie_session.remove_cookies( + cookie['name'] for cookie in expired_cookies + ) httpie_session.save() diff --git a/httpie/sessions.py b/httpie/sessions.py index 948ce324f5..5750f3de46 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -5,11 +5,11 @@ import os import re from pathlib import Path -from typing import Optional, Union +from typing import Iterable, Optional, Union from urllib.parse import urlsplit from requests.auth import AuthBase -from requests.cookies import RequestsCookieJar, create_cookie +from requests.cookies import RequestsCookieJar, create_cookie, remove_cookie_by_name from httpie.cli.dicts import RequestHeadersDict from httpie.config import BaseConfigDict, DEFAULT_CONFIG_DIR @@ -144,3 +144,8 @@ def auth(self) -> Optional[AuthBase]: def auth(self, auth: dict): assert {'type', 'raw_auth'} == auth.keys() self['auth'] = auth + + def remove_cookies(self, names: Iterable[str]): + for name in names: + if name in self['cookies']: + del self['cookies'][name] diff --git a/httpie/utils.py b/httpie/utils.py index c5b60216b2..d47f3531c7 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -1,8 +1,12 @@ from __future__ import division + import json import mimetypes +import time from collections import OrderedDict +from http.cookiejar import parse_ns_headers from pprint import pformat +from typing import List, Tuple import requests.auth @@ -83,3 +87,27 @@ def get_content_type(filename): if encoding: content_type = '%s; charset=%s' % (mime, encoding) return content_type + + +def get_expired_cookies(headers: List[Tuple[str, str]], curr_timestamp: float = None) -> List[dict]: + expired_cookies = [] + cookie_headers = [] + curr_timestamp = curr_timestamp or time.time() + + for header_name, content in headers: + if header_name == 'Set-Cookie': + cookie_headers.append(content) + + extracted_cookies = [ + dict(cookie, name=cookie[0][0]) + for cookie in parse_ns_headers(cookie_headers) + ] + + for cookie in extracted_cookies: + if "expires" in cookie and cookie['expires'] <= curr_timestamp: + expired_cookies.append({ + 'name': cookie['name'], + 'path': cookie.get('path', '/') + }) + + return expired_cookies diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 3b7c7ed5f6..b547431036 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -1,14 +1,17 @@ # coding=utf-8 +import json import os import shutil -import sys +from datetime import datetime from tempfile import gettempdir import pytest +from fixtures import UNICODE from httpie.plugins.builtin import HTTPBasicAuth +from httpie.sessions import Session +from httpie.utils import get_expired_cookies from utils import MockEnvironment, mk_config_dir, http, HTTP_OK -from fixtures import UNICODE class SessionTestBase: @@ -186,3 +189,93 @@ def test_download_in_session(self, httpbin): httpbin.url + '/get', env=self.env()) finally: os.chdir(cwd) + + +class TestExpiredCookies: + + @pytest.mark.parametrize( + argnames=['initial_cookie', 'expired_cookie'], + argvalues=[ + ({'id': {'value': 123}}, 'id'), + ({'id': {'value': 123}}, 'token') + ] + ) + def test_removes_expired_cookies_from_session_obj(self, initial_cookie, expired_cookie, httpbin): + config_dir = mk_config_dir() + session = Session(config_dir) + session['cookies'] = initial_cookie + session.remove_cookies([expired_cookie]) + assert expired_cookie not in session.cookies + + shutil.rmtree(config_dir) + + def test_expired_cookies(self, httpbin): + orig_session = { + 'cookies': { + 'to_expire': { + 'value': 'foo' + }, + 'to_stay': { + 'value': 'foo' + }, + } + } + config_dir = mk_config_dir() + session_path = config_dir / 'test-session.json' + session_path.write_text(json.dumps(orig_session)) + + r = http( + '--session', str(session_path), + '--print=H', + httpbin.url + '/cookies/delete?to_expire', + ) + assert 'Cookie: to_expire=foo; to_stay=foo' in r + + updated_session = json.loads(session_path.read_text()) + assert 'to_stay' in updated_session['cookies'] + assert 'to_expire' not in updated_session['cookies'] + + shutil.rmtree(config_dir) + + @pytest.mark.parametrize( + argnames=['raw_header', 'timestamp', 'expected'], + argvalues=[ + ( + [ + ('Set-Cookie', 'hello=world; Path=/; Expires=Thu, 01-Jan-1970 00:00:00 GMT; HttpOnly'), + ('Connection', 'keep-alive') + ], + None, + [ + { + 'name': 'hello', + 'path': '/' + } + ] + ), + ( + [ + ('Set-Cookie', 'hello=world; Path=/; Expires=Thu, 01-Jan-1970 00:00:00 GMT; HttpOnly'), + ('Set-Cookie', 'pea=pod; Path=/ab; Expires=Thu, 01-Jan-1970 00:00:00 GMT; HttpOnly'), + ('Connection', 'keep-alive') + ], + None, + [ + {'name': 'hello', 'path': '/'}, + {'name': 'pea', 'path': '/ab'} + ] + ), + ( + [ + ('Set-Cookie', 'hello=world; Path=/; Expires=Fri, 12 Jun 2020 12:28:55 GMT; HttpOnly'), + ('Connection', 'keep-alive') + ], + datetime(2020, 6, 11).timestamp(), + [ + + ] + ) + ] + ) + def test_get_expired_cookies_manages_multiple_cookie_headers(self, raw_header, timestamp, expected): + assert get_expired_cookies(raw_header, curr_timestamp=timestamp) == expected From 37200eb055040762593fcde0e864da984c111a70 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 15 Jun 2020 23:02:16 +0200 Subject: [PATCH 0588/1182] Cleanup --- httpie/client.py | 10 ++++++---- httpie/sessions.py | 2 +- httpie/utils.py | 42 +++++++++++++++++++++--------------------- tests/test_sessions.py | 26 ++++++++++++-------------- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index 65f88e43eb..ff596bbd31 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -11,7 +11,6 @@ import requests # noinspection PyPackageRequirements import urllib3 -from requests.cookies import remove_cookie_by_name from httpie import __version__ from httpie.cli.dicts import RequestHeadersDict @@ -96,9 +95,11 @@ def collect_messages( **send_kwargs_merged, **send_kwargs, ) - expired_cookies += get_expired_cookies( - headers=response.raw._original_response.msg._headers - ) + + # noinspection PyProtectedMember + expired_cookies += get_expired_cookies( + headers=response.raw._original_response.msg._headers + ) response_count += 1 if response.next: @@ -116,6 +117,7 @@ def collect_messages( if httpie_session.is_new() or not args.session_read_only: httpie_session.cookies = requests_session.cookies httpie_session.remove_cookies( + # TODO: take path & domain into account? cookie['name'] for cookie in expired_cookies ) httpie_session.save() diff --git a/httpie/sessions.py b/httpie/sessions.py index 5750f3de46..c8581fa6f7 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -9,7 +9,7 @@ from urllib.parse import urlsplit from requests.auth import AuthBase -from requests.cookies import RequestsCookieJar, create_cookie, remove_cookie_by_name +from requests.cookies import RequestsCookieJar, create_cookie from httpie.cli.dicts import RequestHeadersDict from httpie.config import BaseConfigDict, DEFAULT_CONFIG_DIR diff --git a/httpie/utils.py b/httpie/utils.py index d47f3531c7..41bdbdd48c 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -89,25 +89,25 @@ def get_content_type(filename): return content_type -def get_expired_cookies(headers: List[Tuple[str, str]], curr_timestamp: float = None) -> List[dict]: - expired_cookies = [] - cookie_headers = [] - curr_timestamp = curr_timestamp or time.time() - - for header_name, content in headers: - if header_name == 'Set-Cookie': - cookie_headers.append(content) - - extracted_cookies = [ - dict(cookie, name=cookie[0][0]) - for cookie in parse_ns_headers(cookie_headers) +def get_expired_cookies( + headers: List[Tuple[str, str]], + now: float = None +) -> List[dict]: + now = now or time.time() + attr_sets: List[Tuple[str, str]] = parse_ns_headers( + value for name, value in headers + if name.lower() == 'set-cookie' + ) + cookies = [ + # The first attr name is the cookie name. + dict(attrs[1:], name=attrs[0][0]) + for attrs in attr_sets + ] + return [ + { + 'name': cookie['name'], + 'path': cookie.get('path', '/') + } + for cookie in cookies + if cookie.get('expires', float('Inf')) <= now ] - - for cookie in extracted_cookies: - if "expires" in cookie and cookie['expires'] <= curr_timestamp: - expired_cookies.append({ - 'name': cookie['name'], - 'path': cookie.get('path', '/') - }) - - return expired_cookies diff --git a/tests/test_sessions.py b/tests/test_sessions.py index b547431036..6cb5ce0e7a 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -193,6 +193,12 @@ def test_download_in_session(self, httpbin): class TestExpiredCookies: + def setup_method(self, method): + self.config_dir = mk_config_dir() + + def teardown_method(self, method): + shutil.rmtree(self.config_dir) + @pytest.mark.parametrize( argnames=['initial_cookie', 'expired_cookie'], argvalues=[ @@ -201,14 +207,11 @@ class TestExpiredCookies: ] ) def test_removes_expired_cookies_from_session_obj(self, initial_cookie, expired_cookie, httpbin): - config_dir = mk_config_dir() - session = Session(config_dir) + session = Session(self.config_dir) session['cookies'] = initial_cookie session.remove_cookies([expired_cookie]) assert expired_cookie not in session.cookies - shutil.rmtree(config_dir) - def test_expired_cookies(self, httpbin): orig_session = { 'cookies': { @@ -220,8 +223,7 @@ def test_expired_cookies(self, httpbin): }, } } - config_dir = mk_config_dir() - session_path = config_dir / 'test-session.json' + session_path = self.config_dir / 'test-session.json' session_path.write_text(json.dumps(orig_session)) r = http( @@ -235,10 +237,8 @@ def test_expired_cookies(self, httpbin): assert 'to_stay' in updated_session['cookies'] assert 'to_expire' not in updated_session['cookies'] - shutil.rmtree(config_dir) - @pytest.mark.parametrize( - argnames=['raw_header', 'timestamp', 'expected'], + argnames=['headers', 'now', 'expected_expired'], argvalues=[ ( [ @@ -271,11 +271,9 @@ def test_expired_cookies(self, httpbin): ('Connection', 'keep-alive') ], datetime(2020, 6, 11).timestamp(), - [ - - ] + [] ) ] ) - def test_get_expired_cookies_manages_multiple_cookie_headers(self, raw_header, timestamp, expected): - assert get_expired_cookies(raw_header, curr_timestamp=timestamp) == expected + def test_get_expired_cookies_manages_multiple_cookie_headers(self, headers, now, expected_expired): + assert get_expired_cookies(headers, now=now) == expected_expired From 26e29612f2709db1d86d9b61f3d4ed58c2c70a10 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 15 Jun 2020 23:08:09 +0200 Subject: [PATCH 0589/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 46dd453b29..55252d0ca7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,7 @@ This project adheres to `Semantic Versioning `_. * Added ``--ciphers`` to allow configuring OpenSSL ciphers (`#870`_). * Added support for ``$XDG_CONFIG_HOME`` (`#920`_). * Added support for custom content types for uploaded files (`#668`_). +* Added support for ``Set-Cookie``-triggered cookie expiration (`#853`_). `2.1.0`_ (2020-04-18) @@ -437,9 +438,10 @@ This project adheres to `Semantic Versioning `_. .. _#128: https://github.com/jakubroztocil/httpie/issues/128 .. _#488: https://github.com/jakubroztocil/httpie/issues/488 +.. _#668: https://github.com/jakubroztocil/httpie/issues/668 .. _#840: https://github.com/jakubroztocil/httpie/issues/840 +.. _#853: https://github.com/jakubroztocil/httpie/issues/853 .. _#870: https://github.com/jakubroztocil/httpie/issues/870 .. _#895: https://github.com/jakubroztocil/httpie/issues/895 .. _#920: https://github.com/jakubroztocil/httpie/issues/920 .. _#925: https://github.com/jakubroztocil/httpie/issues/925 -.. _#668: https://github.com/jakubroztocil/httpie/issues/668 From c240162cab73c3b7a6bac4fea8d26fbffae7b56e Mon Sep 17 00:00:00 2001 From: Nicolas Beltran Date: Tue, 9 Jun 2020 18:21:48 -0500 Subject: [PATCH 0590/1182] Added a test that verifies .netrc is honored when only --auth-type is passed --- tests/test_auth.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index e94bb3df76..80669b1fd9 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -15,7 +15,6 @@ def test_basic_auth(httpbin_both): assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} - @pytest.mark.parametrize('argument_name', ['--auth-type', '-A']) def test_digest_auth(httpbin_both, argument_name): r = http(argument_name + '=digest', '--auth=user:password', @@ -107,3 +106,11 @@ def test_ignore_netrc_together_with_auth(): env=MockEnvironment(), ) assert isinstance(args.auth, HTTPBasicAuth) + +def test_honor_netrc_authtype(httpbin_both): + with mock.patch('requests.sessions.get_netrc_auth') as get_netrc_auth: + get_netrc_auth.return_value = ('httpie', 'password') + r = http('--auth-type=basic','GET', httpbin_both + '/basic-auth/httpie/password') + assert get_netrc_auth.call_count == 1 + assert HTTP_OK in r + From b86598886ea50c5259982ac18a692748bd3ba402 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 16 Jun 2020 11:05:00 +0200 Subject: [PATCH 0591/1182] Added netrc support for auth plugins. Enabled for --auth-type=basic and digest, 3rd parties may opt in. This closes #718, closes #719, closes #852, and also closes #934 --- CHANGELOG.rst | 6 +++++ httpie/cli/argparser.py | 17 +++++++++++- httpie/plugins/base.py | 11 +++++++- httpie/plugins/builtin.py | 4 ++- tests/test_auth.py | 54 +++++++++++++++++++++++++++++---------- 5 files changed, 75 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 55252d0ca7..54b8c62389 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,8 @@ This project adheres to `Semantic Versioning `_. * Added support for ``$XDG_CONFIG_HOME`` (`#920`_). * Added support for custom content types for uploaded files (`#668`_). * Added support for ``Set-Cookie``-triggered cookie expiration (`#853`_). +* Added ``netrc`` support for auth plugins. + Enabled for ``--auth-type=basic`` and ``digest``, 3rd parties may opt in (`#718`_, `#719`_, `#852`_, `#934`_). `2.1.0`_ (2020-04-18) @@ -439,9 +441,13 @@ This project adheres to `Semantic Versioning `_. .. _#128: https://github.com/jakubroztocil/httpie/issues/128 .. _#488: https://github.com/jakubroztocil/httpie/issues/488 .. _#668: https://github.com/jakubroztocil/httpie/issues/668 +.. _#718: https://github.com/jakubroztocil/httpie/issues/718 +.. _#719: https://github.com/jakubroztocil/httpie/issues/719 .. _#840: https://github.com/jakubroztocil/httpie/issues/840 .. _#853: https://github.com/jakubroztocil/httpie/issues/853 +.. _#852: https://github.com/jakubroztocil/httpie/issues/852 .. _#870: https://github.com/jakubroztocil/httpie/issues/870 .. _#895: https://github.com/jakubroztocil/httpie/issues/895 .. _#920: https://github.com/jakubroztocil/httpie/issues/920 .. _#925: https://github.com/jakubroztocil/httpie/issues/925 +.. _#934: https://github.com/jakubroztocil/httpie/issues/934 diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 87e6a1bf8c..37bb170e63 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -7,6 +7,8 @@ from textwrap import dedent from urllib.parse import urlsplit +from requests.utils import get_netrc_auth + from httpie.cli.argtypes import AuthCredentials, KeyValueArgType, parse_auth from httpie.cli.constants import ( HTTP_GET, HTTP_POST, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, @@ -154,7 +156,7 @@ def _setup_standard_streams(self): self.env.stdout_isatty = False def _process_auth(self): - # TODO: refactor + # TODO: refactor & simplify this method. self.args.auth_plugin = None default_auth_plugin = plugin_manager.get_auth_plugins()[0] auth_type_set = self.args.auth_type is not None @@ -177,6 +179,19 @@ def _process_auth(self): self.args.auth_type = default_auth_plugin.auth_type plugin = plugin_manager.get_auth_plugin(self.args.auth_type)() + if (not self.args.ignore_netrc + and self.args.auth is None + and plugin.netrc_parse): + # Only host needed, so it’s OK URL not finalized. + netrc_credentials = get_netrc_auth(self.args.url) + if netrc_credentials: + self.args.auth = AuthCredentials( + key=netrc_credentials[0], + value=netrc_credentials[1], + sep=SEPARATOR_CREDENTIALS, + orig=SEPARATOR_CREDENTIALS.join(netrc_credentials) + ) + if plugin.auth_require and self.args.auth is None: self.error('--auth required') diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index 80835da05c..5b1b4d8a09 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -35,13 +35,22 @@ class AuthPlugin(BasePlugin): # Set this to `False` to disable the parsing and error handling. auth_parse = True + # Set to `True` to make it possible for this auth + # plugin to acquire credentials from the user’s netrc file(s). + # It is used as a fallback when the credentials are not provided explicitly + # through `--auth, -a`. Enabling this will allow skipping `--auth, -a` + # even when `auth_require` is set `True` (provided that netrc provides + # credential for a given host). + netrc_parse = False + # If both `auth_parse` and `prompt_password` are set to `True`, # and the value of `-a` lacks the password part, # then the user will be prompted to type the password in. prompt_password = True # Will be set to the raw value of `-a` (if provided) before - # `get_auth()` gets called. + # `get_auth()` gets called. If the credentials came from a netrc file, + # then this is `None`. raw_auth = None def get_auth(self, username=None, password=None): diff --git a/httpie/plugins/builtin.py b/httpie/plugins/builtin.py index 1a01c902fb..4c6dc445bb 100644 --- a/httpie/plugins/builtin.py +++ b/httpie/plugins/builtin.py @@ -22,6 +22,7 @@ def __call__( See https://github.com/jakubroztocil/httpie/issues/212 """ + # noinspection PyTypeChecker request.headers['Authorization'] = type(self).make_header( self.username, self.password).encode('latin1') return request @@ -36,6 +37,7 @@ def make_header(username: str, password: str) -> str: class BasicAuthPlugin(BuiltinAuthPlugin): name = 'Basic HTTP auth' auth_type = 'basic' + netrc_parse = True # noinspection PyMethodOverriding def get_auth(self, username: str, password: str) -> HTTPBasicAuth: @@ -43,9 +45,9 @@ def get_auth(self, username: str, password: str) -> HTTPBasicAuth: class DigestAuthPlugin(BuiltinAuthPlugin): - name = 'Digest HTTP auth' auth_type = 'digest' + netrc_parse = True # noinspection PyMethodOverriding def get_auth( diff --git a/tests/test_auth.py b/tests/test_auth.py index 80669b1fd9..7160adaca7 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -3,6 +3,7 @@ import pytest from httpie.plugins.builtin import HTTPBasicAuth +from httpie.status import ExitStatus from httpie.utils import ExplicitNullAuth from utils import http, add_auth, HTTP_OK, MockEnvironment import httpie.cli.constants @@ -15,6 +16,7 @@ def test_basic_auth(httpbin_both): assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} + @pytest.mark.parametrize('argument_name', ['--auth-type', '-A']) def test_digest_auth(httpbin_both, argument_name): r = http(argument_name + '=digest', '--auth=user:password', @@ -77,6 +79,8 @@ def test_missing_auth(httpbin): def test_netrc(httpbin_both): + # This one gets handled by requests (no --auth, --auth-type present), + # that’s why we patch inside `requests.sessions`. with mock.patch('requests.sessions.get_netrc_auth') as get_netrc_auth: get_netrc_auth.return_value = ('httpie', 'password') r = http(httpbin_both + '/basic-auth/httpie/password') @@ -85,21 +89,13 @@ def test_netrc(httpbin_both): def test_ignore_netrc(httpbin_both): - with mock.patch('requests.sessions.get_netrc_auth') as get_netrc_auth: + with mock.patch('httpie.cli.argparser.get_netrc_auth') as get_netrc_auth: get_netrc_auth.return_value = ('httpie', 'password') r = http('--ignore-netrc', httpbin_both + '/basic-auth/httpie/password') assert get_netrc_auth.call_count == 0 assert 'HTTP/1.1 401 UNAUTHORIZED' in r -def test_ignore_netrc_null_auth(): - args = httpie.cli.definition.parser.parse_args( - args=['--ignore-netrc', 'example.org'], - env=MockEnvironment(), - ) - assert isinstance(args.auth, ExplicitNullAuth) - - def test_ignore_netrc_together_with_auth(): args = httpie.cli.definition.parser.parse_args( args=['--ignore-netrc', '--auth=username:password', 'example.org'], @@ -107,10 +103,40 @@ def test_ignore_netrc_together_with_auth(): ) assert isinstance(args.auth, HTTPBasicAuth) -def test_honor_netrc_authtype(httpbin_both): - with mock.patch('requests.sessions.get_netrc_auth') as get_netrc_auth: + +def test_ignore_netrc_with_auth_type_resulting_in_missing_auth(httpbin): + with mock.patch('httpie.cli.argparser.get_netrc_auth') as get_netrc_auth: get_netrc_auth.return_value = ('httpie', 'password') - r = http('--auth-type=basic','GET', httpbin_both + '/basic-auth/httpie/password') - assert get_netrc_auth.call_count == 1 - assert HTTP_OK in r + r = http( + '--ignore-netrc', + '--auth-type=basic', + httpbin + '/basic-auth/httpie/password', + tolerate_error_exit_status=True, + ) + assert get_netrc_auth.call_count == 0 + assert r.exit_status == ExitStatus.ERROR + assert '--auth required' in r.stderr + + +@pytest.mark.parametrize( + argnames=['auth_type', 'endpoint'], + argvalues=[ + ('basic', '/basic-auth/httpie/password'), + ('digest', '/digest-auth/auth/httpie/password'), + ], +) +def test_auth_plugin_netrc_parse(auth_type, endpoint, httpbin): + # Test + with mock.patch('httpie.cli.argparser.get_netrc_auth') as get_netrc_auth: + get_netrc_auth.return_value = ('httpie', 'password') + r = http('--auth-type', auth_type, httpbin + endpoint) + assert get_netrc_auth.call_count == 1 + assert HTTP_OK in r + +def test_ignore_netrc_null_auth(): + args = httpie.cli.definition.parser.parse_args( + args=['--ignore-netrc', 'example.org'], + env=MockEnvironment(), + ) + assert isinstance(args.auth, ExplicitNullAuth) From 826489950db541089c5ab95b96d01b821be3fd8d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 16 Jun 2020 12:20:13 +0200 Subject: [PATCH 0592/1182] Added --unsorted It acts as a shortcut for --format-options=json.sort_keys:false,headers.sort:false #128 --- CHANGELOG.rst | 1 + httpie/cli/argparser.py | 18 ++++++++++-- httpie/cli/argtypes.py | 6 ++++ httpie/cli/constants.py | 5 +++- httpie/cli/definition.py | 28 ++++++++++++------- tests/test_output.py | 59 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 103 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 54b8c62389..3c9b91252a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,7 @@ This project adheres to `Semantic Versioning `_. * Fixed built-in plugins-related circular imports (`#925`_). * Added ``--format-options`` to allow disabling sorting, etc. (`#128`_) +* Added ``--unsorted`` shortcut to set all sorting-related ``--format-options`` to ``false``. (`#128`_) * Added ``--ciphers`` to allow configuring OpenSSL ciphers (`#870`_). * Added support for ``$XDG_CONFIG_HOME`` (`#920`_). * Added support for custom content types for uploaded files (`#668`_). diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 37bb170e63..b99d38be30 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -9,9 +9,14 @@ from requests.utils import get_netrc_auth -from httpie.cli.argtypes import AuthCredentials, KeyValueArgType, parse_auth +from httpie.cli.argtypes import ( + AuthCredentials, KeyValueArgType, PARSED_DEFAULT_FORMAT_OPTIONS, + parse_auth, + parse_format_options, +) from httpie.cli.constants import ( - HTTP_GET, HTTP_POST, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, + DEFAULT_FORMAT_OPTIONS, HTTP_GET, HTTP_POST, OUTPUT_OPTIONS, + OUTPUT_OPTIONS_DEFAULT, OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED, OUT_RESP_BODY, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, SEPARATOR_CREDENTIALS, SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_GROUP_DATA_ITEMS, URL_SCHEME_RE, @@ -44,6 +49,8 @@ def _split_lines(self, text, width): return text.splitlines() +# TODO: refactor and design type-annotated data structures +# for raw args + parsed args and keep things immutable. class HTTPieArgumentParser(argparse.ArgumentParser): """Adds additional logic to `argparse.ArgumentParser`. @@ -84,6 +91,7 @@ def parse_args( self._setup_standard_streams() self._process_output_options() self._process_pretty_options() + self._process_format_options() self._guess_method() self._parse_items() @@ -405,3 +413,9 @@ def _process_download_options(self): if self.args.download_resume and not ( self.args.download and self.args.output_file): self.error('--continue requires --output to be specified') + + def _process_format_options(self): + parsed_options = PARSED_DEFAULT_FORMAT_OPTIONS + for options_group in self.args.format_options: + parsed_options = parse_format_options(options_group, defaults=parsed_options) + self.args.format_options = parsed_options diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index 0d4f9eb244..4f16e7c431 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -242,3 +242,9 @@ def parse_format_options(s: str, defaults: Optional[dict]) -> dict: s=','.join(DEFAULT_FORMAT_OPTIONS), defaults=None, ) + + +class UnsortedAction(argparse.Action): + + def __call__(self, *args, **kwargs): + return 1 diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index ea8036fe24..6305588c46 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -91,7 +91,10 @@ 'json.indent:4', 'json.sort_keys:true', ] - +UNSORTED_FORMAT_OPTIONS = [ + 'headers.sort:false', + 'json.sort_keys:false', +] # Defaults OUTPUT_OPTIONS_DEFAULT = OUT_RESP_HEAD + OUT_RESP_BODY diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index b3b5f3887c..f8215220ce 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -9,14 +9,13 @@ from httpie.cli.argparser import HTTPieArgumentParser from httpie.cli.argtypes import ( KeyValueArgType, PARSED_DEFAULT_FORMAT_OPTIONS, SessionNameValidator, - parse_format_options, readable_file_arg, ) from httpie.cli.constants import ( DEFAULT_FORMAT_OPTIONS, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_BODY, OUT_RESP_HEAD, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, - SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY, + SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY, UNSORTED_FORMAT_OPTIONS, ) from httpie.output.formatters.colors import ( AUTO_STYLE, AVAILABLE_STYLES, DEFAULT_STYLE, @@ -229,14 +228,22 @@ auto_style=AUTO_STYLE, ) ) +output_processing.add_argument( + '--unsorted', + action='append_const', + const=','.join(UNSORTED_FORMAT_OPTIONS), + dest='format_options', + help=""" + Disables all sorting while formatting output. It is a shortcut for: + --format-options=json.sort_keys:false,headers.sort:false + + """ +) output_processing.add_argument( '--format-options', - type=lambda s: parse_format_options( - s=s, - defaults=PARSED_DEFAULT_FORMAT_OPTIONS - ), - default=PARSED_DEFAULT_FORMAT_OPTIONS, + default=[], + action='append', help=""" Controls output formatting. Only relevant when formatting is enabled through (explicit or implied) --pretty=all or --pretty=format. @@ -244,10 +251,11 @@ {option_list} - You can specify multiple comma-separated options. For example, this modifies - the settings to disable the sorting of JSON keys and headers: + You may use this option multiple times, as well as specify multiple + comma-separated options at the same time. For example, this modifies the + settings to disable the sorting of JSON keys, and sets the indent size to 2: - --format-options json.sort_keys:false,headers.sort:false + --format-options json.sort_keys:false,json.indent:2 This is something you will typically put into your config file. diff --git a/tests/test_output.py b/tests/test_output.py index e0438c10f2..afa499ce44 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -6,7 +6,12 @@ import pytest -from httpie.cli.argtypes import parse_format_options +from httpie.cli.constants import DEFAULT_FORMAT_OPTIONS +from httpie.cli.definition import parser +from httpie.cli.argtypes import ( + PARSED_DEFAULT_FORMAT_OPTIONS, + parse_format_options, +) from httpie.output.formatters.colors import get_lexer from httpie.status import ExitStatus from utils import COLOR, CRLF, HTTP_OK, MockEnvironment, http @@ -249,3 +254,55 @@ def test_parse_format_options_errors(self, options_string, expected_error): } with pytest.raises(argparse.ArgumentTypeError, match=expected_error): parse_format_options(s=options_string, defaults=defaults) + + @pytest.mark.parametrize( + argnames=['args', 'expected_format_options'], + argvalues=[ + ( + [ + '--format-options', + 'headers.sort:false,json.sort_keys:false', + '--format-options=json.indent:10' + ], + { + 'headers': {'sort': False}, + 'json': {'sort_keys': False, 'indent': 10, 'format': True}, + } + ), + ( + [ + '--unsorted' + ], + { + 'headers': {'sort': False}, + 'json': {'sort_keys': False, 'indent': 4, 'format': True}, + } + ), + ( + [ + '--format-options=headers.sort:true', + '--unsorted', + '--format-options=headers.sort:true', + ], + { + 'headers': {'sort': True}, + 'json': {'sort_keys': False, 'indent': 4, 'format': True}, + } + ), + ( + [ + '--no-format-options', # --no-

      + This is an example of an + XHTML + 1.0 Strict document. +
      + Valid XHTML 1.0 Strict +
      + + +

      + + diff --git a/tests/fixtures/xmldata/xhtml/xhtml_formatted_python_less_than_3.8.xml b/tests/fixtures/xmldata/xhtml/xhtml_formatted_python_less_than_3.8.xml new file mode 100644 index 0000000000..7e6eced389 --- /dev/null +++ b/tests/fixtures/xmldata/xhtml/xhtml_formatted_python_less_than_3.8.xml @@ -0,0 +1,30 @@ + + + + + + XHTML 1.0 Strict Example + + + +

      + This is an example of an + XHTML + 1.0 Strict document. +
      + Valid XHTML 1.0 Strict +
      + + +

      + + diff --git a/tests/fixtures/xmldata/xhtml/xhtml_raw.xml b/tests/fixtures/xmldata/xhtml/xhtml_raw.xml new file mode 100644 index 0000000000..7868427259 --- /dev/null +++ b/tests/fixtures/xmldata/xhtml/xhtml_raw.xml @@ -0,0 +1,30 @@ + + + + + XHTML 1.0 Strict Example + + + +

      This is an example of an + XHTML 1.0 Strict document.
      + Valid XHTML 1.0 Strict
      + + +

      + + diff --git a/tests/test_output.py b/tests/test_output.py index ee3a85c4d0..1a9d9dadc2 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -377,6 +377,10 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 10, 'format': True }, + 'xml': { + 'format': True, + 'indent': 4, + }, } ), ( @@ -392,6 +396,10 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 4, 'format': True }, + 'xml': { + 'format': True, + 'indent': 4, + }, } ), ( @@ -409,6 +417,10 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 4, 'format': True }, + 'xml': { + 'format': True, + 'indent': 4, + }, } ), ( @@ -423,6 +435,8 @@ def test_parse_format_options_errors(self, options_string, expected_error): ( [ '--format-options=json.indent:2', + '--format-options=xml.format:false', + '--format-options=xml.indent:2', '--unsorted', '--no-unsorted', ], @@ -435,6 +449,10 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 2, 'format': True }, + 'xml': { + 'format': False, + 'indent': 2, + }, } ), ( @@ -452,6 +470,10 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 2, 'format': True }, + 'xml': { + 'format': True, + 'indent': 4, + }, } ), ( @@ -470,6 +492,10 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 2, 'format': True }, + 'xml': { + 'format': True, + 'indent': 4, + }, } ), ], diff --git a/tests/test_xml.py b/tests/test_xml.py new file mode 100644 index 0000000000..a91a583a5b --- /dev/null +++ b/tests/test_xml.py @@ -0,0 +1,90 @@ +import sys + +import pytest +import responses + +from httpie.constants import UTF8 +from httpie.output.formatters.xml import parse_xml, pretty_xml + +from .fixtures import XML_FILES_PATH, XML_FILES_VALID, XML_FILES_INVALID +from .utils import http + +SAMPLE_XML_DATA = 'text' + + +@pytest.mark.parametrize( + 'options, expected_xml', + [ + ('xml.format:false', SAMPLE_XML_DATA), + ('xml.indent:2', pretty_xml(parse_xml(SAMPLE_XML_DATA), indent=2)), + ('xml.indent:4', pretty_xml(parse_xml(SAMPLE_XML_DATA))), + ] +) +@responses.activate +def test_xml_format_options(options, expected_xml): + url = 'https://example.org' + responses.add(responses.GET, url, body=SAMPLE_XML_DATA, + content_type='application/xml') + + r = http('--format-options', options, url) + assert expected_xml in r + + +@pytest.mark.parametrize('file', XML_FILES_VALID) +@responses.activate +def test_valid_xml(file): + """Test XML formatter limits with data containing comments, doctypes + and other XML-specific subtles. + """ + if 'standalone' in file.stem and sys.version_info < (3, 9): + pytest.skip('Standalone XML requires Python 3.9+') + + url = 'https://example.org' + xml_data = file.read_text(encoding=UTF8) + expected_xml_file = file.with_name(file.name.replace('_raw', '_formatted')) + expected_xml_output = expected_xml_file.read_text(encoding=UTF8) + responses.add(responses.GET, url, body=xml_data, + content_type='application/xml') + + r = http(url) + assert expected_xml_output in r + + +@responses.activate +def test_xml_xhtml(): + """XHTML responses are handled by the XML formatter.""" + url = 'https://example.org' + file = XML_FILES_PATH / 'xhtml' / 'xhtml_raw.xml' + xml_data = file.read_text(encoding=UTF8) + + # Python < 3.8 was sorting attributes (https://bugs.python.org/issue34160) + # so we have 2 different output expected given the Python version. + expected_file_name = ( + 'xhtml_formatted_python_less_than_3.8.xml' + if sys.version_info < (3, 8) + else 'xhtml_formatted.xml' + ) + expected_xml_file = file.with_name(expected_file_name) + expected_xml_output = expected_xml_file.read_text(encoding=UTF8) + responses.add(responses.GET, url, body=xml_data, + content_type='application/xhtml+xml') + + r = http(url) + print(r) + assert expected_xml_output in r + + +@pytest.mark.parametrize('file', XML_FILES_INVALID) +@responses.activate +def test_invalid_xml(file): + """Testing several problematic XML files, none should be formatted + and none should make HTTPie to crash. + """ + url = 'https://example.org' + xml_data = file.read_text(encoding=UTF8) + responses.add(responses.GET, url, body=xml_data, + content_type='application/xml') + + # No formatting done, data is simply printed as-is + r = http(url) + assert xml_data in r From 6c501d23c353940b823724061beaa4c5e53f64da Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 31 Aug 2021 22:52:16 +0200 Subject: [PATCH 0780/1182] Change default XML indent to 2 spaces --- README.rst | 6 +++--- httpie/cli/constants.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 6da3c33e82..fb46786917 100644 --- a/README.rst +++ b/README.rst @@ -1566,8 +1566,8 @@ You can further control the applied formatting via the more granular `format opt Format options -------------- -The ``--format-options`` option allows you to control how the output should be formatted when formatting is applied. -The following options are available: +The ``--format-options=opt1:value,opt2:value`` option allows you to control how the output should be formatted +when formatting is applied. The following options are available: +-------------------------------+---------------+------------------------------+ | Option | Default value | Shortcuts | @@ -1582,7 +1582,7 @@ The following options are available: +--------------------+----------+---------------+------------------------------+ | ``xml.format`` | ``true`` | N/A | +-------------------------------+---------------+------------------------------+ -| ``xml.indent`` | ``4`` | N/A | +| ``xml.indent`` | ``2`` | N/A | +--------------------+----------+---------------+------------------------------+ For example, this is how you would disable the default header and JSON key diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index ef6bf2c31f..a1b78d33b2 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -91,7 +91,7 @@ 'json.indent:4', 'json.sort_keys:true', 'xml.format:true', - 'xml.indent:4', + 'xml.indent:2', ] SORTED_FORMAT_OPTIONS = [ 'headers.sort:true', From fdd486415a24503426213478c46d00a306b99e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 1 Sep 2021 10:26:21 +0200 Subject: [PATCH 0781/1182] Fix XML formatter tests --- httpie/output/formatters/xml.py | 2 +- .../fixtures/xmldata/valid/dtd_formatted.xml | 4 +- .../xmldata/valid/simple-ns_formatted.xml | 8 ++-- .../xmldata/valid/simple_formatted.xml | 8 ++-- .../xmldata/xhtml/xhtml_formatted.xml | 36 +++++++++--------- .../xhtml_formatted_python_less_than_3.8.xml | 37 +++++++++---------- tests/test_output.py | 14 +++---- tests/test_xml.py | 5 +-- 8 files changed, 56 insertions(+), 58 deletions(-) diff --git a/httpie/output/formatters/xml.py b/httpie/output/formatters/xml.py index be2cd248f2..e5ce5c23f1 100644 --- a/httpie/output/formatters/xml.py +++ b/httpie/output/formatters/xml.py @@ -16,7 +16,7 @@ def parse_xml(data: str) -> 'Document': def pretty_xml(document: 'Document', encoding: Optional[str] = UTF8, - indent: int = 4, + indent: int = 2, standalone: Optional[bool] = None) -> str: """Render the given :class:`~xml.dom.minidom.Document` `document` into a prettified string.""" kwargs = { diff --git a/tests/fixtures/xmldata/valid/dtd_formatted.xml b/tests/fixtures/xmldata/valid/dtd_formatted.xml index c196becba2..372c93b87a 100644 --- a/tests/fixtures/xmldata/valid/dtd_formatted.xml +++ b/tests/fixtures/xmldata/valid/dtd_formatted.xml @@ -3,6 +3,6 @@ PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'> - - text + + text diff --git a/tests/fixtures/xmldata/valid/simple-ns_formatted.xml b/tests/fixtures/xmldata/valid/simple-ns_formatted.xml index 607f2c74e7..8273afca19 100644 --- a/tests/fixtures/xmldata/valid/simple-ns_formatted.xml +++ b/tests/fixtures/xmldata/valid/simple-ns_formatted.xml @@ -2,8 +2,8 @@ - text - text - tail - + text + text + tail + diff --git a/tests/fixtures/xmldata/valid/simple_formatted.xml b/tests/fixtures/xmldata/valid/simple_formatted.xml index 31973fa637..1638b5b6a7 100644 --- a/tests/fixtures/xmldata/valid/simple_formatted.xml +++ b/tests/fixtures/xmldata/valid/simple_formatted.xml @@ -1,8 +1,8 @@ - text - text - tail - + text + text + tail + diff --git a/tests/fixtures/xmldata/xhtml/xhtml_formatted.xml b/tests/fixtures/xmldata/xhtml/xhtml_formatted.xml index 67bbdb33f0..a1e99c80ed 100644 --- a/tests/fixtures/xmldata/xhtml/xhtml_formatted.xml +++ b/tests/fixtures/xmldata/xhtml/xhtml_formatted.xml @@ -2,28 +2,28 @@ PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'> - - - XHTML 1.0 Strict Example - - - -

      - This is an example of an - XHTML - 1.0 Strict document. -
      - Valid XHTML 1.0 Strict -
      - + //]]> + + + +

      + This is an example of an + XHTML + 1.0 Strict document. +
      + Valid XHTML 1.0 Strict +
      + -

      - +

      + diff --git a/tests/fixtures/xmldata/xhtml/xhtml_formatted_python_less_than_3.8.xml b/tests/fixtures/xmldata/xhtml/xhtml_formatted_python_less_than_3.8.xml index 7e6eced389..5987e10342 100644 --- a/tests/fixtures/xmldata/xhtml/xhtml_formatted_python_less_than_3.8.xml +++ b/tests/fixtures/xmldata/xhtml/xhtml_formatted_python_less_than_3.8.xml @@ -1,30 +1,29 @@ - - - - XHTML 1.0 Strict Example - - - -

      - This is an example of an - XHTML - 1.0 Strict document. -
      - Valid XHTML 1.0 Strict -
      - + //]]> + + + +

      + This is an example of an + XHTML + 1.0 Strict document. +
      + Valid XHTML 1.0 Strict +
      + -

      - +

      + diff --git a/tests/test_output.py b/tests/test_output.py index 1a9d9dadc2..0d0ee2f01b 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -379,7 +379,7 @@ def test_parse_format_options_errors(self, options_string, expected_error): }, 'xml': { 'format': True, - 'indent': 4, + 'indent': 2, }, } ), @@ -398,7 +398,7 @@ def test_parse_format_options_errors(self, options_string, expected_error): }, 'xml': { 'format': True, - 'indent': 4, + 'indent': 2, }, } ), @@ -419,7 +419,7 @@ def test_parse_format_options_errors(self, options_string, expected_error): }, 'xml': { 'format': True, - 'indent': 4, + 'indent': 2, }, } ), @@ -436,7 +436,7 @@ def test_parse_format_options_errors(self, options_string, expected_error): [ '--format-options=json.indent:2', '--format-options=xml.format:false', - '--format-options=xml.indent:2', + '--format-options=xml.indent:4', '--unsorted', '--no-unsorted', ], @@ -451,7 +451,7 @@ def test_parse_format_options_errors(self, options_string, expected_error): }, 'xml': { 'format': False, - 'indent': 2, + 'indent': 4, }, } ), @@ -472,7 +472,7 @@ def test_parse_format_options_errors(self, options_string, expected_error): }, 'xml': { 'format': True, - 'indent': 4, + 'indent': 2, }, } ), @@ -494,7 +494,7 @@ def test_parse_format_options_errors(self, options_string, expected_error): }, 'xml': { 'format': True, - 'indent': 4, + 'indent': 2, }, } ), diff --git a/tests/test_xml.py b/tests/test_xml.py index a91a583a5b..a956d7f550 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -16,8 +16,8 @@ 'options, expected_xml', [ ('xml.format:false', SAMPLE_XML_DATA), - ('xml.indent:2', pretty_xml(parse_xml(SAMPLE_XML_DATA), indent=2)), - ('xml.indent:4', pretty_xml(parse_xml(SAMPLE_XML_DATA))), + ('xml.indent:2', pretty_xml(parse_xml(SAMPLE_XML_DATA))), + ('xml.indent:4', pretty_xml(parse_xml(SAMPLE_XML_DATA), indent=4)), ] ) @responses.activate @@ -70,7 +70,6 @@ def test_xml_xhtml(): content_type='application/xhtml+xml') r = http(url) - print(r) assert expected_xml_output in r From 85110643e7c332f61c76be588a19035207262da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 1 Sep 2021 16:52:10 +0200 Subject: [PATCH 0782/1182] Move example URL in a global variable for tests --- tests/test_stream.py | 7 +++---- tests/utils/__init__.py | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test_stream.py b/tests/test_stream.py index 6d6a57b040..b0b1f93e31 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -9,7 +9,7 @@ from httpie.plugins import ConverterPlugin from httpie.plugins.registry import plugin_manager -from .utils import StdinBytesIO, http, MockEnvironment +from .utils import StdinBytesIO, http, MockEnvironment, URL_EXAMPLE from .fixtures import BIN_FILE_CONTENT, BIN_FILE_PATH PRETTY_OPTIONS = list(PRETTY_MAP.keys()) @@ -64,12 +64,11 @@ def test_pretty_options_with_and_without_stream_with_converter(pretty, stream): # Cover PluginManager.__repr__() assert 'SortJSONConverterPlugin' in str(plugin_manager) - url = 'http://example.org' # Note: URL never fetched body = b'\x00{"foo":42,\n"bar":"baz"}' - responses.add(responses.GET, url, body=body, + responses.add(responses.GET, URL_EXAMPLE, body=body, stream=True, content_type='json/bytes') - args = ['--pretty=' + pretty, 'GET', url] + args = ['--pretty=' + pretty, 'GET', URL_EXAMPLE] if stream: args.insert(0, '--stream') r = http(*args) diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index bf9c8304e7..193d2e2fbb 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -33,6 +33,8 @@ '\x1b[39m\x1b[38;5;245m \x1b[39m\x1b[38;5;136mOK' ) +URL_EXAMPLE = 'http://example.org' # Note: URL never fetched + def mk_config_dir() -> Path: dirname = tempfile.mkdtemp(prefix='httpie_config_') From 71008bbedb7e9b0afb16ebaa1f39eb91aadcb48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 1 Sep 2021 16:56:23 +0200 Subject: [PATCH 0783/1182] Move example URL in a global variable for XML tests --- tests/test_xml.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/tests/test_xml.py b/tests/test_xml.py index a956d7f550..7c35221925 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -7,7 +7,7 @@ from httpie.output.formatters.xml import parse_xml, pretty_xml from .fixtures import XML_FILES_PATH, XML_FILES_VALID, XML_FILES_INVALID -from .utils import http +from .utils import http, URL_EXAMPLE SAMPLE_XML_DATA = 'text' @@ -22,11 +22,10 @@ ) @responses.activate def test_xml_format_options(options, expected_xml): - url = 'https://example.org' - responses.add(responses.GET, url, body=SAMPLE_XML_DATA, + responses.add(responses.GET, URL_EXAMPLE, body=SAMPLE_XML_DATA, content_type='application/xml') - r = http('--format-options', options, url) + r = http('--format-options', options, URL_EXAMPLE) assert expected_xml in r @@ -39,21 +38,19 @@ def test_valid_xml(file): if 'standalone' in file.stem and sys.version_info < (3, 9): pytest.skip('Standalone XML requires Python 3.9+') - url = 'https://example.org' xml_data = file.read_text(encoding=UTF8) expected_xml_file = file.with_name(file.name.replace('_raw', '_formatted')) expected_xml_output = expected_xml_file.read_text(encoding=UTF8) - responses.add(responses.GET, url, body=xml_data, + responses.add(responses.GET, URL_EXAMPLE, body=xml_data, content_type='application/xml') - r = http(url) + r = http(URL_EXAMPLE) assert expected_xml_output in r @responses.activate def test_xml_xhtml(): """XHTML responses are handled by the XML formatter.""" - url = 'https://example.org' file = XML_FILES_PATH / 'xhtml' / 'xhtml_raw.xml' xml_data = file.read_text(encoding=UTF8) @@ -66,10 +63,10 @@ def test_xml_xhtml(): ) expected_xml_file = file.with_name(expected_file_name) expected_xml_output = expected_xml_file.read_text(encoding=UTF8) - responses.add(responses.GET, url, body=xml_data, + responses.add(responses.GET, URL_EXAMPLE, body=xml_data, content_type='application/xhtml+xml') - r = http(url) + r = http(URL_EXAMPLE) assert expected_xml_output in r @@ -79,11 +76,10 @@ def test_invalid_xml(file): """Testing several problematic XML files, none should be formatted and none should make HTTPie to crash. """ - url = 'https://example.org' xml_data = file.read_text(encoding=UTF8) - responses.add(responses.GET, url, body=xml_data, + responses.add(responses.GET, URL_EXAMPLE, body=xml_data, content_type='application/xml') # No formatting done, data is simply printed as-is - r = http(url) + r = http(URL_EXAMPLE) assert xml_data in r From 41666d897f9051143ac33748836a0111fb730a62 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 2 Sep 2021 10:37:14 +0200 Subject: [PATCH 0784/1182] Update CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 56c15b3b47..4a10c74e15 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,10 +12,10 @@ This project adheres to `Semantic Versioning `_. * Added ``--raw`` to allow specifying the raw request body without extra processing as an alternative to ``stdin``. (`#534`_) * Added support for XML formatting. (`#1129`_) +* Added internal support for file-like object responses to improve adapter plugin support. (`#1094`_) * Fixed ``--continue --download`` with a single byte to be downloaded left. (`#1032`_) * Fixed ``--verbose`` HTTP 307 redirects with streamed request body. (`#1088`_) * Fixed handling of session files with ``Cookie:`` followed by other headers. (`#1126`_) -* Add internal support for file-like object responses to improve adapter plugin support. (`#1094`_) `2.4.0`_ (2021-02-06) From a62391e789e1137901228b57c98eb50f2453ca01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 2 Sep 2021 16:47:01 +0200 Subject: [PATCH 0785/1182] Tiny clean-up in `program()` (#1135) --- httpie/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/core.py b/httpie/core.py index cf2567d489..9c9e3ce406 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -213,7 +213,7 @@ def request_body_read_callback(chunk: bytes): finally: if downloader and not downloader.finished: downloader.failed() - if not isinstance(args, list) and args.output_file and args.output_file_specified: + if args.output_file and args.output_file_specified: args.output_file.close() From e7d8b9cece4e1a84970750c9ab9f65369227bf2b Mon Sep 17 00:00:00 2001 From: a1346054 <36859588+a1346054@users.noreply.github.com> Date: Fri, 3 Sep 2021 13:05:03 +0000 Subject: [PATCH 0786/1182] Spelling and bash completion fixes (#1137) * Remove hashbang from bash completion Completion files are not supposed to have a hashbang. They are sourced, not executed. * Fix spelling * Trim excess whitespace --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- CHANGELOG.rst | 4 ++-- CONTRIBUTING.rst | 2 +- README.rst | 10 +++++----- extras/httpie-completion.bash | 5 +---- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index aed8028d11..d3866e8431 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -10,7 +10,7 @@ assignees: '' **Checklist** - [ ] I've searched for similar issues. -- [ ] I'm using the the latest version of HTTPie. +- [ ] I'm using the latest version of HTTPie. --- diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4a10c74e15..d99e5f00ab 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -110,7 +110,7 @@ This project adheres to `Semantic Versioning `_. 2. The server handling the request has been modified by an attacker and instead of the expected response the URL returns a redirect to another URL, e.g., ``attacker.example.org/.bash_profile``, whose response does - not provide a ``Content-Disposition`` header (i.e., the base for the + not provide a ``Content-Disposition`` header (i.e., the base for the generated filename becomes ``.bash_profile`` instead of ``file.txt``). 3. Your current directory doesn’t already contain ``.bash_profile`` (i.e., no unique suffix is added to the generated filename). @@ -286,7 +286,7 @@ This project adheres to `Semantic Versioning `_. * XML data is now formatted * ``--session`` and ``--session-read-only`` now also accept paths to - session files (eg. ``http --session=/tmp/session.json example.org``) + session files (e.g. ``http --session=/tmp/session.json example.org``) `0.5.1`_ (2013-05-13) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 1707fd7f80..d1ad30ce63 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -25,7 +25,7 @@ to your bug report, e.g.: ============================= Before working on a new feature or a bug, please browse `existing issues`_ -to see whether it has previously been discussed. +to see whether it has previously been discussed. If your change alters HTTPie’s behaviour or interface, it's a good idea to discuss it before you start working on it. diff --git a/README.rst b/README.rst index fb46786917..f8c6a27abd 100644 --- a/README.rst +++ b/README.rst @@ -36,7 +36,7 @@ You can select your corresponding HTTPie version as well as run examples directl browser using a `termible.io `_ embedded terminal. If you are reading this on GitHub, then this text covers the current *development* version. -You are invited to submit fixes and improvements to the the docs by editing +You are invited to submit fixes and improvements to the docs by editing `README.rst `_. @@ -159,7 +159,7 @@ 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 +the ``master`` branch on GitHub. It is a work-in-progress of a future stable release so the experience might be not as smooth. @@ -1319,7 +1319,7 @@ Viewing intermediary requests/responses --------------------------------------- To see all the HTTP communication, i.e. the final request/response as -well as any possible intermediary requests/responses, use the ``--all`` +well as any possible intermediary requests/responses, use the ``--all`` option. The intermediary HTTP communication include followed redirects (with ``--follow``), the first unauthorized request when HTTP digest authentication is used (``--auth=digest``), etc. @@ -1727,7 +1727,7 @@ headers and progress are still shown in the terminal: .. code-block:: bash - $ http -d https://github.com/httpie/httpie/archive/master.tar.gz | tar zxf - + $ http -d https://github.com/httpie/httpie/archive/master.tar.gz | tar zxf - @@ -2104,7 +2104,7 @@ Interface design ---------------- The syntax of the command arguments closely corresponds to the actual HTTP -requests sent over the wire. It has the advantage that it’s easy to remember +requests sent over the wire. It has the advantage that it’s easy to remember and read. It is often possible to translate an HTTP request to an HTTPie argument list just by inlining the request elements. For example, compare this HTTP request: diff --git a/extras/httpie-completion.bash b/extras/httpie-completion.bash index a1c29de734..76af2debcf 100644 --- a/extras/httpie-completion.bash +++ b/extras/httpie-completion.bash @@ -1,11 +1,8 @@ -#!/usr/bin/env bash - - _http_complete() { local cur_word=${COMP_WORDS[COMP_CWORD]} local prev_word=${COMP_WORDS[COMP_CWORD - 1]} - if [[ "$cur_word" == -* ]]; then + if [[ "$cur_word" == -* ]]; then _http_complete_options "$cur_word" fi } From 6039bd858235589eb843c4865068e6f73d8fc290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 6 Sep 2021 17:36:13 +0200 Subject: [PATCH 0787/1182] Switch from reStructuredText to Markdown and add `docs/` (#1139) * Convert most of the documentation from the frontend `README.rst` to `docs/REAME.md` Also converted all reStructuredText files to Markdown. * Tell `mdformat` to use LF for end on lines * `--check` is not needed in the help message * Skip tests on GitHub Windows. Those tests pass on a real Windows machine. Let's revisit those failure later, if needed. * Move `mdoformat` requirement from `test` to `dev` extra To fix Fedora CI. --- AUTHORS.md | 41 + AUTHORS.rst | 43 - CHANGELOG.md | 367 +++++++ CHANGELOG.rst | 511 ---------- CODE_OF_CONDUCT.md | 32 +- CONTRIBUTING.md | 196 ++++ CONTRIBUTING.rst | 239 ----- MANIFEST.in | 7 +- Makefile | 16 +- README.md | 105 ++ README.rst | 2269 -------------------------------------------- docs/README.md | 1686 ++++++++++++++++++++++++++++++++ setup.py | 6 +- tests/README.md | 3 + tests/README.rst | 8 - tests/test_docs.py | 64 +- 16 files changed, 2436 insertions(+), 3157 deletions(-) create mode 100644 AUTHORS.md delete mode 100644 AUTHORS.rst create mode 100644 CHANGELOG.md delete mode 100644 CHANGELOG.rst create mode 100644 CONTRIBUTING.md delete mode 100644 CONTRIBUTING.rst create mode 100644 README.md delete mode 100644 README.rst create mode 100644 docs/README.md create mode 100644 tests/README.md delete mode 100644 tests/README.rst diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000000..72fc384df6 --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,41 @@ +# HTTPie authors + +- [Jakub Roztocil](https://github.com/jakubroztocil) + +## Patches, features, ideas + +[Complete list of contributors on GitHub](https://github.com/httpie/httpie/graphs/contributors) + +- [Cláudia T. Delgado](https://github.com/claudiatd) +- [Hank Gay](https://github.com/gthank) +- [Jake Basile](https://github.com/jakebasile) +- [Vladimir Berkutov](https://github.com/dair-targ) +- [Jakob Kramer](https://github.com/gandaro) +- [Chris Faulkner](https://github.com/faulkner) +- [Alen Mujezinovic](https://github.com/flashingpumpkin) +- [Praful Mathur](https://github.com/tictactix) +- [Marc Abramowitz](https://github.com/msabramo) +- [Ismail Badawi](https://github.com/isbadawi) +- [Laurent Bachelier](https://github.com/laurentb) +- [Isman Firmansyah](https://github.com/iromli) +- [Simon Olofsson](https://github.com/simono) +- [Churkin Oleg](https://github.com/Bahus) +- [Jökull Sólberg Auðunsson](https://github.com/jokull) +- [Matthew M. Boedicker](https://github.com/mmb) +- [marblar](https://github.com/marblar) +- [Tomek Wójcik](https://github.com/tomekwojcik) +- [Davey Shafik](https://github.com/dshafik) +- [cido](https://github.com/cido) +- [Justin Bonnar](https://github.com/jargonjustin) +- [Nathan LaFreniere](https://github.com/nlf) +- [Matthias Lehmann](https://github.com/matleh) +- [Dennis Brakhane](https://github.com/brakhane) +- [Matt Layman](https://github.com/mblayman) +- [Edward Yang](https://github.com/honorabrutroll) +- [Aleksandr Vinokurov](https://github.com/aleksandr-vin) +- [Jeff Byrnes](https://github.com/jeffbyrnes) +- [Denis Belavin](https://github.com/LuckyDenis) +- [Mickaël Schoentgen](https://github.com/BoboTiG) +- [Elena Lape](https://github.com/elenalape) +- [Rohit Sehgal](https://github.com/r0hi7) +- [Bartłomiej Jacak](https://github.com/bartekjacak) diff --git a/AUTHORS.rst b/AUTHORS.rst deleted file mode 100644 index b32563a1be..0000000000 --- a/AUTHORS.rst +++ /dev/null @@ -1,43 +0,0 @@ -============== -HTTPie authors -============== - -* `Jakub Roztocil `_ - - -Patches and ideas ------------------ - -`Complete list of contributors on GitHub `_ - -* `Cláudia T. Delgado `_ (logo) -* `Hank Gay `_ -* `Jake Basile `_ -* `Vladimir Berkutov `_ -* `Jakob Kramer `_ -* `Chris Faulkner `_ -* `Alen Mujezinovic `_ -* `Praful Mathur `_ -* `Marc Abramowitz `_ -* `Ismail Badawi `_ -* `Laurent Bachelier `_ -* `Isman Firmansyah `_ -* `Simon Olofsson `_ -* `Churkin Oleg `_ -* `Jökull Sólberg Auðunsson `_ -* `Matthew M. Boedicker `_ -* `marblar `_ -* `Tomek Wójcik `_ -* `Davey Shafik `_ -* `cido `_ -* `Justin Bonnar `_ -* `Nathan LaFreniere `_ -* `Matthias Lehmann `_ -* `Dennis Brakhane `_ -* `Matt Layman `_ -* `Edward Yang `_ -* `Aleksandr Vinokurov `_ -* `Jeff Byrnes `_ -* `Denis Belavin `_ -* `Mickaël Schoentgen `_ -* `Rohit Sehgal `_ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..850784ddc3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,367 @@ +# Change Log + +This document records all notable changes to [HTTPie](https://httpie.io). +This project adheres to [Semantic Versioning](https://semver.org/). + +## [2.5.0-dev](https://github.com/httpie/httpie/compare/2.4.0...master) (unreleased) + +- Added `--raw` to allow specifying the raw request body without extra processing as + an alternative to `stdin`. ([#534](https://github.com/httpie/httpie/issues/534)) +- Added support for XML formatting. ([#1129](https://github.com/httpie/httpie/issues/1129)) +- Added internal support for file-like object responses to improve adapter plugin support. ([#1094](https://github.com/httpie/httpie/issues/1094)) +- Fixed `--continue --download` with a single byte to be downloaded left. ([#1032](https://github.com/httpie/httpie/issues/1032)) +- Fixed `--verbose` HTTP 307 redirects with streamed request body. ([#1088](https://github.com/httpie/httpie/issues/1088)) +- Fixed handling of session files with `Cookie:` followed by other headers. ([#1126](https://github.com/httpie/httpie/issues/1126)) + +## [2.4.0](https://github.com/httpie/httpie/compare/2.3.0...2.4.0) (2021-02-06) + +- Added support for `--session` cookie expiration based on `Set-Cookie: max-age=`. ([#1029](https://github.com/httpie/httpie/issues/1029)) +- Show a `--check-status` warning with `--quiet` as well, not only when the output is redirected. ([#1026](https://github.com/httpie/httpie/issues/1026)) +- Fixed upload with `--session` ([#1020](https://github.com/httpie/httpie/issues/1020)). +- Fixed a missing blank line between request and response ([#1006](https://github.com/httpie/httpie/issues/1006)). + +## [2.3.0](https://github.com/httpie/httpie/compare/2.2.0...2.3.0) (2020-10-25) + +- Added support for streamed uploads ([#201](https://github.com/httpie/httpie/issues/201)). +- Added support for multipart upload streaming ([#684](https://github.com/httpie/httpie/issues/684)). +- Added support for body-from-file upload streaming (`http pie.dev/post @file`). +- Added `--chunked` to enable chunked transfer encoding ([#753](https://github.com/httpie/httpie/issues/753)). +- Added `--multipart` to allow `multipart/form-data` encoding for non-file `--form` requests as well. +- Added support for preserving field order in multipart requests ([#903](https://github.com/httpie/httpie/issues/903)). +- Added `--boundary` to allow a custom boundary string for `multipart/form-data` requests. +- Added support for combining cookies specified on the CLI and in a session file ([#932](https://github.com/httpie/httpie/issues/932)). +- Added out of the box SOCKS support with no extra installation ([#904](https://github.com/httpie/httpie/issues/904)). +- Added `--quiet, -q` flag to enforce silent behaviour. +- Fixed the handling of invalid `expires` dates in `Set-Cookie` headers ([#963](https://github.com/httpie/httpie/issues/963)). +- Removed Tox testing entirely ([#943](https://github.com/httpie/httpie/issues/943)). + +## [2.2.0](https://github.com/httpie/httpie/compare/2.1.0...2.2.0) (2020-06-18) + +- Added support for custom content types for uploaded files ([#668](https://github.com/httpie/httpie/issues/668)). +- Added support for `$XDG_CONFIG_HOME` ([#920](https://github.com/httpie/httpie/issues/920)). +- Added support for `Set-Cookie`-triggered cookie expiration ([#853](https://github.com/httpie/httpie/issues/853)). +- Added `--format-options` to allow disabling sorting, etc. ([#128](https://github.com/httpie/httpie/issues/128)) +- Added `--sorted` and `--unsorted` shortcuts for (un)setting all sorting-related `--format-options`. ([#128](https://github.com/httpie/httpie/issues/128)) +- Added `--ciphers` to allow configuring OpenSSL ciphers ([#870](https://github.com/httpie/httpie/issues/870)). +- Added `netrc` support for auth plugins. Enabled for `--auth-type=basic` + and `digest`, 3rd parties may opt in ([#718](https://github.com/httpie/httpie/issues/718), [#719](https://github.com/httpie/httpie/issues/719), [#852](https://github.com/httpie/httpie/issues/852), [#934](https://github.com/httpie/httpie/issues/934)). +- Fixed built-in plugins-related circular imports ([#925](https://github.com/httpie/httpie/issues/925)). + +## [2.1.0](https://github.com/httpie/httpie/compare/2.0.0...2.1.0) (2020-04-18) + +- Added `--path-as-is` to bypass dot segment (`/../` or `/./`) + URL squashing ([#895](https://github.com/httpie/httpie/issues/895)). +- Changed the default `Accept` header value for JSON requests from + `application/json, */*` to `application/json, */*;q=0.5` + to clearly indicate preference ([#488](https://github.com/httpie/httpie/issues/488)). +- Fixed `--form` file upload mixed with redirected `stdin` error handling + ([#840](https://github.com/httpie/httpie/issues/840)). + +## [2.0.0](https://github.com/httpie/httpie/compare/1.0.3...2.0.0) (2020-01-12) + +- Removed Python 2.7 support ([EOL Jan 2020](https://www.python.org/doc/sunset-python-2/). +- Added `--offline` to allow building an HTTP request and printing it but not + actually sending it over the network. +- Replaced the old collect-all-then-process handling of HTTP communication + with one-by-one processing of each HTTP request or response as they become + available. This means that you can see headers immediately, + see what is being sent even if the request fails, etc. +- Removed automatic config file creation to avoid concurrency issues. +- Removed the default 30-second connection `--timeout` limit. +- Removed Python’s default limit of 100 response headers. +- Added `--max-headers` to allow setting the max header limit. +- Added `--compress` to allow request body compression. +- Added `--ignore-netrc` to allow bypassing credentials from `.netrc`. +- Added `https` alias command with `https://` as the default scheme. +- Added `$ALL_PROXY` documentation. +- Added type annotations throughout the codebase. +- Added `tests/` to the PyPi package for the convenience of + downstream package maintainers. +- Fixed an error when `stdin` was a closed fd. +- Improved `--debug` output formatting. + +## [1.0.3](https://github.com/httpie/httpie/compare/1.0.2...1.0.3) (2019-08-26) + +- Fixed CVE-2019-10751 — the way the output filename is generated for + `--download` requests without `--output` resulting in a redirect has + been changed to only consider the initial URL as the base for the generated + filename, and not the final one. This fixes a potential security issue under + the following scenario: + + 1. A `--download` request with no explicit `--output` is made (e.g., + `$ http -d example.org/file.txt`), instructing httpie to + [generate the output filename](https://httpie.org/doc#downloaded-filename) + from the `Content-Disposition` response header, or from the URL if the header + is not provided. + 2. The server handling the request has been modified by an attacker and + instead of the expected response the URL returns a redirect to another + URL, e.g., `attacker.example.org/.bash_profile`, whose response does + not provide a `Content-Disposition` header (i.e., the base for the + generated filename becomes `.bash_profile` instead of `file.txt`). + 3. Your current directory doesn’t already contain `.bash_profile` + (i.e., no unique suffix is added to the generated filename). + 4. You don’t notice the potentially unexpected output filename + as reported by httpie in the console output + (e.g., `Downloading 100.00 B to ".bash_profile"`). + + Reported by Raul Onitza and Giulio Comi. + +## [1.0.2](https://github.com/httpie/httpie/compare/1.0.1...1.0.2) (2018-11-14) + +- Fixed tests for installation with pyOpenSSL. + +## [1.0.1](https://github.com/httpie/httpie/compare/1.0.0...1.0.1) (2018-11-14) + +- Removed external URL calls from tests. + +## [1.0.0](https://github.com/httpie/httpie/compare/0.9.9...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](https://github.com/httpie/httpie/compare/0.9.8...0.9.9) (2016-12-08) + +- Fixed README. + +## [0.9.8](https://github.com/httpie/httpie/compare/0.9.6...0.9.8) (2016-12-08) + +- Extended auth plugin API. +- Added exit status code `7` for plugin errors. +- Added support for `curses`-less Python installations. +- Fixed `REQUEST_ITEM` arg incorrectly being reported as required. +- Improved `CTRL-C` interrupt handling. +- Added the standard exit status code `130` for keyboard interrupts. + +## [0.9.6](https://github.com/httpie/httpie/compare/0.9.4...0.9.6) (2016-08-13) + +- Added Python 3 as a dependency for Homebrew installations + to ensure some of the newer HTTP features work out of the box + for macOS users (starting with HTTPie 0.9.4.). +- Added the ability to unset a request header with `Header:`, and send an + empty value with `Header;`. +- Added `--default-scheme ` to enable things like + `$ alias https='http --default-scheme=https`. +- Added `-I` as a shortcut for `--ignore-stdin`. +- Added fish shell completion (located in `extras/httpie-completion.fish` + in the GitHub repo). +- Updated `requests` to 2.10.0 so that SOCKS support can be added via + `pip install requests[socks]`. +- Changed the default JSON `Accept` header from `application/json` + to `application/json, */*`. +- Changed the pre-processing of request HTTP headers so that any leading + and trailing whitespace is removed. + +## [0.9.4](https://github.com/httpie/httpie/compare/0.9.3...0.9.4) (2016-07-01) + +- Added `Content-Type` of files uploaded in `multipart/form-data` requests +- Added `--ssl=` to specify the desired SSL/TLS protocol version + to use for HTTPS requests. +- Added JSON detection with `--json, -j` to work around incorrect + `Content-Type` +- Added `--all` to show intermediate responses such as redirects (with `--follow`) +- Added `--history-print, -P WHAT` to specify formatting of intermediate responses +- Added `--max-redirects=N` (default 30) +- Added `-A` as short name for `--auth-type` +- Added `-F` as short name for `--follow` +- Removed the `implicit_content_type` config option + (use `"default_options": ["--form"]` instead) +- Redirected `stdout` doesn't trigger an error anymore when `--output FILE` + is set +- Changed the default `--style` back to `solarized` for better support + of light and dark terminals +- Improved `--debug` output +- Fixed `--session` when used with `--download` +- Fixed `--download` to trim too long filenames before saving the file +- Fixed the handling of `Content-Type` with multiple `+subtype` parts +- Removed the XML formatter as the implementation suffered from multiple issues + +## [0.9.3](https://github.com/httpie/httpie/compare/0.9.2...0.9.3) (2016-01-01) + +- Changed the default color `--style` from `solarized` to `monokai` +- Added basic Bash autocomplete support (need to be installed manually) +- Added request details to connection error messages +- Fixed `'requests.packages.urllib3' has no attribute 'disable_warnings'` + errors that occurred in some installations +- Fixed colors and formatting on Windows +- Fixed `--auth` prompt on Windows + +## [0.9.2](https://github.com/httpie/httpie/compare/0.9.1...0.9.2) (2015-02-24) + +- Fixed compatibility with Requests 2.5.1 +- Changed the default JSON `Content-Type` to `application/json` as UTF-8 + is the default JSON encoding + +## [0.9.1](https://github.com/httpie/httpie/compare/0.9.0...0.9.1) (2015-02-07) + +- Added support for Requests transport adapter plugins + (see [httpie-unixsocket](https://github.com/httpie/httpie-unixsocket) + and [httpie-http2](https://github.com/httpie/httpie-http2)) + +## [0.9.0](https://github.com/httpie/httpie/compare/0.8.0...0.9.0) (2015-01-31) + +- Added `--cert` and `--cert-key` parameters to specify a client side + certificate and private key for SSL +- Improved unicode support +- Improved terminal color depth detection via `curses` +- To make it easier to deal with Windows paths in request items, `\` + now only escapes special characters (the ones that are used as key-value + separators by HTTPie) +- Switched from `unittest` to `pytest` +- Added Python `wheel` support +- Various test suite improvements +- Added `CONTRIBUTING` +- Fixed `User-Agent` overwriting when used within a session +- Fixed handling of empty passwords in URL credentials +- Fixed multiple file uploads with the same form field name +- Fixed `--output=/dev/null` on Linux +- Miscellaneous bugfixes + +## [0.8.0](https://github.com/httpie/httpie/compare/0.7.1...0.8.0) (2014-01-25) + +- Added `field=@file.txt` and `field:=@file.json` for embedding + the contents of text and JSON files into request data +- Added curl-style shorthand for localhost +- Fixed request `Host` header value output so that it doesn't contain + credentials, if included in the URL + +## [0.7.1](https://github.com/httpie/httpie/compare/0.6.0...0.7.1) (2013-09-24) + +- Added `--ignore-stdin` +- Added support for auth plugins +- Improved `--help` output +- Improved `Content-Disposition` parsing for `--download` mode +- Update to Requests 2.0.0 + +## [0.6.0](https://github.com/httpie/httpie/compare/0.5.1...0.6.0) (2013-06-03) + +- XML data is now formatted +- `--session` and `--session-read-only` now also accept paths to + session files (eg. `http --session=/tmp/session.json example.org`) + +## [0.5.1](https://github.com/httpie/httpie/compare/0.5.0...0.5.1) (2013-05-13) + +- `Content-*` and `If-*` request headers are not stored in sessions + anymore as they are request-specific + +## [0.5.0](https://github.com/httpie/httpie/compare/0.4.1...0.5.0) (2013-04-27) + +- Added a download mode via `--download` +- Fixes miscellaneous bugs + +## [0.4.1](https://github.com/httpie/httpie/compare/0.4.0...0.4.1) (2013-02-26) + +- Fixed `setup.py` + +## [0.4.0](https://github.com/httpie/httpie/compare/0.3.0...0.4.0) (2013-02-22) + +- Added Python 3.3 compatibility +- Added Requests >= v1.0.4 compatibility +- Added support for credentials in URL +- Added `--no-option` for every `--option` to be config-friendly +- Mutually exclusive arguments can be specified multiple times. The + last value is used + +## [0.3.0](https://github.com/httpie/httpie/compare/0.2.7...0.3.0) (2012-09-21) + +- Allow output redirection on Windows +- Added configuration file +- Added persistent session support +- Renamed `--allow-redirects` to `--follow` +- Improved the usability of `http --help` +- Fixed installation on Windows with Python 3 +- Fixed colorized output on Windows with Python 3 +- CRLF HTTP header field separation in the output +- Added exit status code `2` for timed-out requests +- Added the option to separate colorizing and formatting + (`--pretty=all`, `--pretty=colors` and `--pretty=format`) + `--ugly` has bee removed in favor of `--pretty=none` + +## [0.2.7](https://github.com/httpie/httpie/compare/0.2.5...0.2.7) (2012-08-07) + +- Added compatibility with Requests 0.13.6 +- Added streamed terminal output. `--stream, -S` can be used to enable + streaming also with `--pretty` and to ensure a more frequent output + flushing +- Added support for efficient large file downloads +- Sort headers by name (unless `--pretty=none`) +- Response body is fetched only when needed (e.g., not with `--headers`) +- Improved content type matching +- Updated Solarized color scheme +- Windows: Added `--output FILE` to store output into a file + (piping results in corrupted data on Windows) +- Proper handling of binary requests and responses +- Fixed printing of `multipart/form-data` requests +- Renamed `--traceback` to `--debug` + +## [0.2.6](https://github.com/httpie/httpie/compare/0.2.5...0.2.6) (2012-07-26) + +- The short option for `--headers` is now `-h` (`-t` has been + removed, for usage use `--help`) +- Form data and URL parameters can have multiple fields with the same name + (e.g.,`http -f url a=1 a=2`) +- Added `--check-status` to exit with an error on HTTP 3xx, 4xx and + 5xx (3, 4, and 5, respectively) +- If the output is piped to another program or redirected to a file, + the default behaviour is to only print the response body + (It can still be overwritten via the `--print` flag.) +- Improved highlighting of HTTP headers +- Added query string parameters (`param==value`) +- Added support for terminal colors under Windows + +## [0.2.5](https://github.com/httpie/httpie/compare/0.2.2...0.2.5) (2012-07-17) + +- Unicode characters in prettified JSON now don't get escaped for + improved readability +- --auth now prompts for a password if only a username provided +- Added support for request payloads from a file path with automatic + `Content-Type` (`http URL @/path`) +- Fixed missing query string when displaying the request headers via + `--verbose` +- Fixed Content-Type for requests with no data + +## [0.2.2](https://github.com/httpie/httpie/compare/0.2.1...0.2.2) (2012-06-24) + +- The `METHOD` positional argument can now be omitted (defaults to + `GET`, or to `POST` with data) +- Fixed --verbose --form +- Added support for Tox + +## [0.2.1](https://github.com/httpie/httpie/compare/0.2.0...0.2.1) (2012-06-13) + +- Added compatibility with `requests-0.12.1` +- Dropped custom JSON and HTTP lexers in favor of the ones newly included + in `pygments-1.5` + +## [0.2.0](https://github.com/httpie/httpie/compare/0.1.6...0.2.0) (2012-04-25) + +- Added Python 3 support +- Added the ability to print the HTTP request as well as the response + (see `--print` and `--verbose`) +- Added support for Digest authentication +- Added file upload support + (`http -f POST file_field_name@/path/to/file`) +- Improved syntax highlighting for JSON +- Added support for field name escaping +- Many bug fixes + +## [0.1.6](https://github.com/httpie/httpie/compare/0.1.5...0.1.6) (2012-03-04) + +- Fixed `setup.py` + +## [0.1.5](https://github.com/httpie/httpie/compare/0.1.4...0.1.5) (2012-03-04) + +- Many improvements and bug fixes + +## [0.1.4](https://github.com/httpie/httpie/compare/b966efa...0.1.4) (2012-02-28) + +- Many improvements and bug fixes + +## [0.1.0](https://github.com/httpie/httpie/commit/b966efa) (2012-02-25) + +- Initial public release diff --git a/CHANGELOG.rst b/CHANGELOG.rst deleted file mode 100644 index d99e5f00ab..0000000000 --- a/CHANGELOG.rst +++ /dev/null @@ -1,511 +0,0 @@ -========== -Change Log -========== - -This document records all notable changes to `HTTPie `_. -This project adheres to `Semantic Versioning `_. - - - -`2.5.0-dev`_ (unreleased) -------------------------- -* Added ``--raw`` to allow specifying the raw request body without extra processing as - an alternative to ``stdin``. (`#534`_) -* Added support for XML formatting. (`#1129`_) -* Added internal support for file-like object responses to improve adapter plugin support. (`#1094`_) -* Fixed ``--continue --download`` with a single byte to be downloaded left. (`#1032`_) -* Fixed ``--verbose`` HTTP 307 redirects with streamed request body. (`#1088`_) -* Fixed handling of session files with ``Cookie:`` followed by other headers. (`#1126`_) - - -`2.4.0`_ (2021-02-06) ---------------------- -* Added support for ``--session`` cookie expiration based on ``Set-Cookie: max-age=``. (`#1029`_) -* Show a ``--check-status`` warning with ``--quiet`` as well, not only when the output is redirected. (`#1026`_) -* Fixed upload with ``--session`` (`#1020`_). -* Fixed a missing blank line between request and response (`#1006`_). - - -`2.3.0`_ (2020-10-25) -------------------------- - -* Added support for streamed uploads (`#201`_). -* Added support for multipart upload streaming (`#684`_). -* Added support for body-from-file upload streaming (``http pie.dev/post @file``). -* Added ``--chunked`` to enable chunked transfer encoding (`#753`_). -* Added ``--multipart`` to allow ``multipart/form-data`` encoding for non-file ``--form`` requests as well. -* Added support for preserving field order in multipart requests (`#903`_). -* Added ``--boundary`` to allow a custom boundary string for ``multipart/form-data`` requests. -* Added support for combining cookies specified on the CLI and in a session file (`#932`_). -* Added out of the box SOCKS support with no extra installation (`#904`_). -* Added ``--quiet, -q`` flag to enforce silent behaviour. -* Fixed the handling of invalid ``expires`` dates in ``Set-Cookie`` headers (`#963`_). -* Removed Tox testing entirely (`#943`_). - - -`2.2.0`_ (2020-06-18) -------------------------- - -* Added support for custom content types for uploaded files (`#668`_). -* Added support for ``$XDG_CONFIG_HOME`` (`#920`_). -* Added support for ``Set-Cookie``-triggered cookie expiration (`#853`_). -* Added ``--format-options`` to allow disabling sorting, etc. (`#128`_) -* Added ``--sorted`` and ``--unsorted`` shortcuts for (un)setting all sorting-related ``--format-options``. (`#128`_) -* Added ``--ciphers`` to allow configuring OpenSSL ciphers (`#870`_). -* Added ``netrc`` support for auth plugins. Enabled for ``--auth-type=basic`` - and ``digest``, 3rd parties may opt in (`#718`_, `#719`_, `#852`_, `#934`_). -* Fixed built-in plugins-related circular imports (`#925`_). - - -`2.1.0`_ (2020-04-18) ---------------------- - -* Added ``--path-as-is`` to bypass dot segment (``/../`` or ``/./``) - URL squashing (`#895`_). -* Changed the default ``Accept`` header value for JSON requests from - ``application/json, */*`` to ``application/json, */*;q=0.5`` - to clearly indicate preference (`#488`_). -* Fixed ``--form`` file upload mixed with redirected ``stdin`` error handling - (`#840`_). - - -`2.0.0`_ (2020-01-12) -------------------------- -* Removed Python 2.7 support (`EOL Jan 2020 `_). -* Added ``--offline`` to allow building an HTTP request and printing it but not - actually sending it over the network. -* Replaced the old collect-all-then-process handling of HTTP communication - with one-by-one processing of each HTTP request or response as they become - available. This means that you can see headers immediately, - see what is being sent even if the request fails, etc. -* Removed automatic config file creation to avoid concurrency issues. -* Removed the default 30-second connection ``--timeout`` limit. -* Removed Python’s default limit of 100 response headers. -* Added ``--max-headers`` to allow setting the max header limit. -* Added ``--compress`` to allow request body compression. -* Added ``--ignore-netrc`` to allow bypassing credentials from ``.netrc``. -* Added ``https`` alias command with ``https://`` as the default scheme. -* Added ``$ALL_PROXY`` documentation. -* Added type annotations throughout the codebase. -* Added ``tests/`` to the PyPi package for the convenience of - downstream package maintainers. -* Fixed an error when ``stdin`` was a closed fd. -* Improved ``--debug`` output formatting. - - -`1.0.3`_ (2019-08-26) ---------------------- - -* Fixed CVE-2019-10751 — the way the output filename is generated for - ``--download`` requests without ``--output`` resulting in a redirect has - been changed to only consider the initial URL as the base for the generated - filename, and not the final one. This fixes a potential security issue under - the following scenario: - - 1. A ``--download`` request with no explicit ``--output`` is made (e.g., - ``$ http -d example.org/file.txt``), instructing httpie to - `generate the output filename `_ - from the ``Content-Disposition`` response header, or from the URL if the header - is not provided. - 2. The server handling the request has been modified by an attacker and - instead of the expected response the URL returns a redirect to another - URL, e.g., ``attacker.example.org/.bash_profile``, whose response does - not provide a ``Content-Disposition`` header (i.e., the base for the - generated filename becomes ``.bash_profile`` instead of ``file.txt``). - 3. Your current directory doesn’t already contain ``.bash_profile`` - (i.e., no unique suffix is added to the generated filename). - 4. You don’t notice the potentially unexpected output filename - as reported by httpie in the console output - (e.g., ``Downloading 100.00 B to ".bash_profile"``). - - Reported by Raul Onitza and Giulio Comi. - - -`1.0.2`_ (2018-11-14) -------------------------- - -* Fixed tests for installation with pyOpenSSL. - - -`1.0.1`_ (2018-11-14) -------------------------- - -* Removed external URL calls from tests. - - -`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) ---------------------- - -* Extended auth plugin API. -* Added exit status code ``7`` for plugin errors. -* Added support for ``curses``-less Python installations. -* Fixed ``REQUEST_ITEM`` arg incorrectly being reported as required. -* Improved ``CTRL-C`` interrupt handling. -* Added the standard exit status code ``130`` for keyboard interrupts. - - -`0.9.6`_ (2016-08-13) ---------------------- - -* Added Python 3 as a dependency for Homebrew installations - to ensure some of the newer HTTP features work out of the box - for macOS users (starting with HTTPie 0.9.4.). -* Added the ability to unset a request header with ``Header:``, and send an - empty value with ``Header;``. -* Added ``--default-scheme `` to enable things like - ``$ alias https='http --default-scheme=https``. -* Added ``-I`` as a shortcut for ``--ignore-stdin``. -* Added fish shell completion (located in ``extras/httpie-completion.fish`` - in the GitHub repo). -* Updated ``requests`` to 2.10.0 so that SOCKS support can be added via - ``python -m pip install requests[socks]``. -* Changed the default JSON ``Accept`` header from ``application/json`` - to ``application/json, */*``. -* Changed the pre-processing of request HTTP headers so that any leading - and trailing whitespace is removed. - - -`0.9.4`_ (2016-07-01) ---------------------- - -* Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests -* Added ``--ssl=`` to specify the desired SSL/TLS protocol version - to use for HTTPS requests. -* Added JSON detection with ``--json, -j`` to work around incorrect - ``Content-Type`` -* Added ``--all`` to show intermediate responses such as redirects (with ``--follow``) -* Added ``--history-print, -P WHAT`` to specify formatting of intermediate responses -* Added ``--max-redirects=N`` (default 30) -* Added ``-A`` as short name for ``--auth-type`` -* Added ``-F`` as short name for ``--follow`` -* Removed the ``implicit_content_type`` config option - (use ``"default_options": ["--form"]`` instead) -* Redirected ``stdout`` doesn't trigger an error anymore when ``--output FILE`` - is set -* Changed the default ``--style`` back to ``solarized`` for better support - of light and dark terminals -* Improved ``--debug`` output -* Fixed ``--session`` when used with ``--download`` -* Fixed ``--download`` to trim too long filenames before saving the file -* Fixed the handling of ``Content-Type`` with multiple ``+subtype`` parts -* Removed the XML formatter as the implementation suffered from multiple issues - - - -`0.9.3`_ (2016-01-01) ---------------------- - -* Changed the default color ``--style`` from ``solarized`` to ``monokai`` -* Added basic Bash autocomplete support (need to be installed manually) -* Added request details to connection error messages -* Fixed ``'requests.packages.urllib3' has no attribute 'disable_warnings'`` - errors that occurred in some installations -* Fixed colors and formatting on Windows -* Fixed ``--auth`` prompt on Windows - - -`0.9.2`_ (2015-02-24) ---------------------- - -* Fixed compatibility with Requests 2.5.1 -* Changed the default JSON ``Content-Type`` to ``application/json`` as UTF-8 - is the default JSON encoding - - -`0.9.1`_ (2015-02-07) ---------------------- - -* Added support for Requests transport adapter plugins - (see `httpie-unixsocket `_ - and `httpie-http2 `_) - - -`0.9.0`_ (2015-01-31) ---------------------- - -* Added ``--cert`` and ``--cert-key`` parameters to specify a client side - certificate and private key for SSL -* Improved unicode support -* Improved terminal color depth detection via ``curses`` -* To make it easier to deal with Windows paths in request items, ``\`` - now only escapes special characters (the ones that are used as key-value - separators by HTTPie) -* Switched from ``unittest`` to ``pytest`` -* Added Python `wheel` support -* Various test suite improvements -* Added ``CONTRIBUTING`` -* Fixed ``User-Agent`` overwriting when used within a session -* Fixed handling of empty passwords in URL credentials -* Fixed multiple file uploads with the same form field name -* Fixed ``--output=/dev/null`` on Linux -* Miscellaneous bugfixes - - -`0.8.0`_ (2014-01-25) ---------------------- - -* Added ``field=@file.txt`` and ``field:=@file.json`` for embedding - the contents of text and JSON files into request data -* Added curl-style shorthand for localhost -* Fixed request ``Host`` header value output so that it doesn't contain - credentials, if included in the URL - - -`0.7.1`_ (2013-09-24) ---------------------- - -* Added ``--ignore-stdin`` -* Added support for auth plugins -* Improved ``--help`` output -* Improved ``Content-Disposition`` parsing for ``--download`` mode -* Update to Requests 2.0.0 - - -`0.6.0`_ (2013-06-03) ---------------------- - -* XML data is now formatted -* ``--session`` and ``--session-read-only`` now also accept paths to - session files (e.g. ``http --session=/tmp/session.json example.org``) - - -`0.5.1`_ (2013-05-13) ---------------------- - -* ``Content-*`` and ``If-*`` request headers are not stored in sessions - anymore as they are request-specific - - -`0.5.0`_ (2013-04-27) ---------------------- - -* Added a download mode via ``--download`` -* Fixes miscellaneous bugs - - -`0.4.1`_ (2013-02-26) ---------------------- - -* Fixed ``setup.py`` - - -`0.4.0`_ (2013-02-22) ---------------------- - -* Added Python 3.3 compatibility -* Added Requests >= v1.0.4 compatibility -* Added support for credentials in URL -* Added ``--no-option`` for every ``--option`` to be config-friendly -* Mutually exclusive arguments can be specified multiple times. The - last value is used - - -`0.3.0`_ (2012-09-21) ---------------------- - -* Allow output redirection on Windows -* Added configuration file -* Added persistent session support -* Renamed ``--allow-redirects`` to ``--follow`` -* Improved the usability of ``http --help`` -* Fixed installation on Windows with Python 3 -* Fixed colorized output on Windows with Python 3 -* CRLF HTTP header field separation in the output -* Added exit status code ``2`` for timed-out requests -* Added the option to separate colorizing and formatting - (``--pretty=all``, ``--pretty=colors`` and ``--pretty=format``) - ``--ugly`` has bee removed in favor of ``--pretty=none`` - - -`0.2.7`_ (2012-08-07) ---------------------- - -* Added compatibility with Requests 0.13.6 -* Added streamed terminal output. ``--stream, -S`` can be used to enable - streaming also with ``--pretty`` and to ensure a more frequent output - flushing -* Added support for efficient large file downloads -* Sort headers by name (unless ``--pretty=none``) -* Response body is fetched only when needed (e.g., not with ``--headers``) -* Improved content type matching -* Updated Solarized color scheme -* Windows: Added ``--output FILE`` to store output into a file - (piping results in corrupted data on Windows) -* Proper handling of binary requests and responses -* Fixed printing of ``multipart/form-data`` requests -* Renamed ``--traceback`` to ``--debug`` - - -`0.2.6`_ (2012-07-26) ---------------------- - -* The short option for ``--headers`` is now ``-h`` (``-t`` has been - removed, for usage use ``--help``) -* Form data and URL parameters can have multiple fields with the same name - (e.g.,``http -f url a=1 a=2``) -* Added ``--check-status`` to exit with an error on HTTP 3xx, 4xx and - 5xx (3, 4, and 5, respectively) -* If the output is piped to another program or redirected to a file, - the default behaviour is to only print the response body - (It can still be overwritten via the ``--print`` flag.) -* Improved highlighting of HTTP headers -* Added query string parameters (``param==value``) -* Added support for terminal colors under Windows - - -`0.2.5`_ (2012-07-17) ---------------------- - -* Unicode characters in prettified JSON now don't get escaped for - improved readability -* --auth now prompts for a password if only a username provided -* Added support for request payloads from a file path with automatic - ``Content-Type`` (``http URL @/path``) -* Fixed missing query string when displaying the request headers via - ``--verbose`` -* Fixed Content-Type for requests with no data - - -`0.2.2`_ (2012-06-24) ---------------------- - -* The ``METHOD`` positional argument can now be omitted (defaults to - ``GET``, or to ``POST`` with data) -* Fixed --verbose --form -* Added support for Tox - - -`0.2.1`_ (2012-06-13) ---------------------- - -* Added compatibility with ``requests-0.12.1`` -* Dropped custom JSON and HTTP lexers in favor of the ones newly included - in ``pygments-1.5`` - - -`0.2.0`_ (2012-04-25) ---------------------- - -* Added Python 3 support -* Added the ability to print the HTTP request as well as the response - (see ``--print`` and ``--verbose``) -* Added support for Digest authentication -* Added file upload support - (``http -f POST file_field_name@/path/to/file``) -* Improved syntax highlighting for JSON -* Added support for field name escaping -* Many bug fixes - - -`0.1.6`_ (2012-03-04) ---------------------- - -* Fixed ``setup.py`` - - -`0.1.5`_ (2012-03-04) ---------------------- - -* Many improvements and bug fixes - - -`0.1.4`_ (2012-02-28) ---------------------- - -* Many improvements and bug fixes - - -`0.1.0`_ (2012-02-25) ---------------------- - -* Initial public release - - -.. _`0.1.0`: https://github.com/httpie/httpie/commit/b966efa -.. _0.1.4: https://github.com/httpie/httpie/compare/b966efa...0.1.4 -.. _0.1.5: https://github.com/httpie/httpie/compare/0.1.4...0.1.5 -.. _0.1.6: https://github.com/httpie/httpie/compare/0.1.5...0.1.6 -.. _0.2.0: https://github.com/httpie/httpie/compare/0.1.6...0.2.0 -.. _0.2.1: https://github.com/httpie/httpie/compare/0.2.0...0.2.1 -.. _0.2.2: https://github.com/httpie/httpie/compare/0.2.1...0.2.2 -.. _0.2.5: https://github.com/httpie/httpie/compare/0.2.2...0.2.5 -.. _0.2.6: https://github.com/httpie/httpie/compare/0.2.5...0.2.6 -.. _0.2.7: https://github.com/httpie/httpie/compare/0.2.5...0.2.7 -.. _0.3.0: https://github.com/httpie/httpie/compare/0.2.7...0.3.0 -.. _0.4.0: https://github.com/httpie/httpie/compare/0.3.0...0.4.0 -.. _0.4.1: https://github.com/httpie/httpie/compare/0.4.0...0.4.1 -.. _0.5.0: https://github.com/httpie/httpie/compare/0.4.1...0.5.0 -.. _0.5.1: https://github.com/httpie/httpie/compare/0.5.0...0.5.1 -.. _0.6.0: https://github.com/httpie/httpie/compare/0.5.1...0.6.0 -.. _0.7.1: https://github.com/httpie/httpie/compare/0.6.0...0.7.1 -.. _0.8.0: https://github.com/httpie/httpie/compare/0.7.1...0.8.0 -.. _0.9.0: https://github.com/httpie/httpie/compare/0.8.0...0.9.0 -.. _0.9.1: https://github.com/httpie/httpie/compare/0.9.0...0.9.1 -.. _0.9.2: https://github.com/httpie/httpie/compare/0.9.1...0.9.2 -.. _0.9.3: https://github.com/httpie/httpie/compare/0.9.2...0.9.3 -.. _0.9.4: https://github.com/httpie/httpie/compare/0.9.3...0.9.4 -.. _0.9.6: https://github.com/httpie/httpie/compare/0.9.4...0.9.6 -.. _0.9.8: https://github.com/httpie/httpie/compare/0.9.6...0.9.8 -.. _0.9.9: https://github.com/httpie/httpie/compare/0.9.8...0.9.9 -.. _1.0.0: https://github.com/httpie/httpie/compare/0.9.9...1.0.0 -.. _1.0.1: https://github.com/httpie/httpie/compare/1.0.0...1.0.1 -.. _1.0.2: https://github.com/httpie/httpie/compare/1.0.1...1.0.2 -.. _1.0.3: https://github.com/httpie/httpie/compare/1.0.2...1.0.3 -.. _2.0.0: https://github.com/httpie/httpie/compare/1.0.3...2.0.0 -.. _2.1.0: https://github.com/httpie/httpie/compare/2.0.0...2.1.0 -.. _2.2.0: https://github.com/httpie/httpie/compare/2.1.0...2.2.0 -.. _2.3.0: https://github.com/httpie/httpie/compare/2.2.0...2.3.0 -.. _2.4.0: https://github.com/httpie/httpie/compare/2.3.0...2.4.0 -.. _2.5.0-dev: https://github.com/httpie/httpie/compare/2.4.0...master - -.. _#128: https://github.com/httpie/httpie/issues/128 -.. _#201: https://github.com/httpie/httpie/issues/201 -.. _#488: https://github.com/httpie/httpie/issues/488 -.. _#534: https://github.com/httpie/httpie/issues/534 -.. _#668: https://github.com/httpie/httpie/issues/668 -.. _#684: https://github.com/httpie/httpie/issues/684 -.. _#718: https://github.com/httpie/httpie/issues/718 -.. _#719: https://github.com/httpie/httpie/issues/719 -.. _#753: https://github.com/httpie/httpie/issues/753 -.. _#840: https://github.com/httpie/httpie/issues/840 -.. _#853: https://github.com/httpie/httpie/issues/853 -.. _#852: https://github.com/httpie/httpie/issues/852 -.. _#870: https://github.com/httpie/httpie/issues/870 -.. _#895: https://github.com/httpie/httpie/issues/895 -.. _#903: https://github.com/httpie/httpie/issues/903 -.. _#920: https://github.com/httpie/httpie/issues/920 -.. _#904: https://github.com/httpie/httpie/issues/904 -.. _#925: https://github.com/httpie/httpie/issues/925 -.. _#932: https://github.com/httpie/httpie/issues/932 -.. _#934: https://github.com/httpie/httpie/issues/934 -.. _#943: https://github.com/httpie/httpie/issues/943 -.. _#963: https://github.com/httpie/httpie/issues/963 -.. _#1006: https://github.com/httpie/httpie/issues/1006 -.. _#1020: https://github.com/httpie/httpie/issues/1020 -.. _#1026: https://github.com/httpie/httpie/issues/1026 -.. _#1029: https://github.com/httpie/httpie/issues/1029 -.. _#1032: https://github.com/httpie/httpie/issues/1032 -.. _#1088: https://github.com/httpie/httpie/issues/1088 -.. _#1094: https://github.com/httpie/httpie/issues/1094 -.. _#1126: https://github.com/httpie/httpie/issues/1126 -.. _#1129: https://github.com/httpie/httpie/issues/1129 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 2bc4be3772..156e17407d 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -14,22 +14,22 @@ appearance, race, religion, or sexual identity and orientation. Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting ## Our Responsibilities @@ -67,10 +67,8 @@ members of the project's leadership. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), +version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..76a8206236 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,196 @@ +# Contributing to HTTPie + +Bug reports and code and documentation patches are welcome. You can +help this project also by using the development version of HTTPie +and by reporting any bugs you might encounter. + +## 1. Reporting bugs + +**It's important that you provide the full command argument list +as well as the output of the failing command.** + +Use the `--debug` flag and copy&paste both the command and its output +to your bug report, e.g.: + +```bash +$ http --debug + +``` + +## 2. Contributing Code and Docs + +Before working on a new feature or a bug, please browse [existing issues](https://github.com/httpie/httpie/issues) +to see whether it has previously been discussed. + +If your change alters HTTPie’s behaviour or interface, it's a good idea to +discuss it before you start working on it. + +If you are fixing an issue, the first step should be to create a test case that +reproduces the incorrect behaviour. That will also help you to build an +understanding of the issue at hand. + +**Pull requests introducing code changes without tests +will generally not get merged. The same goes for PRs changing HTTPie’s +behaviour and not providing documentation.** + +Conversely, PRs consisting of documentation improvements or tests +for existing-yet-previously-untested behavior will very likely be merged. +Therefore, docs and tests improvements are a great candidate for your first +contribution. + +Consider also adding a [CHANGELOG](https://github.com/httpie/httpie/blob/master/CHANGELOG.md) entry for your changes. + +### Development Environment + +#### Getting the code + +Go to https://github.com/httpie/httpie and fork the project repository. + +```bash +# Clone your fork +$ git clone git@github.com:/httpie.git + +# Enter the project directory +$ cd httpie + +# Create a branch for your changes +$ git checkout -b my_topical_branch +``` + +#### Setup + +The [Makefile](https://github.com/httpie/httpie/blob/master/Makefile) contains a bunch of tasks to get you started. Just run +the following command, which: + +- Creates an isolated Python virtual environment inside `./venv` + (via the standard library [venv](https://docs.python.org/3/library/venv.html) tool); +- installs all dependencies and also installs HTTPie + (in editable mode so that the `http` command will point to your + working copy). +- and runs tests (It is the same as running `make install test`). + +```bash +$ make +``` + +#### Python virtual environment + +Activate the Python virtual environment—created via the `make install` +task during [setup](#setup) for your active shell session using the following command: + +```bash +$ source venv/bin/activate +``` + +(If you use `virtualenvwrapper`, you can also use `workon httpie` to +activate the environment — we have created a symlink for you. It’s a bit of +a hack but it works™.) + +You should now see `(httpie)` next to your shell prompt, and +the `http` command should point to your development copy: + +``` +(httpie) ~/Code/httpie $ which http +/Users//Code/httpie/venv/bin/http +(httpie) ~/Code/httpie $ http --version +2.0.0-dev +``` + +(Btw, you don’t need to activate the virtual environment if you just want +run some of the `make` tasks. You can also invoke the development +version of HTTPie directly with `./venv/bin/http` without having to activate +the environment first. The same goes for `./venv/bin/pytest`, etc.). + +### Making Changes + +Please make sure your changes conform to [Style Guide for Python Code](https://python.org/dev/peps/pep-0008/) (PEP8) +and that `make pycodestyle` passes. + +### Testing & CI + +Please add tests for any new features and bug fixes. + +When you open a Pull Request, [GitHub Actions](https://github.com/httpie/httpie/actions) will automatically run HTTPie’s [test suite](https://github.com/httpie/httpie/tree/master/tests) against your code, so please make sure all checks pass. + +#### Running tests locally + +HTTPie uses the [pytest](https://pytest.org/) runner. + +```bash +# Run tests on the current Python interpreter with coverage. +$ make test + +# Run tests with coverage +$ make test-cover + +# Test PEP8 compliance +$ make codestyle + +# Run extended tests — for code as well as .md files syntax, packaging, etc. +$ make test-all +``` + +#### Running specific tests + +After you have activated your virtual environment (see [setup](#setup)), you +can run specific tests from the terminal: + +```bash +# Run specific tests on the current Python +$ python -m pytest tests/test_uploads.py +$ python -m pytest tests/test_uploads.py::TestMultipartFormDataFileUpload +$ python -m pytest tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok +``` + +See [Makefile](https://github.com/httpie/httpie/blob/master/Makefile) for additional development utilities. + +#### Windows + +If you are on a Windows machine and not able to run `make`, +follow the next steps for a basic setup. As a prerequisite, you need to have +Python 3.6+ installed. + +Create a virtual environment and activate it: + +```powershell +C:\> python -m venv --prompt httpie venv +C:\> venv\Scripts\activate +``` + +Install HTTPie in editable mode with all the dependencies: + +```powershell +C:\> python -m pip install --upgrade -e . -r requirements-dev.txt +``` + +You should now see `(httpie)` next to your shell prompt, and +the `http` command should point to your development copy: + +```powershell +# In PowerShell: +(httpie) PS C:\Users\ovezovs\httpie> Get-Command http +CommandType Name Version Source +----------- ---- ------- ------ +Application http.exe 0.0.0.0 C:\Users\ovezovs\httpie\venv\Scripts\http.exe +``` + +```bash +# In CMD: +(httpie) C:\Users\ovezovs\httpie> where http +C:\Users\ovezovs\httpie\venv\Scripts\http.exe +C:\Users\ovezovs\AppData\Local\Programs\Python\Python38-32\Scripts\http.exe + +(httpie) C:\Users\ovezovs\httpie> http --version +2.3.0-dev +``` + +Use `pytest` to run tests locally with an active virtual environment: + +```bash +# Run all tests +$ python -m pytest +``` + +______________________________________________________________________ + +Finally, feel free to add yourself to [AUTHORS](https://github.com/httpie/httpie/blob/master/AUTHORS.md)! diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index d1ad30ce63..0000000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,239 +0,0 @@ -###################### -Contributing to HTTPie -###################### - -Bug reports and code and documentation patches are welcome. You can -help this project also by using the development version of HTTPie -and by reporting any bugs you might encounter. - -1. Reporting bugs -================= - -**It's important that you provide the full command argument list -as well as the output of the failing command.** -Use the ``--debug`` flag and copy&paste both the command and its output -to your bug report, e.g.: - -.. code-block:: bash - - $ http --debug - - - - -2. Contributing Code and Docs -============================= - -Before working on a new feature or a bug, please browse `existing issues`_ -to see whether it has previously been discussed. - -If your change alters HTTPie’s behaviour or interface, it's a good idea to -discuss it before you start working on it. - -If you are fixing an issue, the first step should be to create a test case that -reproduces the incorrect behaviour. That will also help you to build an -understanding of the issue at hand. - -**Pull requests introducing code changes without tests -will generally not get merged. The same goes for PRs changing HTTPie’s -behaviour and not providing documentation.** - -Conversely, PRs consisting of documentation improvements or tests -for existing-yet-previously-untested behavior will very likely be merged. -Therefore, docs and tests improvements are a great candidate for your first -contribution. - -Consider also adding a ``CHANGELOG`` entry for your changes. - - -Development Environment --------------------------------- - - -Getting the code -**************** - -Go to https://github.com/httpie/httpie and fork the project repository. - - -.. code-block:: bash - - # Clone your fork - git clone git@github.com:/httpie.git - - # Enter the project directory - cd httpie - - # Create a branch for your changes - git checkout -b my_topical_branch - - -Setup -***** - -The `Makefile`_ contains a bunch of tasks to get you started. Just run -the following command, which: - - -* Creates an isolated Python virtual environment inside ``./venv`` - (via the standard library `venv`_ tool); -* installs all dependencies and also installs HTTPie - (in editable mode so that the ``http`` command will point to your - working copy). -* and runs tests (It is the same as running ``make install test``). - - -.. code-block:: bash - - make - - - -Python virtual environment -************************** - -Activate the Python virtual environment—created via the ``make install`` -task during `setup`_—for your active shell session using the following command: - -.. code-block:: bash - - source venv/bin/activate - -(If you use ``virtualenvwrapper``, you can also use ``workon httpie`` to -activate the environment — we have created a symlink for you. It’s a bit of -a hack but it works™.) - -You should now see ``(httpie)`` next to your shell prompt, and -the ``http`` command should point to your development copy: - -.. code-block:: - - (httpie) ~/Code/httpie $ which http - /Users/jakub/Code/httpie/venv/bin/http - (httpie) ~/Code/httpie $ http --version - 2.0.0-dev - -(Btw, you don’t need to activate the virtual environment if you just want -run some of the ``make`` tasks. You can also invoke the development -version of HTTPie directly with ``./venv/bin/http`` without having to activate -the environment first. The same goes for ``./venv/bin/pytest``, etc.). - - -Making Changes --------------- - -Please make sure your changes conform to `Style Guide for Python Code`_ (PEP8) -and that ``make codestyle`` passes. - - -Testing & CI ------------- - -Please add tests for any new features and bug fixes. - -When you open a pull request, -`GitHub Actions `_ -will automatically run HTTPie’s `test suite`_ against your code -so please make sure all checks pass. - - -Running tests locally -********************* - -HTTPie uses the `pytest`_ runner. - - -.. code-block:: bash - - # Run tests on the current Python interpreter with coverage. - make test - - # Run tests with coverage - make test-cover - - # Test PEP8 compliance - make codestyle - - # Run extended tests — for code as well as .rst files syntax, packaging, etc. - make test-all - - -Running specific tests -********************** - -After you have activated your virtual environment (see `setup`_), you -can run specific tests from the terminal: - -.. code-block:: bash - - # Run specific tests on the current Python - python -m pytest tests/test_uploads.py - python -m pytest tests/test_uploads.py::TestMultipartFormDataFileUpload - python -m pytest tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok - ------ - -See `Makefile`_ for additional development utilities. - -Windows -******* - -If you are on a Windows machine and not able to run ``make``, -follow the next steps for a basic setup. As a prerequisite, you need to have -Python 3.6+ installed. - -Create a virtual environment and activate it: - -.. code-block:: powershell - - python -m venv --prompt httpie venv - venv\Scripts\activate - -Install HTTPie in editable mode with all the dependencies: - -.. code-block:: powershell - - python -m pip install --upgrade --editable '.[dev]' - -You should now see ``(httpie)`` next to your shell prompt, and -the ``http`` command should point to your development copy: - -.. code-block:: powershell - - # In PowerShell: - (httpie) PS C:\Users\ovezovs\httpie> Get-Command http - CommandType Name Version Source - ----------- ---- ------- ------ - Application http.exe 0.0.0.0 C:\Users\ovezovs\httpie\venv\Scripts\http.exe - -.. code-block:: bash - - # In CMD: - (httpie) C:\Users\ovezovs\httpie> where http - C:\Users\ovezovs\httpie\venv\Scripts\http.exe - C:\Users\ovezovs\AppData\Local\Programs\Python\Python38-32\Scripts\http.exe - - (httpie) C:\Users\ovezovs\httpie> http --version - 2.3.0-dev - -Use ``pytest`` to run tests locally with an active virtual environment: - -.. code-block:: bash - - # Run all tests - python -m pytest - - ------ - - -Finally, feel free to add yourself to `AUTHORS`_! - - -.. _existing issues: https://github.com/httpie/httpie/issues?state=open -.. _AUTHORS: https://github.com/httpie/httpie/blob/master/AUTHORS.rst -.. _Makefile: https://github.com/httpie/httpie/blob/master/Makefile -.. _venv: https://docs.python.org/3/library/venv.html -.. _pytest: https://pytest.org/ -.. _Style Guide for Python Code: https://python.org/dev/peps/pep-0008/ -.. _test suite: https://github.com/httpie/httpie/tree/master/tests diff --git a/MANIFEST.in b/MANIFEST.in index b58818e613..e166aa09fb 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,8 @@ include LICENSE -include README.rst -include CHANGELOG.rst -include AUTHORS.rst +include README.md +include CHANGELOG.md +include AUTHORS.md +include docs/README.md # recursive-include tests/ * diff --git a/Makefile b/Makefile index cc4deff2d3..fa15e8fafd 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ ############################################################################### -# See ./CONTRIBUTING.rst +# See ./CONTRIBUTING.md ############################################################################### .PHONY: build @@ -174,20 +174,6 @@ uninstall-httpie: @echo -############################################################################### -# Docs -############################################################################### - -pdf: - @echo "Converting README.rst to PDF…" - rst2pdf \ - --strip-elements-with-class=no-pdf \ - README.rst \ - -o README.pdf - @echo "Done" - @echo - - ############################################################################### # Homebrew ############################################################################### diff --git a/README.md b/README.md new file mode 100644 index 0000000000..ecad3a3667 --- /dev/null +++ b/README.md @@ -0,0 +1,105 @@ +
      + + Httpie-Logo-Lockup-Pink@2x + + +# HTTPie: the human-friendly HTTP CLI client for working with APIs + + + +[![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%2373DC8C&label=Build&logo=github)](https://github.com/httpie/httpie/actions) +[![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest%20stable%20version&color=%23FA9BFA&logo=pypi&logoColor=white)](https://pypi.python.org/pypi/httpie) +[![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%237D7D7D&logo=codecov)](https://codecov.io/gh/httpie/httpie) +[![Downloads](https://img.shields.io/pypi/dm/httpie?color=%23DBDE52&label=Downloads&logo=python)](https://pepy.tech/project/httpie) + +[![Issues](https://img.shields.io/github/issues/httpie/httpie?style=flat&color=%23FFA24E&label=Issues&logo=github)](https://github.com/httpie/httpie/issues) +[![Docs](https://img.shields.io/badge/stable%20docs-httpie.org%2Fdocs-brightgreen?style=flat&color=%234B78E6&label=Stable%20docs)](https://httpie.org/docs) +[![Chat](https://img.shields.io/badge/chat-on%20Discord-brightgreen?style=flat&logo=discord&label=Chat%20on&color=%23B464F0)](https://httpie.io/chat) + +HTTPie (pronounced _aitch-tee-tee-pie_ 🥧) is a command-line HTTP client. + +The `http` and `https` commands let you send arbitrary HTTP requests for testing, debugging, and generally interacting with APIs & HTTP servers. Commands use simple, natural syntax and provide a formatted and colorized output. + +**Visit [httpie.io](https://httpie.io) to learn more** + +## Features + +- Simple syntax +- Formatted and colorized terminal output +- Built-in JSON support +- Forms and file uploads +- HTTPS, proxies, and authentication +- Persistent sessions +- Wget-like downloads +- Linux, macOS and Windows support +- Plugins, such as JWTAuth and OAuth + +See the [complete list of features](https://httpie.io/docs). + +## Documentation + +Full documentation and installation guides live in [httpie.io/docs](https://httpie.io/docs). + +## Installation + +HTTPie can be installed using Homebrew on macOS (`brew install httpie`), and `pip` on Linux, Windows and other Operating Systems (e.g. `python -m pip install --upgrade httpie`). + +See the [docs](https://httpie.io/docs) for system requirements and full installation instructions. + +## Examples + +Hello World: + +``` +$ https httpie.io/hello +``` + +Custom [HTTP method](https://httpie.io/docs#http-method), [HTTP headers](https://httpie.io/docs#http-headers) and [JSON](https://httpie.io/docs#json) data: + +``` +$ http PUT pie.dev/put X-API-Token:123 name=John +``` + +Build and print a request without sending it using [offline mode](https://httpie.io/docs#offline-mode): + +``` +$ http --offline pie.dev/post hello=offline +``` + +Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comment) to post a comment on an [Issue](https://github.com/httpie/httpie/issues/83) with [authentication](https://httpie.io/docs#authentication): + +``` +$ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comments body='HTTPie is awesome! :heart:' +``` + +**See [the documentation](https://httpie.io/docs) for a complete list of examples and use cases.** + +## Contributing + +We :sparkling_heart: our contributors! Please read the [contribution guide](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md) for how to contribute. +Have a look through existing [Issues](https://github.com/httpie/httpie/issues) and [Pull Requests](https://github.com/httpie/httpie/pulls) that you could help with. + +[![Issues](https://img.shields.io/github/issues/httpie/httpie?style=flat&color=%23FFA24E&label=Issues&logo=github)](https://github.com/httpie/httpie/issues) +[![PRs](https://img.shields.io/github/issues-pr/httpie/httpie?color=%23FA9BFA&label=Pull%20Requests&logo=github)](https://github.com/httpie/httpie/pulls) + +If you'd like to request a feature or report a bug, please [create a GitHub Issue](https://github.com/httpie/httpie/issues) using one of the templates provided. + +## Community & Support + +- Visit the [HTTPie website](https://httpie.io) for full documentation and useful links. + +- Join our [Discord server](https://httpie.io/chat) is to ask questions, discuss features, and for general API chat. + +- Tweet at [@httpie](https://twitter.com/httpie) on Twitter. + +- Use [StackOverflow](https://stackoverflow.com/questions/tagged/httpie) to ask questions and include a `httpie` tag. + +- Create [GitHub Issues](https://github.com/httpie/httpie/issues) for bug reports and feature requests. + +- Subscribe to the [HTTPie newsletter](https://httpie.io) for occasional updates. + +## License + +[![License](https://img.shields.io/github/license/httpie/httpie?color=%2373DC8C&label=License)](https://github.com/httpie/httpie/blob/master/LICENSE) + +HTTPie is licensed under the [BSD-3-Clause License](https://github.com/httpie/httpie/blob/master/LICENSE). diff --git a/README.rst b/README.rst deleted file mode 100644 index f8c6a27abd..0000000000 --- a/README.rst +++ /dev/null @@ -1,2269 +0,0 @@ -HTTPie: human-friendly CLI HTTP client for the API era -###################################################### - -HTTPie (pronounced *aitch-tee-tee-pie*) is a command-line HTTP client. -Its goal is to make CLI interaction with web services as human-friendly as possible. -HTTPie is designed for testing, debugging, and generally interacting with APIs & HTTP servers. -The ``http`` & ``https`` commands allow for creating and sending arbitrary HTTP requests. -They use simple and natural syntax and provide formatted and colorized output. - - - -.. class:: no-web no-pdf - - |docs| |pypi| |build| |coverage| |downloads| |gitter| - - -.. class:: no-web no-pdf - - .. image:: https://raw.githubusercontent.com/httpie/httpie/master/httpie.gif - :alt: HTTPie in action - :width: 100% - :align: center - - -.. contents:: - -.. section-numbering:: - - -About this document -=================== - -This documentation is best viewed at `httpie.org/docs `_. - -You can select your corresponding HTTPie version as well as run examples directly from the -browser using a `termible.io `_ embedded terminal. - -If you are reading this on GitHub, then this text covers the current *development* version. -You are invited to submit fixes and improvements to the docs by editing -`README.rst `_. - - -Main features -============= - -* Expressive and intuitive syntax -* Formatted and colorized terminal output -* Built-in JSON support -* Forms and file uploads -* HTTPS, proxies, and authentication -* Arbitrary request data -* Custom headers -* Persistent sessions -* Wget-like downloads -* Linux, macOS and Windows support -* Plugins -* Documentation -* Test coverage - - -.. class:: no-web - - .. image:: https://raw.githubusercontent.com/httpie/httpie/master/httpie.png - :alt: HTTPie compared to cURL - :width: 100% - :align: center - - -Installation -============ - - -macOS ------ - - -On macOS, HTTPie can be installed via `Homebrew `_ -(recommended): - -.. code-block:: bash - - $ brew install httpie - - -A MacPorts *port* is also available: - -.. code-block:: bash - - $ port install httpie - -Linux ------ - -Most Linux distributions provide a package that can be installed using the -system package manager, for example: - -.. code-block:: bash - - # Debian, Ubuntu, etc. - $ apt install httpie - -.. code-block:: bash - - # Fedora - $ dnf install httpie - -.. code-block:: bash - - # CentOS, RHEL, ... - $ yum install httpie - -.. code-block:: bash - - # Gentoo - $ emerge httpie - -.. code-block:: bash - - # Arch Linux - $ pacman -S httpie - -.. code-block:: bash - - # Solus - $ eopkg install httpie - - -Windows, etc. -------------- - -A universal installation method (that works on Windows, macOS, Linux, …, -and always provides the latest version) is to use `pip`_: - -.. code-block:: bash - - # Make sure we have an up-to-date version of pip and setuptools: - $ python -m pip install --upgrade pip setuptools - - $ python -m pip install --upgrade httpie - - -(If ``pip`` installation fails for some reason, you can try -``easy_install httpie`` as a fallback.) - -Windows users can also install HTTPie with `Chocolatey `_: - -.. code-block:: bash - - $ choco upgrade httpie - - -Python version --------------- - -Python version 3.6 or greater is required. - - -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. - - -.. class:: no-pdf - -|build| - - -On macOS you can install it with Homebrew: - -.. code-block:: bash - - $ brew uninstall --force httpie - $ brew install --HEAD httpie - - -Otherwise with ``pip``: - -.. code-block:: bash - - $ python -m pip install --upgrade https://github.com/httpie/httpie/archive/master.tar.gz - - -Verify that now we have the -`current development version identifier `_ -with the ``-dev`` suffix, for example: - -.. code-block:: bash - - $ http --version - # 2.0.0-dev - - -Usage -===== - - -Hello World: - - -.. code-block:: bash - - $ https httpie.io/hello - - -Synopsis: - -.. code-block:: bash - - $ http [flags] [METHOD] URL [ITEM [ITEM]] - - -See also ``http --help``. - - -Examples --------- - -Custom `HTTP method`_, `HTTP headers`_ and `JSON`_ data: - -.. code-block:: bash - - $ http PUT pie.dev/put X-API-Token:123 name=John - - -Submitting `forms`_: - -.. code-block:: bash - - $ http -f POST pie.dev/post hello=World - - -See the request that is being sent using one of the `output options`_: - -.. code-block:: bash - - $ http -v pie.dev/get - - -Build and print a request without sending it using `offline mode`_: - -.. code-block:: bash - - $ http --offline pie.dev/post hello=offline - - -Use `GitHub API`_ to post a comment on an -`issue `_ -with `authentication`_: - -.. code-block:: bash - - $ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comments body='HTTPie is awesome! :heart:' - - -Upload a file using `redirected input`_: - -.. code-block:: bash - - $ http pie.dev/post < files/data.json - - -Download a file and save it via `redirected output`_: - -.. code-block:: bash - - $ http pie.dev/image/png > image.png - - -Download a file ``wget`` style: - -.. code-block:: bash - - $ http --download pie.dev/image/png - -Use named `sessions`_ to make certain aspects of the communication persistent -between requests to the same host: - - -.. code-block:: bash - - $ http --session=logged-in -a username:password pie.dev/get API-Key:123 - - -.. code-block:: bash - - $ http --session=logged-in pie.dev/headers - - -Set a custom ``Host`` header to work around missing DNS records: - -.. code-block:: bash - - $ http localhost:8000 Host:example.com - -.. - - -HTTP method -=========== - -The name of the HTTP method comes right before the URL argument: - -.. code-block:: bash - - $ http DELETE pie.dev/delete - - -Which looks similar to the actual ``Request-Line`` that is sent: - -.. code-block:: http - - DELETE /delete HTTP/1.1 - - -When the ``METHOD`` argument is omitted from the command, HTTPie defaults to -either ``GET`` (with no request data) or ``POST`` (with request data). - - -Request URL -=========== - -The only information HTTPie needs to perform a request is a URL. - -The default scheme is ``http://`` and can be omitted from the argument: - -.. code-block:: bash - - $ http example.org - # => http://example.org - - -HTTPie also installs an ``https`` executable, where the default -scheme is ``https://``: - - -.. code-block:: bash - - $ https example.org - # => https://example.org - - -Querystring parameters ----------------------- - -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. Additionally, any special characters in the -parameter name or value get automatically URL-escaped -(as opposed to parameters specified in the full URL, which HTTPie doesn’t -modify). - -.. code-block:: bash - - $ http https://api.github.com/search/repositories q==httpie per_page==1 - - -.. code-block:: http - - GET /search/repositories?q=httpie&per_page=1 HTTP/1.1 - - - -URL shortcuts for ``localhost`` -------------------------------- - -Additionally, curl-like shorthand for localhost is supported. -This means that, for example ``:3000`` would expand to ``http://localhost:3000`` -If the port is omitted, then port 80 is assumed. - -.. code-block:: bash - - $ http :/foo - - -.. code-block:: http - - GET /foo HTTP/1.1 - Host: localhost - - -.. code-block:: bash - - $ http :3000/bar - - -.. code-block:: http - - GET /bar HTTP/1.1 - Host: localhost:3000 - - -.. code-block:: bash - - $ http : - - -.. code-block:: http - - GET / HTTP/1.1 - Host: localhost - - -Other default schemes ---------------------- - -When HTTPie is invoked as ``https`` then the default scheme is ``https://`` -(``$ https example.org`` will make a request to ``https://example.org``). - -You can also use the ``--default-scheme `` option to create -shortcuts for other protocols than HTTP (possibly supported via plugins). -Example for the `httpie-unixsocket `_ plugin: - -.. code-block:: bash - - # Before - $ http http+unix://%2Fvar%2Frun%2Fdocker.sock/info - - -.. code-block:: bash - - # Create an alias - $ alias http-unix='http --default-scheme="http+unix"' - - -.. code-block:: bash - - # Now the scheme can be omitted - $ http-unix %2Fvar%2Frun%2Fdocker.sock/info - - -``--path-as-is`` ----------------- - -The standard behaviour of HTTP clients is to normalize the path portion of URLs by squashing dot segments -as a typically filesystem would: - - -.. code-block:: bash - - $ http -v example.org/./../../etc/password - -.. code-block:: http - - GET /etc/password HTTP/1.1 - - -The ``--path-as-is`` option allows you to disable this behavior: - -.. code-block:: bash - - $ http --path-as-is -v example.org/./../../etc/password - -.. code-block:: http - - GET /../../etc/password HTTP/1.1 - - -Request items -============= - -There are a few different *request item* types that provide a -convenient mechanism for specifying HTTP headers, simple JSON and -form data, files, and URL parameters. - -They are key/value pairs specified after the URL. All have in -common that they become part of the actual request that is sent and that -their type is distinguished only by the separator used: -``:``, ``=``, ``:=``, ``==``, ``@``, ``=@``, and ``:=@``. The ones with an -``@`` expect a file path as value. - -+------------------------------+---------------------------------------------------+ -| Item Type | Description | -+==============================+===================================================+ -| HTTP Headers | Arbitrary HTTP header, e.g. ``X-API-Token:123``. | -| ``Name:Value`` | | -+------------------------------+---------------------------------------------------+ -| URL parameters | Appends the given name/value pair as a query | -| ``name==value`` | string parameter to the URL. | -| | The ``==`` separator is used. | -+------------------------------+---------------------------------------------------+ -| Data Fields | Request data fields to be serialized as a JSON | -| ``field=value``, | object (default), to be form-encoded | -| ``field=@file.txt`` | (with ``--form, -f``), or to be serialized as | -| | ``multipart/form-data`` (with ``--multipart``). | -+------------------------------+---------------------------------------------------+ -| Raw JSON fields | Useful when sending JSON and one or | -| ``field:=json``, | more fields need to be a ``Boolean``, ``Number``, | -| ``field:=@file.json`` | nested ``Object``, or an ``Array``, e.g., | -| | ``meals:='["ham","spam"]'`` or ``pies:=[1,2,3]`` | -| | (note the quotes). | -+------------------------------+---------------------------------------------------+ -| Fields upload fields | Only available with ``--form, -f`` and | -| ``field@/dir/file`` | ``--multipart``. | -| ``field@file;type=mime`` | For example ``screenshot@~/Pictures/img.png``, or | -| | ``'cv@cv.txt;type=text/markdown'``. | -| | With ``--form``, the presence of a file field | -| | results in a ``--multipart`` request. | -+------------------------------+---------------------------------------------------+ - - -Note that the structured data fields aren’t the only way to specify request data: -The `raw request body`_ section describes mechanisms for passing arbitrary request data. - - -Escaping rules --------------- - -You can use ``\`` to escape characters that shouldn’t be used as separators -(or parts thereof). For instance, ``foo\==bar`` will become a data key/value -pair (``foo=`` and ``bar``) instead of a URL parameter. - -Often it is necessary to quote the values, e.g. ``foo='bar baz'``. - -If any of the field names or headers starts with a minus -(e.g., ``-fieldname``), you need to place all such items after the special -token ``--`` to prevent confusion with ``--arguments``: - -.. code-block:: bash - - $ http pie.dev/post -- -name-starting-with-dash=foo -Unusual-Header:bar - -.. code-block:: http - - POST /post HTTP/1.1 - -Unusual-Header: bar - Content-Type: application/json - - { - "-name-starting-with-dash": "foo" - } - - - -JSON -==== - -JSON is the *lingua franca* of modern web services and it is also the -**implicit content type** HTTPie uses by default. - - -Simple example: - -.. code-block:: bash - - $ http PUT pie.dev/put name=John email=john@example.org - -.. code-block:: http - - PUT / HTTP/1.1 - Accept: application/json, */*;q=0.5 - Accept-Encoding: gzip, deflate - Content-Type: application/json - Host: pie.dev - - { - "name": "John", - "email": "john@example.org" - } - - -Default behaviour ------------------ - - -If your command includes some data `request items`_, they are serialized as a JSON -object by default. HTTPie also automatically sets the following headers, -both of which can be overwritten: - -================ ======================================= -``Content-Type`` ``application/json`` -``Accept`` ``application/json, */*;q=0.5`` -================ ======================================= - - -Explicit JSON -------------- - -You can use ``--json, -j`` to explicitly set ``Accept`` -to ``application/json`` regardless of whether you are sending data -(it’s a shortcut for setting the header via the usual header notation: -``http url Accept:'application/json, */*;q=0.5'``). Additionally, -HTTPie will try to detect JSON responses even when the -``Content-Type`` is incorrectly ``text/plain`` or unknown. - - - -Non-string JSON fields ----------------------- - -Non-string JSON fields use the ``:=`` separator, which allows you to embed arbitrary JSON data -into the resulting JSON object. Additionally, text and raw JSON files can also be embedded into -fields using ``=@`` and ``:=@``: - -.. code-block:: bash - - $ http PUT pie.dev/put \ - name=John \ # String (default) - age:=29 \ # Raw JSON — Number - married:=false \ # Raw JSON — Boolean - hobbies:='["http", "pies"]' \ # Raw JSON — Array - favorite:='{"tool": "HTTPie"}' \ # Raw JSON — Object - bookmarks:=@files/data.json \ # Embed JSON file - description=@files/text.txt # Embed text file - - -.. code-block:: http - - PUT /person/1 HTTP/1.1 - Accept: application/json, */*;q=0.5 - Content-Type: application/json - Host: pie.dev - - { - "age": 29, - "hobbies": [ - "http", - "pies" - ], - "description": "John is a nice guy who likes pies.", - "married": false, - "name": "John", - "favorite": { - "tool": "HTTPie" - }, - "bookmarks": { - "HTTPie": "https://httpie.org", - } - } - - -Raw and complex JSON --------------------- - -Please note that with the structured `request items`_ data field syntax, commands -can quickly become unwieldy when sending complex structures. -In such cases, it’s better to pass the full raw JSON data as a `raw request body`_, for example: - -.. code-block:: bash - - $ echo -n '{"hello": "world"}' | http POST pie.dev/post - -.. code-block:: bash - - $ http --raw '{"hello": "world"}' POST pie.dev/post - -.. code-block:: bash - - $ http POST pie.dev/post < files/data.json - -Furthermore, the structure syntax only allows you to send an object as the JSON document, but not an array, etc. -Here, again, the solution is to use a `raw request body`_. - -Forms -===== - -Submitting forms is very similar to sending `JSON`_ requests. Often the only -difference is in adding the ``--form, -f`` option, which ensures that -data fields are serialized as, and ``Content-Type`` is set to, -``application/x-www-form-urlencoded; charset=utf-8``. It is possible to make -form data the implicit content type instead of JSON -via the `config`_ file. - - -Regular forms -------------- - -.. code-block:: bash - - $ http --form POST pie.dev/post name='John Smith' - - -.. code-block:: http - - POST /post HTTP/1.1 - Content-Type: application/x-www-form-urlencoded; charset=utf-8 - - name=John+Smith - - -File upload forms ------------------ - -If one or more file fields is present, the serialization and content type is -``multipart/form-data``: - -.. code-block:: bash - - $ http -f POST pie.dev/post name='John Smith' cv@~/files/data.xml - - -The request above is the same as if the following HTML form were -submitted: - -.. code-block:: html - -
      - - -
      - -Please note that ``@`` is used to simulate a file upload form field, whereas -``=@`` just embeds the file content as a regular text field value. - -When uploading files, their content type is inferred from the file name. You can manually -override the inferred content type: - -.. code-block:: bash - - $ http -f POST pie.dev/post name='John Smith' cv@'~/files/data.bin;type=application/pdf' - -To perform a ``multipart/form-data`` request even without any files, use -``--multipart`` instead of ``--form``: - -.. code-block:: bash - - $ http --multipart --offline example.org hello=world - -.. code-block:: http - - POST / HTTP/1.1 - Content-Length: 129 - Content-Type: multipart/form-data; boundary=c31279ab254f40aeb06df32b433cbccb - Host: example.org - - --c31279ab254f40aeb06df32b433cbccb - Content-Disposition: form-data; name="hello" - - world - --c31279ab254f40aeb06df32b433cbccb-- - -File uploads are always streamed to avoid memory issues with large files. - -By default, HTTPie uses a random unique string as the multipart boundary -but you can use ``--boundary`` to specify a custom string instead: - -.. code-block:: bash - - $ http --form --multipart --boundary=xoxo --offline example.org hello=world - -.. code-block:: http - - POST / HTTP/1.1 - Content-Length: 129 - Content-Type: multipart/form-data; boundary=xoxo - Host: example.org - - --xoxo - Content-Disposition: form-data; name="hello" - - world - --xoxo-- - -If you specify a custom ``Content-Type`` header without including the boundary -bit, HTTPie will add the boundary value (explicitly specified or auto-generated) -to the header automatically: - - -.. code-block:: bash - - http --form --multipart --offline example.org hello=world Content-Type:multipart/letter - -.. code-block:: http - - POST / HTTP/1.1 - Content-Length: 129 - Content-Type: multipart/letter; boundary=c31279ab254f40aeb06df32b433cbccb - Host: example.org - - --c31279ab254f40aeb06df32b433cbccb - Content-Disposition: form-data; name="hello" - - world - --c31279ab254f40aeb06df32b433cbccb-- - - -HTTP headers -============ - -To set custom headers you can use the ``Header:Value`` notation: - -.. code-block:: bash - - $ http pie.dev/headers User-Agent:Bacon/1.0 'Cookie:valued-visitor=yes;foo=bar' \ - X-Foo:Bar Referer:https://httpie.org/ - - -.. code-block:: http - - GET /headers HTTP/1.1 - Accept: */* - Accept-Encoding: gzip, deflate - Cookie: valued-visitor=yes;foo=bar - Host: pie.dev - Referer: https://httpie.org/ - User-Agent: Bacon/1.0 - X-Foo: Bar - - -Default request headers ------------------------ - -There are a couple of default headers that HTTPie sets: - -.. code-block:: http - - GET / HTTP/1.1 - Accept: */* - Accept-Encoding: gzip, deflate - User-Agent: HTTPie/ - Host: - - - -Any of these can be overwritten and some of them unset (see below). - - - -Empty headers and header un-setting ------------------------------------ - -To unset a previously specified header -(such a one of the default headers), use ``Header:``: - - -.. code-block:: bash - - $ http pie.dev/headers Accept: User-Agent: - - -To send a header with an empty value, use ``Header;``: - - -.. code-block:: bash - - $ http pie.dev/headers 'Header;' - - -Limiting response headers -------------------------- - -The ``--max-headers=n`` options allows you to control the number of headers -HTTPie reads before giving up (the default ``0``, i.e., there’s no limit). - - -.. code-block:: bash - - $ http --max-headers=100 pie.dev/get - - - -Offline mode -============ - -Use ``--offline`` to construct HTTP requests without sending them anywhere. -With ``--offline``, HTTPie builds a request based on the specified options and arguments, prints it to ``stdout``, -and then exits. It works completely offline; no network connection is ever made. -This has a number of use cases, including: - - -Generating API documentation examples that you can copy & paste without sending a request: - - -.. code-block:: bash - - $ http --offline POST server.chess/api/games API-Key:ZZZ w=magnus b=hikaru t=180 i=2 - - -.. code-block:: bash - - $ http --offline MOVE server.chess/api/games/123 API-Key:ZZZ p=b a=R1a3 t=77 - - -Generating raw requests that can be sent with any other client: - -.. code-block:: bash - - # 1. save a raw request to a file: - $ http --offline POST pie.dev/post hello=world > request.http - - -.. code-block:: bash - - # 2. send it over the wire with, for example, the fantastic netcat tool: - $ nc pie.dev 80 < request.http - - -You can also use the ``--offline`` mode for debugging and exploring HTTP and HTTPie, and for “dry runs”. - -``--offline`` has the side-effect of automatically activating ``--print=HB``, i.e., both the request headers and the body -are printed. You can customize the output with the usual `output options`_, with the exception that there -is not response to be printed. You can use ``--offline`` in combination with all the other options (e.g., ``--session``). - - - -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 pie.dev/cookies Cookie:sessionid=foo - -.. code-block:: http - - GET / HTTP/1.1 - Accept: */* - Accept-Encoding: gzip, deflate - Connection: keep-alive - Cookie: sessionid=foo - Host: pie.dev - 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 pie.dev/cookies '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: pie.dev - 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 -============== - -The currently supported authentication schemes are Basic and Digest -(see `auth plugins`_ for more). There are two flags that control authentication: - -=================== ====================================================== -``--auth, -a`` Pass a ``username:password`` pair as - the argument. Or, if you only specify a username - (``-a username``), you’ll be prompted for - the password before the request is sent. - To send an empty password, pass ``username:``. - The ``username:password@hostname`` URL syntax is - supported as well (but credentials passed via ``-a`` - have higher priority). - -``--auth-type, -A`` Specify the auth mechanism. Possible values are - ``basic``, ``digest``, or the name of any `auth plugins`_ you have installed. The default value is - ``basic`` so it can often be omitted. -=================== ====================================================== - - - -Basic auth ----------- - - -.. code-block:: bash - - $ http -a username:password pie.dev/basic-auth/username/password - - -Digest auth ------------ - - -.. code-block:: bash - - $ http -A digest -a username:password pie.dev/digest-auth/httpie/username/password - - -Password prompt ---------------- - -.. code-block:: bash - - $ http -a username pie.dev/basic-auth/username/password - - -Empty password --------------- - -.. code-block:: bash - - $ http -a username: pie.dev/headers - - -``.netrc`` ----------- - -Authentication information from your ``~/.netrc`` -file is by default honored as well. - -For example: - -.. code-block:: bash - - $ cat ~/.netrc - machine pie.dev - login httpie - password test - -.. code-block:: bash - - $ http pie.dev/basic-auth/httpie/test - HTTP/1.1 200 OK - [...] - -This can be disabled with the ``--ignore-netrc`` option: - -.. code-block:: bash - - $ http --ignore-netrc pie.dev/basic-auth/httpie/test - HTTP/1.1 401 UNAUTHORIZED - [...] - - -Auth plugins ------------- - -Additional authentication mechanism can be installed as plugins. -They can be found on the `Python Package Index `_. -Here’s a few picks: - -* `httpie-api-auth `_: ApiAuth -* `httpie-aws-auth `_: AWS / Amazon S3 -* `httpie-edgegrid `_: EdgeGrid -* `httpie-hmac-auth `_: HMAC -* `httpie-jwt-auth `_: JWTAuth (JSON Web Tokens) -* `httpie-negotiate `_: SPNEGO (GSS Negotiate) -* `httpie-ntlm `_: NTLM (NT LAN Manager) -* `httpie-oauth `_: OAuth -* `requests-hawk `_: Hawk - - - - -HTTP redirects -============== - -By default, HTTP redirects are not followed and only the first -response is shown: - - -.. code-block:: bash - - $ http pie.dev/redirect/3 - - -Follow ``Location`` -------------------- - -To instruct HTTPie to follow the ``Location`` header of ``30x`` responses -and show the final response instead, use the ``--follow, -F`` option: - - -.. code-block:: bash - - $ http --follow pie.dev/redirect/3 - - -With ``307 Temporary Redirect`` and ``308 Permanent Redirect``, the method and the body of the original request -are reused to perform the redirected request. Otherwise, a body-less ``GET`` request is performed. - - -Showing intermediary redirect responses ---------------------------------------- - -If you additionally wish to see the intermediary requests/responses, -then use the ``--all`` option as well: - - -.. code-block:: bash - - $ http --follow --all pie.dev/redirect/3 - - - -Limiting maximum redirects followed ------------------------------------ - -To change the default limit of maximum ``30`` redirects, use the -``--max-redirects=`` option: - - -.. code-block:: bash - - $ http --follow --all --max-redirects=2 pie.dev/redirect/3 - - -Proxies -======= - -You can specify proxies to be used through the ``--proxy`` argument for each -protocol (which is included in the value in case of redirects across protocols): - -.. code-block:: bash - - $ http --proxy=http:http://10.10.1.10:3128 --proxy=https:https://10.10.1.10:1080 example.org - - -With Basic authentication: - -.. code-block:: bash - - $ http --proxy=http:http://user:pass@10.10.1.10:3128 example.org - - -Environment variables ---------------------- - -You can also configure proxies by environment variables ``ALL_PROXY``, -``HTTP_PROXY`` and ``HTTPS_PROXY``, and the underlying Requests library will -pick them up as well. If you want to disable proxies configured through -the environment variables for certain hosts, you can specify them in ``NO_PROXY``. - -In your ``~/.bash_profile``: - -.. code-block:: bash - - export HTTP_PROXY=http://10.10.1.10:3128 - export HTTPS_PROXY=https://10.10.1.10:1080 - export NO_PROXY=localhost,example.com - - -SOCKS ------ - -Usage is the same as for other types of `proxies`_: - -.. code-block:: bash - - $ http --proxy=http:socks5://user:pass@host:port --proxy=https:socks5://user:pass@host:port example.org - - -HTTPS -===== - - -Server SSL certificate verification ------------------------------------ - -To skip the host’s SSL certificate verification, you can pass ``--verify=no`` -(default is ``yes``): - -.. code-block:: bash - - $ http --verify=no https://pie.dev/get - - -Custom CA bundle ----------------- - -You can also use ``--verify=`` to set a custom CA bundle path: - -.. code-block:: bash - - $ http --verify=/ssl/custom_ca_bundle https://example.org - - - -Client side SSL certificate ---------------------------- -To use a client side certificate for the SSL communication, you can pass -the path of the cert file with ``--cert``: - -.. code-block:: bash - - $ http --cert=client.pem https://example.org - - -If the private key is not contained in the cert file you may pass the -path of the key file with ``--cert-key``: - -.. code-block:: bash - - $ http --cert=client.crt --cert-key=client.key https://example.org - - -SSL version ------------ - -Use the ``--ssl=`` option 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``, ``tls1.3``. -(The actually available set of protocols may vary depending on your OpenSSL -installation.) - -.. code-block:: bash - - # Specify the vulnerable SSL v3 protocol to talk to an outdated server: - $ http --ssl=ssl3 https://vulnerable.example.org - - - -SSL ciphers ------------ - -You can specify the available ciphers with ``--ciphers``. -It should be a string in the -`OpenSSL cipher list format `_. - -.. code-block:: bash - - $ http --ciphers=ECDHE-RSA-AES128-GCM-SHA256 https://pie.dev/get - -Note: these cipher strings do not change the negotiated version of SSL or TLS, -they only affect the list of available cipher suites. - -To see the default cipher string, run ``http --help`` and see -the ``--ciphers`` section under SSL. - - - -Output options -============== - -By default, HTTPie only outputs the final response and the whole response -message is printed (headers as well as the body). You can control what should -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 below). -``--print, -p`` Selects parts of the HTTP exchange. -``--quiet, -q`` Don't print anything to ``stdout`` and ``stderr``. -================= ===================================================== - - -What parts of the HTTP exchange should be printed -------------------------------------------------- - -All the other `output options`_ are under the hood just shortcuts for -the more powerful ``--print, -p``. It accepts a string of characters each -of which represents a specific part of the HTTP exchange: - -========== ================== -Character Stands for -========== ================== -``H`` request headers -``B`` request body -``h`` response headers -``b`` response body -========== ================== - -Print request and response headers: - -.. code-block:: bash - - $ http --print=Hh PUT pie.dev/put hello=world - -Verbose output --------------- - -``--verbose`` can often be useful for debugging the request and generating -documentation examples: - -.. code-block:: bash - - $ http --verbose PUT pie.dev/put hello=world - PUT /put HTTP/1.1 - Accept: application/json, */*;q=0.5 - Accept-Encoding: gzip, deflate - Content-Type: application/json - Host: pie.dev - User-Agent: HTTPie/0.2.7dev - - { - "hello": "world" - } - - - HTTP/1.1 200 OK - Connection: keep-alive - Content-Length: 477 - Content-Type: application/json - Date: Sun, 05 Aug 2012 00:25:23 GMT - Server: gunicorn/0.13.4 - - { - […] - } - -Quiet output ------------- - -``--quiet`` redirects all output that would otherwise go to ``stdout`` -and ``stderr`` to ``/dev/null`` (except for errors and warnings). -This doesn’t affect output to a file via ``--output`` or ``--download``. - -.. code-block:: bash - - # There will be no output: - $ http --quiet pie.dev/post enjoy='the silence' - - -Viewing intermediary requests/responses ---------------------------------------- - -To see all the HTTP communication, i.e. the final request/response as -well as any possible intermediary requests/responses, use the ``--all`` -option. The intermediary HTTP communication include followed redirects -(with ``--follow``), the first unauthorized request when HTTP digest -authentication is used (``--auth=digest``), etc. - -.. code-block:: bash - - # Include all responses that lead to the final one: - $ http --all --follow pie.dev/redirect/3 - - -The intermediary requests/response are by default formatted according to -``--print, -p`` (and its shortcuts described above). If you’d like to change -that, use the ``--history-print, -P`` option. It takes the same -arguments as ``--print, -p`` but applies to the intermediary requests only. - - -.. code-block:: bash - - # Print the intermediary requests/responses differently than the final one: - $ http -A digest -a foo:bar --all -p Hh -P H pie.dev/digest-auth/auth/foo/bar - - -Conditional body download -------------------------- - -As an optimization, the response body is downloaded from the server -only if it’s part of the output. This is similar to performing a ``HEAD`` -request, except that it applies to any HTTP method you use. - -Let’s say that there is an API that returns the whole resource when it is -updated, but you are only interested in the response headers to see the -status code after an update: - -.. code-block:: bash - - $ http --headers PATCH pie.dev/patch name='New Name' - - -Since we are only printing the HTTP headers here, the connection to the server -is closed as soon as all the response headers have been received. -Therefore, bandwidth and time isn’t wasted downloading the body -which you don’t care about. The response headers are downloaded always, -even if they are not part of the output - - -Raw request body -================ - -In addition to crafting structured `JSON`_ and `forms`_ requests with the -`request items`_ syntax, you can provide a raw request body that will be -sent without further processing. These two approaches for specifying request -data (i.e., structured and raw) cannot be combined. - -There’re three methods for passing raw request data: piping via ``stdin``, -``--raw='data'``, and ``@/file/path``. - - -Redirected Input ----------------- - -The universal method for passing request data is through redirected ``stdin`` -(standard input)—piping. - -By default, ``stdin`` data is buffered and then with no further processing -used as the request body. If you provide ``Content-Length``, then the request -body is streamed without buffering. You can also use ``--chunked`` to enable -streaming via `chunked transfer encoding`_. - -There are multiple useful ways to use piping: - -Redirect from a file: - -.. code-block:: bash - - $ http PUT pie.dev/put X-API-Token:123 < files/data.json - - -Or the output of another program: - -.. code-block:: bash - - $ grep '401 Unauthorized' /var/log/httpd/error_log | http POST pie.dev/post - - -You can use ``echo`` for simple data: - -.. code-block:: bash - - $ echo -n '{"name": "John"}' | http PATCH pie.dev/patch X-API-Token:123 - - -You can also use a Bash *here string*: - -.. code-block:: bash - - $ http pie.dev/post <<<'{"name": "John"}' - - -You can even pipe web services together using HTTPie: - -.. code-block:: bash - - $ http GET https://api.github.com/repos/httpie/httpie | http POST pie.dev/post - - -You can use ``cat`` to enter multiline data on the terminal: - -.. code-block:: bash - - $ cat | http POST pie.dev/post - - ^D - - -.. code-block:: bash - - $ cat | http POST pie.dev/post Content-Type:text/plain - - buy milk - - call parents - ^D - - -On OS X, you can send the contents of the clipboard with ``pbpaste``: - -.. code-block:: bash - - $ pbpaste | http PUT pie.dev/put - - -Passing data through ``stdin`` cannot be combined with data fields specified -on the command line: - -.. code-block:: bash - - $ echo -n 'data' | http POST example.org more=data # This is invalid - - -To prevent HTTPie from reading ``stdin`` data you can use the -``--ignore-stdin`` option. - - -Request data via ``--raw`` --------------------------- - -In a situation when piping data via ``stdin`` is not convenient (for example, -when generating API docs examples), you can specify the raw request body via -the ``--raw`` option. - -.. code-block:: bash - - $ http --raw 'Hello, world!' pie.dev/post - -.. code-block:: bash - - $ http --raw '{"name": "John"}' pie.dev/post - - -Request data from a filename ----------------------------- - -An alternative to redirected ``stdin`` is specifying a filename (as -``@/path/to/file``) whose content is used as if it came from ``stdin``. - -It has the advantage that the ``Content-Type`` -header is automatically set to the appropriate value based on the -filename extension. For example, the following request sends the -verbatim contents of that XML file with ``Content-Type: application/xml``: - -.. code-block:: bash - - $ http PUT pie.dev/put @files/data.xml - -File uploads are always streamed to avoid memory issues with large files. - - -Chunked transfer encoding -========================= - -You can use the ``--chunked`` flag to instruct HTTPie to use -``Transfer-Encoding: chunked``: - - -.. code-block:: bash - - $ http --chunked PUT pie.dev/put hello=world - -.. code-block:: bash - - $ http --chunked --multipart PUT pie.dev/put hello=world foo@files/data.xml - -.. code-block:: bash - - $ http --chunked pie.dev/post @files/data.xml - -.. code-block:: bash - - $ cat files/data.xml | http --chunked pie.dev/post - - - -Terminal output -=============== - -HTTPie does several things by default in order to make its terminal output -easy to read. - - -Colors and formatting ---------------------- - -Syntax highlighting is applied to HTTP headers and bodies (where it makes -sense). You can choose your preferred color scheme via the ``--style`` option -if you don’t like the default one. There dozens of styles available, here are just a few special or notable ones: - -==================== ======================================================================== -``auto`` Follows your terminal ANSI color styles. This is the default style used by HTTPie. -``default`` Default styles of the underlying Pygments library. Not actually used by default by HTTPie. - You can enable it with ``--style=default`` -``monokai`` A popular color scheme. Enable with ``--style=monokai``. -``fruity`` A bold, colorful scheme. Enable with ``--style=fruity``. -… See ``$ http --help`` for all the possible ``--style`` values. -==================== ======================================================================== - -Also, the following formatting is applied: - -* HTTP headers are sorted by name. -* JSON data is indented, sorted by keys, and unicode escapes are converted - to the characters they represent. - -One of these options can be used to control output processing: - -==================== ======================================================== -``--pretty=all`` Apply both colors and formatting. - Default for terminal output. -``--pretty=colors`` Apply colors. -``--pretty=format`` Apply formatting. -``--pretty=none`` Disables output processing. - Default for redirected output. -==================== ======================================================== - -You can further control the applied formatting via the more granular `format options`_. - - -Format options --------------- - -The ``--format-options=opt1:value,opt2:value`` option allows you to control how the output should be formatted -when formatting is applied. The following options are available: - -+-------------------------------+---------------+------------------------------+ -| Option | Default value | Shortcuts | -+===============================+===============+==============================+ -| ``headers.sort`` | ``true`` | ``--sorted``, ``--unsorted`` | -+-------------------------------+---------------+------------------------------+ -| ``json.format`` | ``true`` | N/A | -+-------------------------------+---------------+------------------------------+ -| ``json.indent`` | ``4`` | N/A | -+--------------------+----------+---------------+------------------------------+ -| ``json.sort_keys`` | ``true`` | ``--sorted``, ``--unsorted`` | -+--------------------+----------+---------------+------------------------------+ -| ``xml.format`` | ``true`` | N/A | -+-------------------------------+---------------+------------------------------+ -| ``xml.indent`` | ``2`` | N/A | -+--------------------+----------+---------------+------------------------------+ - -For example, this is how you would disable the default header and JSON key -sorting, and specify a custom JSON indent size: - -.. code-block:: bash - - $ http --format-options headers.sort:false,json.sort_keys:false,json.indent:2 pie.dev/get - -There are also two shortcuts that allow you to quickly disable and re-enable -sorting-related format options (currently it means JSON keys and headers): -``--unsorted`` and ``--sorted``. - -This is something you will typically store as one of the default options in your `config`_ file. - - -Binary data ------------ - -Binary data is suppressed for terminal output, which makes it safe to perform -requests to URLs that send back binary data. Binary data is suppressed also in -redirected, but prettified output. The connection is closed as soon as we know -that the response body is binary, - -.. code-block:: bash - - $ http pie.dev/bytes/2000 - - -You will nearly instantly see something like this: - -.. code-block:: http - - HTTP/1.1 200 OK - Content-Type: application/octet-stream - - +-----------------------------------------+ - | NOTE: binary data not shown in terminal | - +-----------------------------------------+ - - -Redirected output -================= - -HTTPie uses a different set of defaults for redirected output than for -`terminal output`_. The differences being: - -* Formatting and colors aren’t applied (unless ``--pretty`` is specified). -* Only the response body is printed (unless one of the `output options`_ is set). -* Also, binary data isn’t suppressed. - -The reason is to make piping HTTPie’s output to another programs and -downloading files work with no extra flags. Most of the time, only the raw -response body is of an interest when the output is redirected. - -Download a file: - -.. code-block:: bash - - $ http pie.dev/image/png > image.png - - -Download an image of Octocat, resize it using ImageMagick, upload it elsewhere: - -.. code-block:: bash - - $ http octodex.github.com/images/original.jpg | convert - -resize 25% - | http example.org/Octocats - - -Force colorizing and formatting, and show both the request and the response in -``less`` pager: - -.. code-block:: bash - - $ http --pretty=all --verbose pie.dev/get | less -R - - -The ``-R`` flag tells ``less`` to interpret color escape sequences included -HTTPie`s output. - -You can create a shortcut for invoking HTTPie with colorized and paged output -by adding the following to your ``~/.bash_profile``: - -.. code-block:: bash - - function httpless { - # `httpless example.org' - http --pretty=all --print=hb "$@" | less -R; - } - - -Download mode -============= - -HTTPie features a download mode in which it acts similarly to ``wget``. - -When enabled using the ``--download, -d`` flag, response headers are printed to -the terminal (``stderr``), and a progress bar is shown while the response body -is being saved to a file. - -.. code-block:: bash - - $ http --download https://github.com/httpie/httpie/archive/master.tar.gz - -.. code-block:: http - - HTTP/1.1 200 OK - Content-Disposition: attachment; filename=httpie-master.tar.gz - Content-Length: 257336 - Content-Type: application/x-gzip - - Downloading 251.30 kB to "httpie-master.tar.gz" - Done. 251.30 kB in 2.73862s (91.76 kB/s) - - -Downloaded filename --------------------- - -There are three mutually exclusive ways through which HTTPie determines -the output filename (with decreasing priority): - -1. You can explicitly provide it via ``--output, -o``. - The file gets overwritten if it already exists - (or appended to with ``--continue, -c``). -2. The server may specify the filename in the optional ``Content-Disposition`` - response header. Any leading dots are stripped from a server-provided filename. -3. The last resort HTTPie uses is to generate the filename from a combination - of the request URL and the response ``Content-Type``. - The initial URL is always used as the basis for - the generated filename — even if there has been one or more redirects. - - -To prevent data loss by overwriting, HTTPie adds a unique numerical suffix to the -filename when necessary (unless specified with ``--output, -o``). - - -Piping while downloading ------------------------- - -You can also redirect the response body to another program while the response -headers and progress are still shown in the terminal: - -.. code-block:: bash - - $ http -d https://github.com/httpie/httpie/archive/master.tar.gz | tar zxf - - - - -Resuming downloads ------------------- - -If ``--output, -o`` is specified, you can resume a partial download using the -``--continue, -c`` option. This only works with servers that support -``Range`` requests and ``206 Partial Content`` responses. If the server doesn’t -support that, the whole file will simply be downloaded: - -.. code-block:: bash - - $ http -dco file.zip example.org/file - -Other notes ------------ - -* The ``--download`` option only changes how the response body is treated. -* You can still set custom headers, use sessions, ``--verbose, -v``, etc. -* ``--download`` always implies ``--follow`` (redirects are followed). -* ``--download`` also implies ``--check-status`` - (error HTTP status will result in a non-zero exist static code). -* HTTPie exits with status code ``1`` (error) if the body hasn’t been fully - downloaded. -* ``Accept-Encoding`` cannot be set with ``--download``. - - -Streamed responses -================== - -Responses are downloaded and printed in chunks which allows for streaming -and large file downloads without using too much memory. However, when -`colors and formatting`_ is applied, the whole response is buffered and only -then processed at once. - - -Disabling buffering -------------------- - -You can use the ``--stream, -S`` flag to make two things happen: - -1. The output is flushed in much smaller chunks without any buffering, - which makes HTTPie behave kind of like ``tail -f`` for URLs. - -2. Streaming becomes enabled even when the output is prettified: It will be - applied to each line of the response and flushed immediately. This makes - it possible to have a nice output for long-lived requests, such as one - to the Twitter streaming API. - - -Examples use cases ------------------- - -Prettified streamed response: - -.. code-block:: bash - - $ http --stream pie.dev/stream/3 - - -Streamed output by small chunks à la ``tail -f``: - -.. code-block:: bash - - # Send each new line (JSON object) to another URL as soon as it arrives from a streaming API: - $ http --stream pie.dev/stream/3 | while read line; do echo "$line" | http pie.dev/post ; done - -Sessions -======== - -By default, every request HTTPie makes is completely independent of any -previous ones to the same host. - - -However, HTTPie also supports persistent -sessions via the ``--session=SESSION_NAME_OR_PATH`` option. In a session, -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. - - -.. code-block:: bash - - # Create a new session: - $ http --session=./session.json pie.dev/headers API-Token:123 - - -.. code-block:: bash - - # Inspect / edit the generated session file: - $ cat session.json - -.. code-block:: bash - - # Re-use the existing session — the API-Token header will be set: - $ http --session=./session.json pie.dev/headers - - -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. It also means that they can be read by anyone -who has access to the session file. - - -Named sessions --------------- - - -You can create one or more named session per host. For example, this is how -you can create a new session named ``user1`` for ``pie.dev``: - -.. code-block:: bash - - $ http --session=user1 -a user1:password pie.dev/get X-Foo:Bar - -From now on, you can refer to the session by its name (``user1``). When you choose -to use the session again, any previously specified authentication or HTTP headers -will automatically be set: - -.. code-block:: bash - - $ http --session=user1 pie.dev/get - -To create or reuse a different session, simple specify a different name: - -.. code-block:: bash - - $ http --session=user2 -a user2:password pie.dev/get X-Bar:Foo - -Named sessions’s data is stored in JSON files inside the ``sessions`` -subdirectory of the `config`_ directory, typically: -``~/.config/httpie/sessions//.json`` -(``%APPDATA%\httpie\sessions\\.json`` on Windows). - -If you have executed the above commands on a unix machine, -you should be able list the generated sessions files using: - - -.. code-block:: bash - - $ ls -l ~/.config/httpie/sessions/pie.dev - - -Anonymous sessions ------------------- - -Instead of a name, you can also directly specify a path to a session file. This -allows for sessions to be re-used across multiple hosts: - -.. code-block:: bash - - # Create a session: - $ http --session=/tmp/session.json example.org - - -.. code-block:: bash - - # Use the session to make a request to another host: - $ http --session=/tmp/session.json admin.example.org - -.. code-block:: bash - - # You can also refer to a previously created named session: - $ http --session=~/.config/httpie/sessions/another.example.org/test.json example.org - - -When creating anonymous sessions, please remember to always include at least -one ``/``, even if the session files is located in the current directory -(i.e., ``--session=./session.json`` instead of just ``--session=session.json``), -otherwise HTTPie assumes a named session instead. - - -Readonly session ----------------- - -To use an existing session file without updating it from the request/response -exchange after it has been created, specify the session name via -``--session-read-only=SESSION_NAME_OR_PATH`` instead. - -.. code-block:: bash - - # If the session file doesn’t exist, then it is created: - $ http --session-read-only=./ro-session.json pie.dev/headers Custom-Header:orig-value - -.. code-block:: bash - - # But it is not updated: - $ http --session-read-only=./ro-session.json pie.dev/headers Custom-Header:new-value - -Cookie Storage Behaviour ------------------------- - -**TL;DR:** Cookie storage priority: Server response > Command line request > Session file - -To set a cookie within a Session there are three options: - -1. Get a ``Set-Cookie`` header in a response from a server - -.. code-block:: bash - - $ http --session=./session.json pie.dev/cookie/set?foo=bar - -2. Set the cookie name and value through the command line as seen in `cookies`_ - -.. code-block:: bash - - $ http --session=./session.json pie.dev/headers Cookie:foo=bar - -3. Manually set cookie parameters in the json file of the session - -.. code-block:: json - - { - "__meta__": { - "about": "HTTPie session file", - "help": "https://httpie.org/doc#sessions", - "httpie": "2.2.0-dev" - }, - "auth": { - "password": null, - "type": null, - "username": null - }, - "cookies": { - "foo": { - "expires": null, - "path": "/", - "secure": false, - "value": "bar" - } - } - } - -Cookies will be set in the session file with the priority specified above. For example, a cookie -set through the command line will overwrite a cookie of the same name stored -in the session file. If the server returns a ``Set-Cookie`` header with a -cookie of the same name, the returned cookie will overwrite the preexisting cookie. - -Expired cookies are never stored. If a cookie in a session file expires, it will be removed before -sending a new request. If the server expires an existing cookie, it will also be removed from the -session file. - - -Config -====== - -HTTPie uses a simple ``config.json`` file. The file doesn’t exist by default -but you can create it manually. - - -Config file directory ---------------------- - -To see the exact location for your installation, run ``http --debug`` and -look for ``config_dir`` in the output. - -The default location of the configuration file on most platforms is -``$XDG_CONFIG_HOME/httpie/config.json`` (defaulting to -``~/.config/httpie/config.json``). - -For backwards compatibility, if the directory ``~/.httpie`` exists, -the configuration file there will be used instead. - -On Windows, the config file is located at ``%APPDATA%\httpie\config.json``. - -The config directory can be changed by setting the ``$HTTPIE_CONFIG_DIR`` -environment variable: - -.. code-block:: bash - - $ export HTTPIE_CONFIG_DIR=/tmp/httpie - $ http pie.dev/get - - - -Configurable options --------------------- - -Currently HTTPie offers a single configurable option: - - -``default_options`` -~~~~~~~~~~~~~~~~~~~ - -An ``Array`` (by default empty) of default options that should be applied to -every invocation of HTTPie. - -For instance, you can use this config option to change your default color theme: - - -.. code-block:: bash - - $ cat ~/.config/httpie/config.json - - -.. code-block:: json - - { - "default_options": [ - "--style=fruity" - ] - } - - -Even though it is technically possible to include there any of HTTPie’s -options, it is not recommended to modify the default behaviour in a way -that would break your compatibility with the wider world as that can -generate a lot of confusion. - - -Un-setting previously specified options ---------------------------------------- - -Default options from the config file, or specified any other way, -can be unset for a particular invocation via ``--no-OPTION`` arguments passed -on the command line (e.g., ``--no-style`` or ``--no-session``). - - - -Scripting -========= - -When using HTTPie from shell scripts, it can be handy to set the -``--check-status`` flag. It instructs HTTPie to exit with an error if the -HTTP status is one of ``3xx``, ``4xx``, or ``5xx``. The exit status will -be ``3`` (unless ``--follow`` is set), ``4``, or ``5``, -respectively. - -.. code-block:: bash - - #!/bin/bash - - if http --check-status --ignore-stdin --timeout=2.5 HEAD pie.dev/get &> /dev/null; then - echo 'OK!' - else - case $? in - 2) echo 'Request timed out!' ;; - 3) echo 'Unexpected HTTP 3xx Redirection!' ;; - 4) echo 'HTTP 4xx Client Error!' ;; - 5) echo 'HTTP 5xx Server Error!' ;; - 6) echo 'Exceeded --max-redirects= redirects!' ;; - *) echo 'Other Error!' ;; - esac - fi - - -Best practices --------------- - -The default behaviour of automatically reading ``stdin`` is typically not -desirable during non-interactive invocations. You most likely want to -use the ``--ignore-stdin`` option to disable it. - -It is a common gotcha that without this option HTTPie seemingly hangs. -What happens is that when HTTPie is invoked for example from a cron job, -``stdin`` is not connected to a terminal. -Therefore, rules for `redirected input`_ apply, i.e., HTTPie starts to read it -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 might be good to set a connection ``--timeout`` limit to prevent -your program from hanging if the server never responds. - - - -Meta -==== - -Interface design ----------------- - -The syntax of the command arguments closely corresponds to the actual HTTP -requests sent over the wire. It has the advantage that it’s easy to remember -and read. It is often possible to translate an HTTP request to an HTTPie -argument list just by inlining the request elements. For example, compare this -HTTP request: - -.. code-block:: http - - POST /post HTTP/1.1 - Host: pie.dev - X-API-Key: 123 - User-Agent: Bacon/1.0 - Content-Type: application/x-www-form-urlencoded - - name=value&name2=value2 - - -with the HTTPie command that sends it: - -.. code-block:: bash - - $ http -f POST pie.dev/post \ - X-API-Key:123 \ - User-Agent:Bacon/1.0 \ - name=value \ - name2=value2 - - -Notice that both the order of elements and the syntax is very similar, -and that only a small portion of the command is used to control HTTPie and -doesn’t directly correspond to any part of the request (here it’s only ``-f`` -asking HTTPie to send a form request). - -The two modes, ``--pretty=all`` (default for terminal) and ``--pretty=none`` -(default for redirected output), allow for both user-friendly interactive use -and usage from scripts, where HTTPie serves as a generic HTTP client. - -As HTTPie is still under heavy development, the existing command line -syntax and some of the ``--OPTIONS`` may change slightly before -HTTPie reaches its final version ``1.0``. All changes are recorded in the -`change log`_. - - - -Community and Support ---------------------- - -HTTPie has the following community channels: - -* `GitHub issues `_ - for bug reports and feature requests. -* `Discord server `_ - to ask questions, discuss features, and for general API development discussion. -* `StackOverflow `_ - to ask questions (please make sure to use the - `httpie `_ tag). -* Tweet directly to `@httpie `_. -* You can also tweet directly to `@jakubroztocil`_. - - -Related projects ----------------- - -Dependencies -~~~~~~~~~~~~ - -Under the hood, HTTPie uses these two amazing libraries: - -* `Requests `_ - — Python HTTP library for humans -* `Pygments `_ - — Python syntax highlighter - - -HTTPie friends -~~~~~~~~~~~~~~ - -HTTPie plays exceptionally well with the following tools: - -* `http-prompt `_ - — interactive shell for HTTPie featuring autocomplete - and command syntax highlighting -* `jq `_ - — CLI JSON processor that - works great in conjunction with HTTPie - -Helpers to convert from other client tools: - -* `CurliPie `_ help convert cURL command line to HTTPie command line. - - -Alternatives -~~~~~~~~~~~~ - -* `httpcat `_ — a lower-level sister utility - of HTTPie for constructing raw HTTP requests on the command line. -* `curl `_ — a "Swiss knife" command line tool and - an exceptional library for transferring data with URLs. - - -Contributing ------------- - -See `CONTRIBUTING.rst `_. - - -Change log ----------- - -See `CHANGELOG `_. - - -Artwork -------- - -* `Logo `_ by `Cláudia Delgado `_. -* `Animation `_ by `Allen Smith `_ of GitHub. - - - -Licence -------- - -BSD-3-Clause: `LICENSE `_. - - - -Authors -------- - -`Jakub Roztocil`_ (`@jakubroztocil`_) created HTTPie and `these fine people`_ -have contributed. - - -.. _pip: https://pip.pypa.io/en/stable/installing/ -.. _GitHub API: https://developer.github.com/v3/issues/comments/#create-a-comment -.. _these fine people: https://github.com/httpie/httpie/contributors -.. _Jakub Roztocil: https://roztocil.co -.. _@jakubroztocil: https://twitter.com/jakubroztocil - - -.. |docs| image:: https://img.shields.io/badge/stable%20docs-httpie.org%2Fdocs-brightgreen?style=flat-square - :target: https://httpie.org/docs - :alt: Stable documentation - -.. |pypi| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square&label=latest%20stable%20version - :target: https://pypi.python.org/pypi/httpie - :alt: Latest version released on PyPi - -.. |coverage| image:: https://img.shields.io/codecov/c/github/httpie/httpie?style=flat-square - :target: https://codecov.io/gh/httpie/httpie - :alt: Test coverage - -.. |build| image:: https://github.com/httpie/httpie/workflows/Build/badge.svg - :target: https://github.com/httpie/httpie/actions - :alt: Build status of the master branch on Mac/Linux/Windows - -.. |gitter| image:: https://img.shields.io/badge/chat-on%20Discord-brightgreen?style=flat-square - :target: https://httpie.io/chat - :alt: Chat on Discord - -.. |downloads| image:: https://pepy.tech/badge/httpie - :target: https://pepy.tech/project/httpie - :alt: Download count diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..4da6215c81 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,1686 @@ +
      + +# HTTPie Documentation + +
      + +**HTTPie (pronounced aitch-tee-tee-pie) is a command-line HTTP client. +Its goal is to make CLI interaction with web services as human-friendly as possible. +HTTPie is designed for testing, debugging, and generally interacting with APIs & HTTP servers. +The http & https commands allow for creating and sending arbitrary HTTP requests. +They use simple and natural syntax and provide formatted and colorized output.** + +## About this document + +This documentation is best viewed at [httpie.io/docs](https://httpie.org/docs). + +You can select your corresponding HTTPie version as well as run examples directly from the browser using a [termible.io](https://termible.io?utm_source=httpie-readme) embedded terminal. + +If you are reading this on GitHub, then this text covers the current *development* version. +You are invited to submit fixes and improvements to the docs by editing [this file](https://github.com/httpie/httpie/blob/master/docs/README.md). + +## Main features + +- Expressive and intuitive syntax +- Formatted and colorized terminal output +- Built-in JSON support +- Forms and file uploads +- HTTPS, proxies, and authentication +- Arbitrary request data +- Custom headers +- Persistent sessions +- Wget-like downloads +- Linux, macOS and Windows support +- Plugins +- Documentation +- Test coverage + +## Installation + +### macOS + +On macOS, HTTPie can also be installed via [Homebrew](https://brew.sh/): + +```bash +$ brew install httpie +``` + +A MacPorts *port* is also available: + +```bash +$ port install httpie +``` + +### Linux + +Most Linux distributions provide a package that can be installed using the +system package manager, for example: + +```bash +# Debian, Ubuntu, etc. +$ apt install httpie +``` + +```bash +# Fedora +$ dnf install httpie +``` + +```bash +# CentOS, RHEL, ... +$ yum install httpie +``` + +```bash +# Gentoo +$ emerge httpie +``` + +```bash +# Arch Linux +$ pacman -S httpie +``` + +```bash +# Solus +$ eopkg install httpie +``` + +### Windows, etc. + +A universal installation method (that works on Linux, macOS and Windows, and always provides the latest version) is to use [pip](https://pypi.org/project/pip/): + +```bash +# Make sure we have an up-to-date version of pip and setuptools: +$ python -m pip install --upgrade pip setuptools + +$ python -m pip install --upgrade httpie +``` + +(If `pip` installation fails for some reason, you can try +`easy_install httpie` as a fallback.) + +Windows users can also install HTTPie with [Chocolatey](https://chocolatey.org): + +```bash +$ choco upgrade httpie +``` + +### Python version + +Python version 3.6 or greater is required. + +### 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. + +
      + +[![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%2373DC8C&label=Build&logo=github)](https://github.com/httpie/httpie/actions) + +
      + +You can install it on Linux, macOS or Windows with `pip`: + +```bash +$ python -m pip install --upgrade https://github.com/httpie/httpie/archive/master.tar.gz +``` + +Or on macOS with Homebrew: + +```bash +$ brew uninstall --force httpie +$ brew install --HEAD httpie +``` + +Verify that now you have the [current development version identifier](https://github.com/httpie/httpie/blob/master/httpie__init__.py#L6) with the `-dev` suffix, for example: + +```bash +$ http --version +# 2.5.0-dev +``` + +## Usage + +Hello World: + +```bash +$ https httpie.io/hello +``` + +Synopsis: + +```bash +$ http [flags] [METHOD] URL [ITEM [ITEM]] +``` + +See also `http --help`. + +### Examples + +Custom [HTTP method](#http-method), [HTTP headers](#http-headers) and [JSON](#json) data: + +```bash +$ http PUT pie.dev/put X-API-Token:123 name=John +``` + +Submitting [forms](#forms): + +```bash +$ http -f POST pie.dev/post hello=World +``` + +See the request that is being sent using one of the [output options](#output-options): + +```bash +$ http -v pie.dev/get +``` + +Build and print a request without sending it using [offline mode](#offline-mode): + +```bash +$ http --offline pie.dev/post hello=offline +``` + +Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comment) to post a comment on an [issue](https://github.com/httpie/httpie/issues/83) with [authentication](#authentication): + +```bash +$ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comments body='HTTPie is awesome! :heart:' +``` + +Upload a file using [redirected input](#redirected-input): + +```bash +$ http pie.dev/post < files/data.json +``` + +Download a file and save it via [redirected output](#redirected-output): + +```bash +$ http pie.dev/image/png > image.png +``` + +Download a file `wget` style: + +```bash +$ http --download pie.dev/image/png +``` + +Use named [sessions](#sessions) to make certain aspects of the communication persistent between requests to the same host: + +```bash +$ http --session=logged-in -a username:password pie.dev/get API-Key:123 +``` + +```bash +$ http --session=logged-in pie.dev/headers +``` + +Set a custom `Host` header to work around missing DNS records: + +```bash +$ http localhost:8000 Host:example.com +``` + +## HTTP method + +The name of the HTTP method comes right before the URL argument: + +```bash +$ http DELETE pie.dev/delete +``` + +Which looks similar to the actual `Request-Line` that is sent: + +```http +DELETE /delete HTTP/1.1 +``` + +When the `METHOD` argument is omitted from the command, HTTPie defaults to either `GET` (with no request data) or `POST` (with request data). + +## Request URL + +The only information HTTPie needs to perform a request is a URL. + +The default scheme is `http://` and can be omitted from the argument: + +```bash +$ http example.org +# => http://example.org +``` + +HTTPie also installs an `https` executable, where the default scheme is `https://`: + +```bash +$ https example.org +# => https://example.org +``` + +### Querystring parameters + +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. Additionally, any special characters in the parameter name or value get automatically URL-escaped (as opposed to the parameters specified in the full URL, which HTTPie doesn’t modify). + +```bash +$ http https://api.github.com/search/repositories q==httpie per_page==1 +``` + +```http +GET /search/repositories?q=httpie&per_page=1 HTTP/1.1 +``` + +### URL shortcuts for `localhost` + +Additionally, curl-like shorthand for localhost is supported. +This means that, for example, `:3000` would expand to `http://localhost:3000` +If the port is omitted, then port 80 is assumed. + +```bash +$ http :/foo +``` + +```http +GET /foo HTTP/1.1 +Host: localhost +``` + +```bash +$ http :3000/bar +``` + +```http +GET /bar HTTP/1.1 +Host: localhost:3000 +``` + +```bash +$ http : +``` + +```http +GET / HTTP/1.1 +Host: localhost +``` + +### Other default schemes + +When HTTPie is invoked as `https` then the default scheme is `https://` (`$ https example.org` will make a request to `https://example.org`). + +You can also use the `--default-scheme ` option to create shortcuts for other protocols than HTTP (possibly supported via [plugins](https://pypi.org/search/?q=httpie)). Example for the [httpie-unixsocket](https://github.com/httpie/httpie-unixsocket) plugin: + +```bash +# Before +$ http http+unix://%2Fvar%2Frun%2Fdocker.sock/info +``` + +```bash +# Create an alias +$ alias http-unix='http --default-scheme="http+unix"' +``` + +```bash +# Now the scheme can be omitted +$ http-unix %2Fvar%2Frun%2Fdocker.sock/info +``` + +### `--path-as-is` + +The standard behavior of HTTP clients is to normalize the path portion of URLs by squashing dot segments as a typically filesystem would: + +```bash +$ http -v example.org/./../../etc/password +``` + +```http +GET /etc/password HTTP/1.1 +``` + +The `--path-as-is` option allows you to disable this behavior: + +```bash +$ http --path-as-is -v example.org/./../../etc/password +``` + +```http +GET /../../etc/password HTTP/1.1 +``` + +## Request items + +There are a few different *request item* types that provide a convenient mechanism for specifying HTTP headers, simple JSON and form data, files, and URL parameters. + +They are key/value pairs specified after the URL. All have in common that they become part of the actual request that is sent and that their type is distinguished only by the separator used: `:`, `=`, `:=`, `==`, `@`, `=@`, and `:=@`. The ones with an `@` expect a file path as value. + +| Item Type | Description | +| -----------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| HTTP Headers `Name:Value` | Arbitrary HTTP header, e.g. `X-API-Token:123` | +| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. | +| Data Fields `field=value`, `field=@file.txt` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) | +| Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:=[1,2,3]` (note the quotes) | +| File upload fields `field@/dir/file`, `field@file;type=mime` | Only available with `--form`, `-f` and `--multipart`. For example `screenshot@~/Pictures/img.png`, or `'cv@cv.txt;type=text/markdown'`. With `--form`, the presence of a file field results in a `--multipart` request | + +Note that the structured data fields aren’t the only way to specify request data: +[raw request body](#raw-request-body) is a mechanism for passing arbitrary request data. + +### Escaping rules + +You can use `\` to escape characters that shouldn’t be used as separators (or parts thereof). For instance, `foo\==bar` will become a data key/value pair (`foo=` and `bar`) instead of a URL parameter. + +Often it is necessary to quote the values, e.g. `foo='bar baz'`. + +If any of the field names or headers starts with a minus (e.g. `-fieldname`), you need to place all such items after the special token `--` to prevent confusion with `--arguments`: + +```bash +$ http pie.dev/post -- -name-starting-with-dash=foo -Unusual-Header:bar +``` + +```http +POST /post HTTP/1.1 +-Unusual-Header: bar +Content-Type: application/json + +{ + "-name-starting-with-dash": "foo" +} +``` + +## JSON + +JSON is the *lingua franca* of modern web services and it is also the **implicit content type** HTTPie uses by default. + +Simple example: + +```bash +$ http PUT pie.dev/put name=John email=john@example.org +``` + +```http +PUT / HTTP/1.1 +Accept: application/json, */*;q=0.5 +Accept-Encoding: gzip, deflate +Content-Type: application/json +Host: pie.dev + +{ + "name": "John", + "email": "john@example.org" +} +``` + +### Default behavior + +If your command includes some data [request items](#request-items), they are serialized as a JSON object by default. HTTPie also automatically sets the following headers, both of which can be overwritten: + +| Header | Value | +| -------------: | ----------------------------- | +| `Content-Type` | `application/json` | +| `Accept` | `application/json, */*;q=0.5` | + +### Explicit JSON + +You can use `--json, -j` to explicitly set `Accept` to `application/json` regardless of whether you are sending data (it’s a shortcut for setting the header via the usual header notation: `http url Accept:'application/json, */*;q=0.5'`). +Additionally, HTTPie will try to detect JSON responses even when the `Content-Type` is incorrectly `text/plain` or unknown. + +### Non-string JSON fields + +Non-string JSON fields use the `:=` separator, which allows you to embed arbitrary JSON data into the resulting JSON object. +Additionally, text and raw JSON files can also be embedded into fields using `=@` and `:=@`: + +```bash +$ http PUT pie.dev/put \ + name=John \ # String (default) + age:=29 \ # Raw JSON — Number + married:=false \ # Raw JSON — Boolean + hobbies:='["http", "pies"]' \ # Raw JSON — Array + favorite:='{"tool": "HTTPie"}' \ # Raw JSON — Object + bookmarks:=@files/data.json \ # Embed JSON file + description=@files/text.txt # Embed text file +``` + +```http +PUT /person/1 HTTP/1.1 +Accept: application/json, */*;q=0.5 +Content-Type: application/json +Host: pie.dev + +{ + "age": 29, + "hobbies": [ + "http", + "pies" + ], + "description": "John is a nice guy who likes pies.", + "married": false, + "name": "John", + "favorite": { + "tool": "HTTPie" + }, + "bookmarks": { + "HTTPie": "https://httpie.org", + } +} +``` + +### Raw and complex JSON + +Please note that with the [request items](#request-items) data field syntax, commands can quickly become unwieldy when sending complex structures. +In such cases, it’s better to pass the full raw JSON data via [raw request body](#raw-request-body), for example: + +```bash +$ echo -n '{"hello": "world"}' | http POST pie.dev/post +``` + +```bash +$ http --raw '{"hello": "world"}' POST pie.dev/post +``` + +```bash +$ http POST pie.dev/post < files/data.json +``` + +Furthermore, the structure syntax only allows you to send an object as the JSON document, but not an array, etc. +Here, again, the solution is to use [redirected input](#redirected-input). + +## Forms + +Submitting forms is very similar to sending [JSON](#json) requests. +Often the only difference is in adding the `--form, -f` option, which ensures that data fields are serialized as, and `Content-Type` is set to `application/x-www-form-urlencoded; charset=utf-8`. +It is possible to make form data the implicit content type instead of JSON via the [config](#config) file. + +### Regular forms + +```bash +$ http --form POST pie.dev/post name='John Smith' +``` + +```http +POST /post HTTP/1.1 +Content-Type: application/x-www-form-urlencoded; charset=utf-8 + +name=John+Smith +``` + +### File upload forms + +If one or more file fields is present, the serialization and content type is `multipart/form-data`: + +```bash +$ http -f POST pie.dev/post name='John Smith' cv@~/files/data.xml +``` + +The request above is the same as if the following HTML form were submitted: + +```html +
      + + +
      +``` + +Please note that `@` is used to simulate a file upload form field, whereas `=@` just embeds the file content as a regular text field value. + +When uploading files, their content type is inferred from the file name. You can manually override the inferred content type: + +```bash +$ http -f POST pie.dev/post name='John Smith' cv@'~/files/data.bin;type=application/pdf' +``` + +To perform a `multipart/form-data` request even without any files, use `--multipart` instead of `--form`: + +```bash +$ http --multipart --offline example.org hello=world +``` + +```http +POST / HTTP/1.1 +Content-Length: 129 +Content-Type: multipart/form-data; boundary=c31279ab254f40aeb06df32b433cbccb +Host: example.org + +--c31279ab254f40aeb06df32b433cbccb +Content-Disposition: form-data; name="hello" + +world +--c31279ab254f40aeb06df32b433cbccb-- +``` + +File uploads are always streamed to avoid memory issues with large files. + +By default, HTTPie uses a random unique string as the multipart boundary but you can use `--boundary` to specify a custom string instead: + +```bash +$ http --form --multipart --boundary=xoxo --offline example.org hello=world +``` + +```http +POST / HTTP/1.1 +Content-Length: 129 +Content-Type: multipart/form-data; boundary=xoxo +Host: example.org + +--xoxo +Content-Disposition: form-data; name="hello" + +world +--xoxo-- +``` + +If you specify a custom `Content-Type` header without including the boundary bit, HTTPie will add the boundary value (explicitly specified or auto-generated) to the header automatically: + +```bash +$ http --form --multipart --offline example.org hello=world Content-Type:multipart/letter +``` + +```http +POST / HTTP/1.1 +Content-Length: 129 +Content-Type: multipart/letter; boundary=c31279ab254f40aeb06df32b433cbccb +Host: example.org + +--c31279ab254f40aeb06df32b433cbccb +Content-Disposition: form-data; name="hello" + +world +--c31279ab254f40aeb06df32b433cbccb-- +``` + +## HTTP headers + +To set custom headers you can use the `Header:Value` notation: + +```bash +$ http pie.dev/headers User-Agent:Bacon/1.0 'Cookie:valued-visitor=yes;foo=bar' \ + X-Foo:Bar Referer:https://httpie.org/ +``` + +```http +GET /headers HTTP/1.1 +Accept: */* +Accept-Encoding: gzip, deflate +Cookie: valued-visitor=yes;foo=bar +Host: pie.dev +Referer: https://httpie.org/ +User-Agent: Bacon/1.0 +X-Foo: Bar +``` + +### Default request headers + +There are a couple of default headers that HTTPie sets: + +```http +GET / HTTP/1.1 +Accept: */* +Accept-Encoding: gzip, deflate +User-Agent: HTTPie/ +Host: +``` + +Any of these can be overwritten and some of them unset (see below). + +### Empty headers and header un-setting + +To unset a previously specified header (such a one of the default headers), use `Header:`: + +```bash +$ http pie.dev/headers Accept: User-Agent: +``` + +To send a header with an empty value, use `Header;`, with a semicolon: + +```bash +$ http pie.dev/headers 'Header;' +``` + +### Limiting response headers + +The `--max-headers=n` options allows you to control the number of headers HTTPie reads before giving up (the default `0`, i.e., there’s no limit). + +```bash +$ http --max-headers=100 pie.dev/get +``` + +## Offline mode + +Use `--offline` to construct HTTP requests without sending them anywhere. +With `--offline`, HTTPie builds a request based on the specified options and arguments, prints it to `stdout`, and then exits. It works completely offline; no network connection is ever made. This has a number of use cases, including: + +Generating API documentation examples that you can copy & paste without sending a request: + +```bash +$ http --offline POST server.chess/api/games API-Key:ZZZ w=magnus b=hikaru t=180 i=2 +``` + +```bash +$ http --offline MOVE server.chess/api/games/123 API-Key:ZZZ p=b a=R1a3 t=77 +``` + +Generating raw requests that can be sent with any other client: + +```bash +# 1. save a raw request to a file: +$ http --offline POST pie.dev/post hello=world > request.http +``` + +```bash +# 2. send it over the wire with, for example, the fantastic netcat tool: +$ nc pie.dev 80 < request.http +``` + +You can also use the `--offline` mode for debugging and exploring HTTP and HTTPie, and for “dry runs”. + +`--offline` has the side-effect of automatically activating `--print=HB`, i.e., both the request headers and the body +are printed. You can customize the output with the usual [output options](#output-options), with the exception where there +is no response to be printed. You can use `--offline` in combination with all the other options (e.g. `--session`). + +## Cookies + +HTTP clients send cookies to the server as regular [HTTP headers](#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: + +```bash +$ http pie.dev/cookies Cookie:sessionid=foo +``` + +```http +GET / HTTP/1.1 +Accept: */* +Accept-Encoding: gzip, deflate +Connection: keep-alive +Cookie: sessionid=foo +Host: pie.dev +User-Agent: HTTPie/0.9.9 +``` + +Send multiple cookies (note: the header is quoted to prevent the shell from interpreting the `;`): + +```bash +$ http pie.dev/cookies 'Cookie:sessionid=foo;another-cookie=bar' +``` + +```http +GET / HTTP/1.1 +Accept: */* +Accept-Encoding: gzip, deflate +Connection: keep-alive +Cookie: sessionid=foo;another-cookie=bar +Host: pie.dev +User-Agent: HTTPie/0.9.9 +``` + +If you often deal with cookies in your requests, then you’d appreciate +the [sessions](#sessions) feature. + +## Authentication + +The currently supported authentication schemes are Basic and Digest (see [auth plugins](#auth-plugins) for more). There are two flags that control authentication: + +| Flag | Arguments | +| ----------------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--auth, -a` | Pass a `username:password` pair as the argument. Or, if you only specify a username (`-a username`), you’ll be prompted for the password before the request is sent. To send an empty password, pass `username:`. The `username:password@hostname` URL syntax is supported as well (but credentials passed via `-a` have higher priority) | +| `--auth-type, -A` | Specify the auth mechanism. Possible values are `basic`, `digest`, or the name of any [auth plugins](#auth-plugins) you have installed. The default value is `basic` so it can often be omitted | + +### Basic auth + +```bash +$ http -a username:password pie.dev/basic-auth/username/password +``` + +### Digest auth + +```bash +$ http -A digest -a username:password pie.dev/digest-auth/httpie/username/password +``` + +### Password prompt + +```bash +$ http -a username pie.dev/basic-auth/username/password +``` + +### Empty password + +```bash +$ http -a username: pie.dev/headers +``` + +### `.netrc` + +Authentication information from your `~/.netrc` file is by default honored as well. + +For example: + +```bash +$ cat ~/.netrc +machine pie.dev +login httpie +password test +``` + +```bash +$ http pie.dev/basic-auth/httpie/test +HTTP/1.1 200 OK +[...] +``` + +This can be disabled with the `--ignore-netrc` option: + +```bash +$ http --ignore-netrc pie.dev/basic-auth/httpie/test +HTTP/1.1 401 UNAUTHORIZED +[...] +``` + +### Auth plugins + +Additional authentication mechanism can be installed as plugins. +They can be found on the [Python Package Index](https://pypi.python.org/pypi?%3Aaction=search&term=httpie&submit=search). +Here are a few picks: + +- [httpie-api-auth](https://github.com/pd/httpie-api-auth): ApiAuth +- [httpie-aws-auth](https://github.com/httpie/httpie-aws-auth): AWS / Amazon S3 +- [httpie-edgegrid](https://github.com/akamai-open/httpie-edgegrid): EdgeGrid +- [httpie-hmac-auth](https://github.com/guardian/httpie-hmac-auth): HMAC +- [httpie-jwt-auth](https://github.com/teracyhq/httpie-jwt-auth): JWTAuth (JSON Web Tokens) +- [httpie-negotiate](https://github.com/ndzou/httpie-negotiate): SPNEGO (GSS Negotiate) +- [httpie-ntlm](https://github.com/httpie/httpie-ntlm): NTLM (NT LAN Manager) +- [httpie-oauth](https://github.com/httpie/httpie-oauth): OAuth +- [requests-hawk](https://github.com/mozilla-services/requests-hawk): Hawk + +## HTTP redirects + +By default, HTTP redirects are not followed and only the first +response is shown: + +```bash +$ http pie.dev/redirect/3 +``` + +### Follow `Location` + +To instruct HTTPie to follow the `Location` header of `30x` responses +and show the final response instead, use the `--follow, -F` option: + +```bash +$ http --follow pie.dev/redirect/3 +``` + +With `307 Temporary Redirect` and `308 Permanent Redirect`, the method and the body of the original request +are reused to perform the redirected request. Otherwise, a body-less `GET` request is performed. + +### Showing intermediary redirect responses + +If you wish to see the intermediary requests/responses, +then use the `--all` option: + +```bash +$ http --follow --all pie.dev/redirect/3 +``` + +### Limiting maximum redirects followed + +To change the default limit of maximum `30` redirects, use the `--max-redirects=` option: + +```bash +$ http --follow --all --max-redirects=2 pie.dev/redirect/3 +``` + +## Proxies + +You can specify proxies to be used through the `--proxy` argument for each protocol (which is included in the value in case of redirects across protocols): + +```bash +$ http --proxy=http:http://10.10.1.10:3128 --proxy=https:https://10.10.1.10:1080 example.org +``` + +With Basic authentication: + +```bash +$ http --proxy=http:http://user:pass@10.10.1.10:3128 example.org +``` + +### Environment variables + +You can also configure proxies by environment variables `ALL_PROXY`, `HTTP_PROXY` and `HTTPS_PROXY`, and the underlying [Requests library](https://python-requests.org/) will pick them up. +If you want to disable proxies configured through the environment variables for certain hosts, you can specify them in `NO_PROXY`. + +In your `~/.bash_profile`: + +```bash +export HTTP_PROXY=http://10.10.1.10:3128 +export HTTPS_PROXY=https://10.10.1.10:1080 +export NO_PROXY=localhost,example.com +``` + +### SOCKS + +Usage for SOCKS is the same as for other types of [proxies](#proxies): + +```bash +$ http --proxy=http:socks5://user:pass@host:port --proxy=https:socks5://user:pass@host:port example.org +``` + +## HTTPS + +### Server SSL certificate verification + +To skip the host’s SSL certificate verification, you can pass `--verify=no` (default is `yes`): + +```bash +$ http --verify=no https://pie.dev/get +``` + +### Custom CA bundle + +You can also use `--verify=` to set a custom CA bundle path: + +```bash +$ http --verify=/ssl/custom_ca_bundle https://example.org +``` + +### Client side SSL certificate + +To use a client side certificate for the SSL communication, you can pass +the path of the cert file with `--cert`: + +```bash +$ http --cert=client.pem https://example.org +``` + +If the private key is not contained in the cert file, you may pass the +path of the key file with `--cert-key`: + +```bash +$ http --cert=client.crt --cert-key=client.key https://example.org +``` + +### SSL version + +Use the `--ssl=` option 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`, `tls1.3`. +(The actually available set of protocols may vary depending on your OpenSSL installation.) + +```bash +# Specify the vulnerable SSL v3 protocol to talk to an outdated server: +$ http --ssl=ssl3 https://vulnerable.example.org +``` + +### SSL ciphers + +You can specify the available ciphers with `--ciphers`. +It should be a string in the [OpenSSL cipher list format](https://www.openssl.org/docs/man1.1.0/man1/ciphers.html). + +```bash +$ http --ciphers=ECDHE-RSA-AES128-GCM-SHA256 https://pie.dev/get +``` + +Note: these cipher strings do not change the negotiated version of SSL or TLS, they only affect the list of available cipher suites. + +To see the default cipher string, run `http --help` and see the `--ciphers` section under SSL. + +## Output options + +By default, HTTPie only outputs the final response and the whole response +message is printed (headers as well as the body). You can control what should +be printed via several options: + +| Option | What is printed | +| --------------: | -------------------------------------------------------------------------------------------------- | +| `--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 below) | +| `--print, -p` | Selects parts of the HTTP exchange | +| `--quiet, -q` | Don't print anything to `stdout` and `stderr` | + +### What parts of the HTTP exchange should be printed + +All the other [output options](#output-options) are under the hood just shortcuts for the more powerful `--print, -p`. +It accepts a string of characters each of which represents a specific part of the HTTP exchange: + +| Character | Stands for | +| --------: | ---------------- | +| `H` | request headers | +| `B` | request body | +| `h` | response headers | +| `b` | response body | + +Print request and response headers: + +```bash +$ http --print=Hh PUT pie.dev/put hello=world +``` + +### Verbose output + +`--verbose` can often be useful for debugging the request and generating documentation examples: + +```bash +$ http --verbose PUT pie.dev/put hello=world +PUT /put HTTP/1.1 +Accept: application/json, */*;q=0.5 +Accept-Encoding: gzip, deflate +Content-Type: application/json +Host: pie.dev +User-Agent: HTTPie/0.2.7dev + +{ + "hello": "world" +} + +HTTP/1.1 200 OK +Connection: keep-alive +Content-Length: 477 +Content-Type: application/json +Date: Sun, 05 Aug 2012 00:25:23 GMT +Server: gunicorn/0.13.4 + +{ + […] +} +``` + +### Quiet output + +`--quiet` redirects all output that would otherwise go to `stdout` and `stderr` to `/dev/null` (except for errors and warnings). +This doesn’t affect output to a file via `--output` or `--download`. + +```bash +# There will be no output: +$ http --quiet pie.dev/post enjoy='the silence' +``` + +### Viewing intermediary requests/responses + +To see all the HTTP communication, i.e. the final request/response as well as any possible intermediary requests/responses, use the `--all` option. +The intermediary HTTP communication include followed redirects (with `--follow`), the first unauthorized request when HTTP digest authentication is used (`--auth=digest`), etc. + +```bash +# Include all responses that lead to the final one: +$ http --all --follow pie.dev/redirect/3 +``` + +The intermediary requests/responses are by default formatted according to `--print, -p` (and its shortcuts described above). + +If you’d like to change that, use the `--history-print, -P` option. +It takes the same arguments as `--print, -p` but applies to the intermediary requests only. + +```bash +# Print the intermediary requests/responses differently than the final one: +$ http -A digest -a foo:bar --all -p Hh -P H pie.dev/digest-auth/auth/foo/bar +``` + +### Conditional body download + +As an optimization, the response body is downloaded from the server only if it’s part of the output. +This is similar to performing a `HEAD` request, except that it applies to any HTTP method you use. + +Let’s say that there is an API that returns the whole resource when it is updated, but you are only interested in the response headers to see the status code after an update: + +```bash +$ http --headers PATCH pie.dev/patch name='New Name' +``` + +Since you are only printing the HTTP headers here, the connection to the server is closed as soon as all the response headers have been received. +Therefore, bandwidth and time isn’t wasted downloading the body which you don’t care about. +The response headers are downloaded always, even if they are not part of the output + +## Raw request body + +In addition to crafting structured [JSON](#json) and [forms](#forms) requests with the [request items](#request-items) syntax, you can provide a raw request body that will be sent without further processing. +These two approaches for specifying request data (i.e., structured and raw) cannot be combined. + +There’re three methods for passing raw request data: piping via `stdin`, +`--raw='data'`, and `@/file/path`. + +### Redirected Input + +The universal method for passing request data is through redirected `stdin` +(standard input)—piping. + +By default, `stdin` data is buffered and then with no further processing used as the request body. +If you provide `Content-Length`, then the request body is streamed without buffering. +You may also use `--chunked` to enable streaming via [chunked transfer encoding](#chunked-transfer-encoding). + +There are multiple useful ways to use piping: + +Redirect from a file: + +```bash +$ http PUT pie.dev/put X-API-Token:123 < files/data.json +``` + +Or the output of another program: + +```bash +$ grep '401 Unauthorized' /var/log/httpd/error_log | http POST pie.dev/post +``` + +You can use `echo` for simple data: + +```bash +$ echo -n '{"name": "John"}' | http PATCH pie.dev/patch X-API-Token:123 +``` + +You can also use a Bash *here string*: + +```bash +$ http pie.dev/post <<<'{"name": "John"}' +``` + +You can even pipe web services together using HTTPie: + +```bash +$ http GET https://api.github.com/repos/httpie/httpie | http POST pie.dev/post +``` + +You can use `cat` to enter multiline data on the terminal: + +```bash +$ cat | http POST pie.dev/post + +^D +``` + +```bash +$ cat | http POST pie.dev/post Content-Type:text/plain +- buy milk +- call parents +^D +``` + +On macOS, you can send the contents of the clipboard with `pbpaste`: + +```bash +$ pbpaste | http PUT pie.dev/put +``` + +Passing data through `stdin` **can't** be combined with data fields specified on the command line: + +```bash +$ echo -n 'data' | http POST example.org more=data # This is invalid +``` + +To prevent HTTPie from reading `stdin` data you can use the `--ignore-stdin` option. + +### Request data via `--raw` + +In a situation when piping data via `stdin` is not convenient (for example, +when generating API docs examples), you can specify the raw request body via +the `--raw` option. + +```bash +$ http --raw 'Hello, world!' pie.dev/post +``` + +```bash +$ http --raw '{"name": "John"}' pie.dev/post +``` + +### Request data from a filename + +An alternative to redirected `stdin` is specifying a filename (as `@/path/to/file`) whose content is used as if it came from `stdin`. + +It has the advantage that the `Content-Type` header is automatically set to the appropriate value based on the filename extension. +For example, the following request sends the verbatim contents of that XML file with `Content-Type: application/xml`: + +```bash +$ http PUT pie.dev/put @files/data.xml +``` + +File uploads are always streamed to avoid memory issues with large files. + +## Chunked transfer encoding + +You can use the `--chunked` flag to instruct HTTPie to use `Transfer-Encoding: chunked`: + +```bash +$ http --chunked PUT pie.dev/put hello=world +``` + +```bash +$ http --chunked --multipart PUT pie.dev/put hello=world foo@files/data.xml +``` + +```bash +$ http --chunked pie.dev/post @files/data.xml +``` + +```bash +$ cat files/data.xml | http --chunked pie.dev/post +``` + +## Terminal output + +HTTPie does several things by default in order to make its terminal output easy to read. + +### Colors and formatting + +Syntax highlighting is applied to HTTP headers and bodies (where it makes sense). +You can choose your preferred color scheme via the `--style` option if you don’t like the default one. +There are dozens of styles available, here are just a few notable ones: + +| Style | Description | +| --------: | ----------------------------------------------------------------------------------------------------------------------------------- | +| `auto` | Follows your terminal ANSI color styles. This is the default style used by HTTPie | +| `default` | Default styles of the underlying Pygments library. Not actually used by default by HTTPie. You can enable it with `--style=default` | +| `monokai` | A popular color scheme. Enable with `--style=monokai` | +| `fruity` | A bold, colorful scheme. Enable with `--style=fruity` | +| … | See `$ http --help` for all the possible `--style` values | + +Also, the following formatting is applied: + +- HTTP headers are sorted by name. +- JSON data is indented, sorted by keys, and unicode escapes are converted + to the characters they represent. + +Use one of these options to control output processing: + +| Option | Description | +| ----------------: | ------------------------------------------------------------- | +| `--pretty=all` | Apply both colors and formatting. Default for terminal output | +| `--pretty=colors` | Apply colors | +| `--pretty=format` | Apply formatting | +| `--pretty=none` | Disables output processing. Default for redirected output | + +You can further control the applied formatting via the more granular [format options](#format-options). + +### Format options + +The `--format-options=opt1:value,opt2:value` option allows you to control how the output should be formatted +when formatting is applied. The following options are available: + +| Option | Default value | Shortcuts | +| ---------------: | :-----------: | ------------------------ | +| `headers.sort` | `true` | `--sorted`, `--unsorted` | +| `json.format` | `true` | N/A | +| `json.indent` | `4` | N/A | +| `json.sort_keys` | `true` | `--sorted`, `--unsorted` | +| `xml.format` | `true` | N/A | +| `xml.indent` | `2` | N/A | + +For example, this is how you would disable the default header and JSON key +sorting, and specify a custom JSON indent size: + +```bash +$ http --format-options headers.sort:false,json.sort_keys:false,json.indent:2 pie.dev/get +``` + +There are also two shortcuts that allow you to quickly disable and re-enable +sorting-related format options (currently it means JSON keys and headers): +`--unsorted` and `--sorted`. + +This is something you will typically store as one of the default options in your [config](#config) file. + +### Binary data + +Binary data is suppressed for terminal output, which makes it safe to perform requests to URLs that send back binary data. +Binary data is also suppressed in redirected but prettified output. +The connection is closed as soon as we know that the response body is binary, + +```bash +$ http pie.dev/bytes/2000 +``` + +You will nearly instantly see something like this: + +```http +HTTP/1.1 200 OK +Content-Type: application/octet-stream + ++-----------------------------------------+ +| NOTE: binary data not shown in terminal | ++-----------------------------------------+ +``` + +### Redirected output + +HTTPie uses a different set of defaults for redirected output than for [terminal output](#terminal-output). +The differences being: + +- Formatting and colors aren’t applied (unless `--pretty` is specified). +- Only the response body is printed (unless one of the [output options](#output-options) is set). +- Also, binary data isn’t suppressed. + +The reason is to make piping HTTPie’s output to another programs and downloading files work with no extra flags. +Most of the time, only the raw response body is of an interest when the output is redirected. + +Download a file: + +```bash +$ http pie.dev/image/png > image.png +``` + +Download an image of an [Octocat](https://octodex.github.com/images/original.jpg), resize it using [ImageMagick](https://imagemagick.org/), and upload it elsewhere: + +```bash +$ http octodex.github.com/images/original.jpg | convert - -resize 25% - | http example.org/Octocats +``` + +Force colorizing and formatting, and show both the request and the response in `less` pager: + +```bash +$ http --pretty=all --verbose pie.dev/get | less -R +``` + +The `-R` flag tells `less` to interpret color escape sequences included HTTPie’s output. + +You can create a shortcut for invoking HTTPie with colorized and paged output by adding the following to your `~/.bash_profile`: + +```bash +function httpless { + # `httpless example.org' + http --pretty=all --print=hb "$@" | less -R; +} +``` + +## Download mode + +HTTPie features a download mode in which it acts similarly to `wget`. + +When enabled using the `--download, -d` flag, response headers are printed to the terminal (`stderr`), and a progress bar is shown while the response body is being saved to a file. + +```bash +$ http --download https://github.com/httpie/httpie/archive/master.tar.gz +``` + +```http +HTTP/1.1 200 OK +Content-Disposition: attachment; filename=httpie-master.tar.gz +Content-Length: 257336 +Content-Type: application/x-gzip + +Downloading 251.30 kB to "httpie-master.tar.gz" +Done. 251.30 kB in 2.73862s (91.76 kB/s) +``` + +### Downloaded filename + +There are three mutually exclusive ways through which HTTPie determines +the output filename (with decreasing priority): + +1. You can explicitly provide it via `--output, -o`. The file gets overwritten if it already exists (or appended to with `--continue, -c`). +2. The server may specify the filename in the optional `Content-Disposition` response header. Any leading dots are stripped from a server-provided filename. +3. The last resort HTTPie uses is to generate the filename from a combination of the request URL and the response `Content-Type`. The initial URL is always used as the basis for the generated filename — even if there has been one or more redirects. + +To prevent data loss by overwriting, HTTPie adds a unique numerical suffix to the filename when necessary (unless specified with `--output, -o`). + +### Piping while downloading + +You can also redirect the response body to another program while the response headers and progress are still shown in the terminal: + +```bash +$ http -d https://github.com/httpie/httpie/archive/master.tar.gz | tar zxf - +``` + +### Resuming downloads + +If `--output, -o` is specified, you can resume a partial download using the `--continue, -c` option. +This only works with servers that support `Range` requests and `206 Partial Content` responses. +If the server doesn’t support that, the whole file will simply be downloaded: + +```bash +$ http -dco file.zip example.org/file +``` + +`-dco` is shorthand for `--download` `--continue` `--output`. + +### Other notes + +- The `--download` option only changes how the response body is treated. +- You can still set custom headers, use sessions, `--verbose, -v`, etc. +- `--download` always implies `--follow` (redirects are followed). +- `--download` also implies `--check-status` (error HTTP status will result in a non-zero exist static code). +- HTTPie exits with status code `1` (error) if the body hasn’t been fully downloaded. +- `Accept-Encoding` can't be set with `--download`. + +## Streamed responses + +Responses are downloaded and printed in chunks. +This allows for streaming and large file downloads without using too much memory. +However, when [colors and formatting](#colors-and-formatting) are applied, the whole response is buffered and only then processed at once. + +### Disabling buffering + +You can use the `--stream, -S` flag to make two things happen: + +1. The output is flushed in much smaller chunks without any buffering, which makes HTTPie behave kind of like `tail -f` for URLs. +2. Streaming becomes enabled even when the output is prettified: It will be applied to each line of the response and flushed immediately. This makes it possible to have a nice output for long-lived requests, such as one to the [Twitter streaming API](https://developer.twitter.com/en/docs/tutorials/consuming-streaming-data). + +### Example use cases + +Prettified streamed response: + +```bash +$ http --stream pie.dev/stream/3 +``` + +Streamed output by small chunks à la `tail -f`: + +```bash +# Send each new line (JSON object) to another URL as soon as it arrives from a streaming API: +$ http --stream pie.dev/stream/3 | while read line; do echo "$line" | http pie.dev/post ; done +``` + +## Sessions + +By default, every request HTTPie makes is completely independent of any previous ones to the same host. + +However, HTTPie also supports persistent sessions via the `--session=SESSION_NAME_OR_PATH` option. +In a session, custom [HTTP headers](#http-headers) (except for the ones starting with `Content-` or `If-`), [authentication](#authentication), and [cookies](#cookies) (manually specified or sent by the server) persist between requests to the same host. + +```bash +# Create a new session: +$ http --session=./session.json pie.dev/headers API-Token:123 +``` + +```bash +# Inspect / edit the generated session file: +$ cat session.json +``` + +```bash +# Re-use the existing session — the API-Token header will be set: +$ http --session=./session.json pie.dev/headers +``` + +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. +It also means that they can be read by anyone who has access to the session file. + +### Named sessions + +You can create one or more named session per host. For example, this is how you can create a new session named `user1` for `pie.dev`: + +```bash +$ http --session=user1 -a user1:password pie.dev/get X-Foo:Bar +``` + +From now on, you can refer to the session by its name (`user1`). +When you choose to use the session again, all previously specified authentication or HTTP headers will automatically be set: + +```bash +$ http --session=user1 pie.dev/get +``` + +To create or reuse a different session, simply specify a different name: + +```bash +$ http --session=user2 -a user2:password pie.dev/get X-Bar:Foo +``` + +Named sessions’ data is stored in JSON files inside the `sessions` subdirectory of the [config](#config) directory, typically `~/.config/httpie/sessions//.json` (`%APPDATA%\httpie\sessions\\.json` on Windows). + +If you have executed the above commands on a Unix machine, you should be able list the generated sessions files using: + +```bash +$ ls -l ~/.config/httpie/sessions/pie.dev +``` + +### Anonymous sessions + +Instead of giving it a name, you can also directly specify a path to a session file. +This allows for sessions to be re-used across multiple hosts: + +```bash +# Create a session: +$ http --session=/tmp/session.json example.org +``` + +```bash +# Use the session to make a request to another host: +$ http --session=/tmp/session.json admin.example.org +``` + +```bash +# You can also refer to a previously created named session: +$ http --session=~/.config/httpie/sessions/another.example.org/test.json example.org +``` + +When creating anonymous sessions, please remember to always include at least one `/`, even if the session files is located in the current directory (i.e. `--session=./session.json` instead of just `--session=session.json`), otherwise HTTPie assumes a named session instead. + +### Readonly session + +To use the original session file without updating it from the request/response exchange after it has been created, specify the session name via `--session-read-only=SESSION_NAME_OR_PATH` instead. + +```bash +# If the session file doesn’t exist, then it is created: +$ http --session-read-only=./ro-session.json pie.dev/headers Custom-Header:orig-value +``` + +```bash +# But it is not updated: +$ http --session-read-only=./ro-session.json pie.dev/headers Custom-Header:new-value +``` + +### Cookie Storage Behavior + +**TL;DR:** Cookie storage priority: Server response > Command line request > Session file + +To set a cookie within a Session there are three options: + +1. Get a `Set-Cookie` header in a response from a server + +```bash +$ http --session=./session.json pie.dev/cookie/set?foo=bar +``` + +2. Set the cookie name and value through the command line as seen in [cookies](#cookies) + +```bash +$ http --session=./session.json pie.dev/headers Cookie:foo=bar +``` + +3. Manually set cookie parameters in the JSON file of the session + +```json +{ + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.org/doc#sessions", + "httpie": "2.2.0-dev" + }, + "auth": { + "password": null, + "type": null, + "username": null + }, + "cookies": { + "foo": { + "expires": null, + "path": "/", + "secure": false, + "value": "bar" + } + } +} +``` + +Cookies will be set in the session file with the priority specified above. +For example, a cookie set through the command line will overwrite a cookie of the same name stored in the session file. +If the server returns a `Set-Cookie` header with a cookie of the same name, the returned cookie will overwrite the preexisting cookie. + +Expired cookies are never stored. +If a cookie in a session file expires, it will be removed before sending a new request. +If the server expires an existing cookie, it will also be removed from the session file. + +## Config + +HTTPie uses a simple `config.json` file. +The file doesn’t exist by default but you can create it manually. + +### Config file directory + +To see the exact location for your installation, run `http --debug` and look for `config_dir` in the output. + +The default location of the configuration file on most platforms is `$XDG_CONFIG_HOME/httpie/config.json` (defaulting to `~/.config/httpie/config.json`). + +For backwards compatibility, if the directory `~/.httpie` exists, the configuration file there will be used instead. + +On Windows, the config file is located at `%APPDATA%\httpie\config.json`. + +The config directory can be changed by setting the `$HTTPIE_CONFIG_DIR` environment variable: + +```bash +$ export HTTPIE_CONFIG_DIR=/tmp/httpie +$ http pie.dev/get +``` + +### Configurable options + +Currently, HTTPie offers a single configurable option: + +#### `default_options` + +An `Array` (by default empty) of default options that should be applied to every invocation of HTTPie. + +For instance, you can use this config option to change your default color theme: + +```bash +$ cat ~/.config/httpie/config.json +``` + +```json +{ + "default_options": [ + "--style=fruity" + ] +} +``` + +Technically, it is possible to include any HTTPie options in there. +However, it is not recommended to modify the default behavior in a way that would break your compatibility with the wider world as that may become confusing. + +### Un-setting previously specified options + +Default options from the config file, or specified any other way, can be unset for a particular invocation via `--no-OPTION` arguments passed via the command line (e.g., `--no-style` or `--no-session`). + +## Scripting + +When using HTTPie from shell scripts, it can be handy to set the `--check-status` flag. +It instructs HTTPie to exit with an error if the HTTP status is one of `3xx`, `4xx`, or `5xx`. +The exit status will be `3` (unless `--follow` is set), `4`, or `5`, respectively. + +```bash +#!/bin/bash + +if http --check-status --ignore-stdin --timeout=2.5 HEAD pie.dev/get &> /dev/null; then + echo 'OK!' +else + case $? in + 2) echo 'Request timed out!' ;; + 3) echo 'Unexpected HTTP 3xx Redirection!' ;; + 4) echo 'HTTP 4xx Client Error!' ;; + 5) echo 'HTTP 5xx Server Error!' ;; + 6) echo 'Exceeded --max-redirects= redirects!' ;; + *) echo 'Other Error!' ;; + esac +fi +``` + +### Best practices + +The default behavior of automatically reading `stdin` is typically not desirable during non-interactive invocations. +You most likely want to use the `--ignore-stdin` option to disable it. + +It is a common *gotcha* that without this option HTTPie seemingly hangs. +What happens is that when HTTPie is invoked, for example, from a cron job, `stdin` is not connected to a terminal. +Therefore, the rules for [redirected input](#redirected-input) apply, i.e. HTTPie starts to read it expecting that the request body will be passed through. +And since there’s neither data nor `EOF`, it will get stuck. So unless you’re piping some data to HTTPie, the `--ignore-stdin` flag should be used in scripts. + +Also, it might be good to set a connection `--timeout` limit to prevent your program from hanging if the server never responds. + +## Meta + +### Interface design + +The syntax of the command arguments closely correspond to the actual HTTP requests sent over the wire. +It has the advantage that it’s easy to remember and read. +You can often translate an HTTP request to an HTTPie argument list just by inlining the request elements. +For example, compare this HTTP request: + +```http +POST /post HTTP/1.1 +Host: pie.dev +X-API-Key: 123 +User-Agent: Bacon/1.0 +Content-Type: application/x-www-form-urlencoded + +name=value&name2=value2 +``` + +with the HTTPie command that sends it: + +```bash +$ http -f POST pie.dev/post \ + X-API-Key:123 \ + User-Agent:Bacon/1.0 \ + name=value \ + name2=value2 +``` + +Notice that both the order of elements and the syntax are very similar, and that only a small portion of the command is used to control HTTPie and doesn’t directly correspond to any part of the request (here, it’s only `-f` asking HTTPie to send a form request). + +The two modes, `--pretty=all` (default for terminal) and `--pretty=none` (default for [redirected output](#redirected-output)), allow for both user-friendly interactive use and usage from scripts, where HTTPie serves as a generic HTTP client. + +In the future, the command line syntax and some of the `--OPTIONS` may change slightly, as HTTPie improves and new features are added. +All changes are recorded in the [change log](#change-log). + +### Community and Support + +HTTPie has the following community channels: + +- [GitHub Issues](https://github.com/jkbr/httpie/issues) for bug reports and feature requests +- [Discord server](https://httpie.io/chat) to ask questions, discuss features, and for general API development discussion +- [StackOverflow](https://stackoverflow.com) to ask questions (make sure to use the [httpie](https://stackoverflow.com/questions/tagged/httpie) tag) +- Twitter; where you can tweet directly to (and follow!) [@httpie](https://twitter.com/httpie) + +### Related projects + +#### Dependencies + +Under the hood, HTTPie uses these two amazing libraries: + +- [Requests](https://python-requests.org) — Python HTTP library for humans +- [Pygments](https://pygments.org/) — Python syntax highlighter + +#### HTTPie friends + +HTTPie plays exceptionally well with the following tools: + +- [http-prompt](https://github.com/httpie/http-prompt) — an interactive shell for HTTPie featuring autocomplete and command syntax highlighting +- [jq](https://stedolan.github.io/jq/) — CLI JSON processor that works great in conjunction with HTTPie + +Helpers to convert from other client tools: + +- [CurliPie](https://curlipie.now.sh/) help convert cURL command line to HTTPie command line + +#### 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](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md). + +### Change log + +See [CHANGELOG](https://github.com/httpie/httpie/blob/master/CHANGELOG.md). + +### Artwork + +- Logo and branding by [HTTPie](https://httpie.io). +- [README Animation](https://raw.githubusercontent.com/httpie/httpie/master/httpie.gif) by [Allen Smith](https://github.com/loranallensmith). + +### Licence + +BSD-3-Clause: [LICENSE](https://github.com/httpie/httpie/blob/master/LICENSE). + +### Authors + +[Jakub Roztocil](https://roztocil.co) ([@jakubroztocil](https://twitter.com/jakubroztocil)) created HTTPie and [these fine people](https://github.com/httpie/httpie/AUTHORS.md) have contributed. diff --git a/setup.py b/setup.py index dca1d72736..d841aa3acd 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,6 @@ # Note: keep requirements here to ease distributions packaging tests_require = [ - 'docutils', 'pytest', 'pytest-httpbin>=0.0.6', 'responses', @@ -20,6 +19,7 @@ 'flake8-deprecated', 'flake8-mutable', 'flake8-tuple', + 'mdformat', 'pytest-cov', 'twine', 'wheel', @@ -55,7 +55,7 @@ def long_description(): - with open('README.rst', encoding='utf-8') as f: + with open('README.md', encoding='utf-8') as f: return f.read() @@ -64,7 +64,7 @@ def long_description(): version=httpie.__version__, description=httpie.__doc__.strip(), long_description=long_description(), - long_description_content_type='text/x-rst', + long_description_content_type='text/markdown', url='https://httpie.org/', download_url=f'https://github.com/httpie/httpie/archive/{httpie.__version__}.tar.gz', author=httpie.__author__, diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000000..d3e460914e --- /dev/null +++ b/tests/README.md @@ -0,0 +1,3 @@ +# HTTPie Test Suite + +Please see [CONTRIBUTING](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md) for contribution and testing guidelines. diff --git a/tests/README.rst b/tests/README.rst deleted file mode 100644 index ab7d518e9c..0000000000 --- a/tests/README.rst +++ /dev/null @@ -1,8 +0,0 @@ -HTTPie Test Suite -================= - - -Please see `CONTRIBUTING`_. - - -.. _CONTRIBUTING: https://github.com/httpie/httpie/blob/master/CONTRIBUTING.rst diff --git a/tests/test_docs.py b/tests/test_docs.py index ef45d795f5..9a5afbf7e9 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -1,69 +1,35 @@ import os -import subprocess -from glob import glob -from pathlib import Path import pytest +from httpie.compat import is_windows from .utils import TESTS_ROOT +ROOT = TESTS_ROOT.parent SOURCE_DIRECTORIES = [ + 'docs', 'extras', 'httpie', 'tests', ] -def has_docutils(): - try: - # noinspection PyUnresolvedReferences,PyPackageRequirements - import docutils # noqa - return True - except ImportError: - return False +def md_filenames(): + yield from ROOT.glob('*.md') + for directory in SOURCE_DIRECTORIES: + yield from (ROOT / directory).glob('**/*.md') -def rst_filenames(): - cwd = os.getcwd() - os.chdir(TESTS_ROOT.parent) - try: - yield from glob('*.rst') - for directory in SOURCE_DIRECTORIES: - yield from glob(f'{directory}/**/*.rst', recursive=True) - finally: - os.chdir(cwd) - - -filenames = sorted(rst_filenames()) +filenames = sorted(md_filenames()) assert filenames -# HACK: hardcoded paths, venv should be irrelevant, etc. -# TODO: simplify by using the Python API instead of a subprocess -# then we wont’t need the paths. -VENV_BIN = Path(__file__).parent.parent / 'venv/bin' -VENV_PYTHON = VENV_BIN / 'python' -VENV_RST2PSEUDOXML = VENV_BIN / 'rst2pseudoxml.py' - - -@pytest.mark.skipif( - not VENV_RST2PSEUDOXML.exists(), - reason='docutils not installed', -) +@pytest.mark.skipif(is_windows and 'CI' in os.environ, + reason='Does not pass on GitHub.') @pytest.mark.parametrize('filename', filenames) -def test_rst_file_syntax(filename): - p = subprocess.Popen( - [ - VENV_PYTHON, - VENV_RST2PSEUDOXML, - '--report=1', - '--exit-status=1', - filename, - ], - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - shell=True, - ) - err = p.communicate()[1] - assert p.returncode == 0, err.decode() +def test_md_file_syntax(filename): + mdformat = pytest.importorskip('mdformat._cli') + args = ['--end-of-line', 'lf', '--number'] + err = f'Running "python -m mdformat {" ".join(args)} {filename}; git diff" should help.' + assert mdformat.run(args + ['--check', str(filename)]) == 0, err From 7e9e7c783f9145b63f77c83f7277792ac8d470f5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 6 Sep 2021 20:17:21 +0200 Subject: [PATCH 0788/1182] Readme tweaks (#1141) --- README.md | 77 +++++++++--------------- docs/README.md | 12 ++-- httpie.gif => docs/httpie-animation.gif | Bin docs/httpie-logo.svg | 1 + httpie.png | Bin 697537 -> 0 bytes 5 files changed, 35 insertions(+), 55 deletions(-) rename httpie.gif => docs/httpie-animation.gif (100%) create mode 100644 docs/httpie-logo.svg delete mode 100644 httpie.png diff --git a/README.md b/README.md index ecad3a3667..cf78466671 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,44 @@
      - Httpie-Logo-Lockup-Pink@2x + HTTPie +
      -# HTTPie: the human-friendly HTTP CLI client for working with APIs - - +# HTTPie: human-friendly CLI HTTP client for the API era -[![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%2373DC8C&label=Build&logo=github)](https://github.com/httpie/httpie/actions) -[![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest%20stable%20version&color=%23FA9BFA&logo=pypi&logoColor=white)](https://pypi.python.org/pypi/httpie) -[![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%237D7D7D&logo=codecov)](https://codecov.io/gh/httpie/httpie) -[![Downloads](https://img.shields.io/pypi/dm/httpie?color=%23DBDE52&label=Downloads&logo=python)](https://pepy.tech/project/httpie) +HTTPie (pronounced _aitch-tee-tee-pie_) is a command-line HTTP client. +Its goal is to make CLI interaction with web services as human-friendly as possible. +HTTPie is designed for testing, debugging, and generally interacting with APIs & HTTP servers. +The `http` & `https` commands allow for creating and sending arbitrary HTTP requests. +They use simple and natural syntax and provide formatted and colorized output. -[![Issues](https://img.shields.io/github/issues/httpie/httpie?style=flat&color=%23FFA24E&label=Issues&logo=github)](https://github.com/httpie/httpie/issues) -[![Docs](https://img.shields.io/badge/stable%20docs-httpie.org%2Fdocs-brightgreen?style=flat&color=%234B78E6&label=Stable%20docs)](https://httpie.org/docs) -[![Chat](https://img.shields.io/badge/chat-on%20Discord-brightgreen?style=flat&logo=discord&label=Chat%20on&color=%23B464F0)](https://httpie.io/chat) +[![Docs](https://img.shields.io/badge/stable%20docs-httpie.io%2Fdocs-brightgreen?style=flat&color=%2373DC8C&label=Docs)](https://httpie.org/docs) +[![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/httpie) +[![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions) +[![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/httpie) +[![Twitter](https://img.shields.io/twitter/follow/httpie?style=flat&color=%234B78E6&logoColor=%234B78E6)](https://twitter.com/httpie) +[![Chat](https://img.shields.io/badge/chat-Discord-brightgreen?style=flat&label=Chat%20on&color=%23FA9BFA)](https://httpie.io/chat) -HTTPie (pronounced _aitch-tee-tee-pie_ 🥧) is a command-line HTTP client. +HTTPie in action -The `http` and `https` commands let you send arbitrary HTTP requests for testing, debugging, and generally interacting with APIs & HTTP servers. Commands use simple, natural syntax and provide a formatted and colorized output. +## Getting started -**Visit [httpie.io](https://httpie.io) to learn more** +- [Installation instructions →](https://httpie.io/docs#installation) +- [Full documentation →](https://httpie.io/docs) ## Features -- Simple syntax +- Expressive and intuitive syntax - Formatted and colorized terminal output - Built-in JSON support - Forms and file uploads - HTTPS, proxies, and authentication +- Arbitrary request data +- Custom headers - Persistent sessions -- Wget-like downloads -- Linux, macOS and Windows support -- Plugins, such as JWTAuth and OAuth - -See the [complete list of features](https://httpie.io/docs). - -## Documentation - -Full documentation and installation guides live in [httpie.io/docs](https://httpie.io/docs). +- `wget`-like downloads -## Installation - -HTTPie can be installed using Homebrew on macOS (`brew install httpie`), and `pip` on Linux, Windows and other Operating Systems (e.g. `python -m pip install --upgrade httpie`). - -See the [docs](https://httpie.io/docs) for system requirements and full installation instructions. +[See for all features →](https://httpie.io/docs) ## Examples @@ -72,34 +66,19 @@ Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comme $ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comments body='HTTPie is awesome! :heart:' ``` -**See [the documentation](https://httpie.io/docs) for a complete list of examples and use cases.** - -## Contributing - -We :sparkling_heart: our contributors! Please read the [contribution guide](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md) for how to contribute. -Have a look through existing [Issues](https://github.com/httpie/httpie/issues) and [Pull Requests](https://github.com/httpie/httpie/pulls) that you could help with. - -[![Issues](https://img.shields.io/github/issues/httpie/httpie?style=flat&color=%23FFA24E&label=Issues&logo=github)](https://github.com/httpie/httpie/issues) -[![PRs](https://img.shields.io/github/issues-pr/httpie/httpie?color=%23FA9BFA&label=Pull%20Requests&logo=github)](https://github.com/httpie/httpie/pulls) - -If you'd like to request a feature or report a bug, please [create a GitHub Issue](https://github.com/httpie/httpie/issues) using one of the templates provided. +[See more examples →](https://httpie.io/docs#examples) -## Community & Support +## Community & support - Visit the [HTTPie website](https://httpie.io) for full documentation and useful links. - - Join our [Discord server](https://httpie.io/chat) is to ask questions, discuss features, and for general API chat. - - Tweet at [@httpie](https://twitter.com/httpie) on Twitter. - - Use [StackOverflow](https://stackoverflow.com/questions/tagged/httpie) to ask questions and include a `httpie` tag. - - Create [GitHub Issues](https://github.com/httpie/httpie/issues) for bug reports and feature requests. - - Subscribe to the [HTTPie newsletter](https://httpie.io) for occasional updates. -## License +## Contributing -[![License](https://img.shields.io/github/license/httpie/httpie?color=%2373DC8C&label=License)](https://github.com/httpie/httpie/blob/master/LICENSE) +Have a look through existing [Issues](https://github.com/httpie/httpie/issues) and [Pull Requests](https://github.com/httpie/httpie/pulls) that you could help with. If you'd like to request a feature or report a bug, please [create a GitHub Issue](https://github.com/httpie/httpie/issues) using one of the templates provided. -HTTPie is licensed under the [BSD-3-Clause License](https://github.com/httpie/httpie/blob/master/LICENSE). +[See full contribution guide →](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md) diff --git a/docs/README.md b/docs/README.md index 4da6215c81..010fa570bd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,15 +1,14 @@
      - # HTTPie Documentation -
      -**HTTPie (pronounced aitch-tee-tee-pie) is a command-line HTTP client. +HTTPie (pronounced _aitch-tee-tee-pie_) is a command-line HTTP client. Its goal is to make CLI interaction with web services as human-friendly as possible. HTTPie is designed for testing, debugging, and generally interacting with APIs & HTTP servers. -The http & https commands allow for creating and sending arbitrary HTTP requests. -They use simple and natural syntax and provide formatted and colorized output.** +The `http` & `https` commands allow for creating and sending arbitrary HTTP requests. +They use simple and natural syntax and provide formatted and colorized output. +
      ## About this document This documentation is best viewed at [httpie.io/docs](https://httpie.org/docs). @@ -19,6 +18,8 @@ You can select your corresponding HTTPie version as well as run examples directl If you are reading this on GitHub, then this text covers the current *development* version. You are invited to submit fixes and improvements to the docs by editing [this file](https://github.com/httpie/httpie/blob/master/docs/README.md). +
      + ## Main features - Expressive and intuitive syntax @@ -1674,7 +1675,6 @@ See [CHANGELOG](https://github.com/httpie/httpie/blob/master/CHANGELOG.md). ### Artwork -- Logo and branding by [HTTPie](https://httpie.io). - [README Animation](https://raw.githubusercontent.com/httpie/httpie/master/httpie.gif) by [Allen Smith](https://github.com/loranallensmith). ### Licence diff --git a/httpie.gif b/docs/httpie-animation.gif similarity index 100% rename from httpie.gif rename to docs/httpie-animation.gif diff --git a/docs/httpie-logo.svg b/docs/httpie-logo.svg new file mode 100644 index 0000000000..4a1f506151 --- /dev/null +++ b/docs/httpie-logo.svg @@ -0,0 +1 @@ + diff --git a/httpie.png b/httpie.png deleted file mode 100644 index d87eae38850e55acbba2cfb4374127241f8039b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 697537 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�)*F#7|l1 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®b~++&gc$PaZjUE_IfkLdcuxUt!{p@GK8 zgMp<@G9|#&1+iz7qr!dLmBpa7)aYo-{QxIlU1DDUaeH`{fi2ErH4r^U3Qkn8|!eO&A4Tg}CdrkbCc-u`_GZ#ro&_I5K9N|D{~ z!Hx3>_{r9sD*W?B^Gz#T%(iWNtiH9gE)C>gfy&#TP_JuO120i&5YGb}JJ18eLCc?! zOYd#!YKG^Mp71tDMU?*OSjTSKs9cbSk|q#|Qi;!SY7iU_s+SLGG{pKD_?m1@ndLkM zpzD_C{qE`jET(`zSZG1lp>$O%`D+3pUS$2^eJHyZ3FqBgETW;*vx4_c@7&8D=B2)0-Dd^hWLtW`cHDc@nMJ2Sl=>AP z+;TB6_$N+mf%Rko=bg)2`FtD6d$V`y8PMqcx-%COO#%zj{Z-D&xV9IR|D$R1!R0m93%eO| zzQk?UV?(h9gKen^|90U$$Z*2w`=sJWZj~3WYEM>!VgBwlfY1IvPa_Vs8Ii@UREH|GS}>SGSSm@zwJ*&%1x963)w`(*#x@$-0lhP zpS<=1&RIw2g!>`M=NeT)XVi*3eY`^Ah+;1al!J9^&lE z8!=sMai89fr$M|^*1p&E^_6(%Pkj+!8hef~51$2`|B~=um*ZSYl=DRe6o=PSr~Su~ zZ+_iYi-O5NCie#dB0&hDQWg@v#3_;AQ)dPmDrUxY&xj0UZ=C*lrurg9mFU^0q;%zB zVWACepiX%a30rjHepvgRJAN6Ixs^&AR%MQG791{HM%sRdLYFIq;QFm1wK?Rf!bwOT z5MXCVeLx4y>X*u#NdNKxMgaErF)Sp6LPx|`G=$lkF;Xa1FB(XRWD}_l3S#_a6~YuE z-tn>6u<^X&>Vdfk@Zx3^Z~Xsb0umZ$P8&3f;upK-94r*z+UosV=wsmd~32-dBje)8lhx;qz2fxQ3&rf6{;?dUJxF_wZUYC;$ zOBqIEAmoWu8eQ(y8yvKn*Yp0JE+n@eZ8276<PuO?-shBd&w21eyk3;<*^T=;|L+Rs%_i4dzco1e4D+Zzyghqi zWFT!cOz{ra$j|tzMwFEZw(PPD9YK3BaRe1_c-x7DA48#;sq84Yj_OU(dkrGN-~WBQ zsNFAJW_%U#YhA`cSN{^u4!nNeNzA0)JpN(Mx!|Jr3dfaCF^mu{mMjlYXAMYuO0Q`K z0=O-omc!^hM&@>n{m}W1y?ZBN!`A0AkT6WM(re?u2l`TjM#cFNAbn{4Iy}Z?FY%^1 zx|R-DRQ!x!N4OnEc^%;!c7t>lDn61}*k4V!b(m*yw{bzxXHPbl!gLQNOtkrTcJ}_A zmMzHY7|?<#Lqh?P_RF%WxbXNt4=hDw$|x}yb?WtTbv4+U&*H#S8T=fG8aj2$O{Ffc zyQ>)<5~|S2ukOB$}72 zDZie8Q;8d=h&IjT*;HR)6B1T{;C@OGv0sE!6c=cWLE7ZB`+08>&r@rh8W)w}Zkq=j z{X}%s(0Kgrg)EPzpKJj|h`zpnA;&B+)g3Gp>TwI}T;OQ*%N~!yhy=Oe{7fZh1&ZRG zD>+i|)3TOyfNA-{{@7xH_FRLxrs>X=OYZwXC=d(HxPqQrkk{dHeDe@rN2>1L)^c6R z@=*qve{zG%+HPQ6HAqH-gvX~6+O3js(=G*FfIGq^Ti+L zTBQ8tH=~XgoU@8QsxRRu9KE)Vg(Js!LT&IP;0`}5ZW+B{yA9I)<9e`M`a zegmjbr;P+CM|K>)ddto(mkd~pntHH^w%i?;*f5_D&hbCE=G=VHev+Tm$whBo0W?4F z@*NPARkOmaf1gtOPTyYjOos;pSlVFpJbwJXsLvG8{g4_F(SwKT4u;DVbPIhQWycwb z^(-|Ddill0^zYYGL{os@&>rLOb?Jq0yI{SB*q*j#7m`G0Kq>xPQfC}}T*?GK&hV@V z79j{pAU=@~C19$N$wYb{AVht`WGE&rWwUTa&=U_jcljgIe!n)9gU^n}5npploJ3h0 znc{E$zMUK`ATbnOpg8)-jJfR~KFtG*J;@z2M>jGtK1DB zH%LqHfJ{{P<_|XxMlR<(?Etjs%ayQZ+kT(Yoap>b$phC zwX!uaU<6UxGD#s0AQSw+xB?xt^r|N&PfqaX(ySwx6)jk5@$g7(hae(TrKMBBuj*HH z963V<92O7UIRKesYr@e@n)8k*&m*YtZC<3~>21d3)dFf;`=X99#75p#jHs&~y8u#T zrXED7RR95H`=Pi!!jbF^GbJv@N<0pB`mjYanpHmt7--vk(b%aw(I~H5B#b}Yxa#Ns z@sL=>^JkYk1s5V#+Aq- z%Etq^fvU5EnwofB(I0uXW~>$Jy%`0{g1{E!_qYISla+Ig;(3psAh zFG0~JM~2$WUo&S7AO}PM$W26~;Du!gsWz_Y*)i*ocD!Q@Z-h7k>8#W7@b>;a+J%nK z(k2_|ooSaMYcx=^Y>FU*Oqru}<>y+U4v`8Lq?DI*sIfS|%s=K8T9G*!I@~DpUVeiU7VUUuZ=rFXu2~D{~o3 zJ5?1P0#!a@ZHmEE$VyW}N^(NrLF2E*>u3jcssItQ+Je%WmEH{nagI=-eD_b0lXSn? zm$qqto;gVSZn*F~PECSSShZ*qzgmbgMW{+qqER^$3@EY>%Ag6J$J`)iX_Q%oLwKl&Iflvx?=jGUxm7&EBT8gb)&sW<1%n8W-VQP!ZUa z4dPx0&IT}Y`On!fvc{gY+}e=?F5jc_Pj2id#Hz=+F z9gELwv&8*S;`SfLubqvvLz&Vciu9SL{h={e)_Q3wuXj9ojQXlBZ!q#`XYyOGc_nU{x_{B z8i#lV4df!7%_lA!L0Ss_UE)hFdfP|T%nh|~)_@P2d*RO?Kwq#SUHr#kFPw7pjrp#!>+d{Wf z=N_i`b54wWJK1-$k*AeIC~+MM3!0lh>VIF*Xtw;jEn+{}f?gP3RAvS)C{~ryiN!KM zEdEipXtlF25^`|*YamGITV+JSJyBv_2JNmb?3 znm^Be6?>z#>#8KP3S^uQ)lfx??7vEhRWV{Bq4?;Bpt(Ekc*QZNrt&kOmfT2uG`` zY`R&(2OEer1mXNo6|1QkOV?wMk$oxexCPvwbYNiMl0M~mfKWg}(#i}KNC@I500%*T z70y42j8CJa{Xs^@;&~^E$EHEfkkstgC%kJ3dcqCOn0tE!jMa!$ohQBnEe)lr=6vBD zc7uAr1ou(__HO%#Kdr3*Xp|OMS6>U*Wr;n#6Ic&21y2t7O$hbA1_Vx}!jm$jj`9Ws*zS6^f%Kh{!W$MO*%40Tb;6B?)G`7T3OG4M8%1Ae+ zEWHL(@63eW7>~I#r%$y58~6!|^c6Rg2`z3c$;ll{Ppt?S#+jJ(1=Pr9>Qbl^uCBLM z0NyOrpR1Wv>fd(H(TtjZg~NmXp+65lc28yilb`pAp}U(@*(Y|+UH60UQE>U|smDESmykqG~w;aoTeUi-oTaVIZFg z3!SMLA4rJ@R!VuriYFB>mKZMe#w`ZM>{R;_8Fz;pb2frSx_zswk7J#VxI1LRsVzBK ziCPf%9Dey%i=z8*MtLw4UxHyD=FbeZX<4lbLBpb(VxKrAi@ryyJ6g$qj9ZW0BH}M> zk&p)NK)^)^(u^ZD-+kHYF(!=gy%ZViBpX~_OMBN%DE2e|nhHCk=3b&ie0!2PHIG+^i?{vS>65m(C1Ns-_@FMnavli0p~;m0O@`NKO|hL zvIqN@X%7*>z4gjy_ZZ=J6ba|JAOHTZGof$eU zD9=Jq51+t%Lx~{msLV273QBJrMVHjGbVe!({CW6qzvp+L+_X@7Qu=w4lU^lGw9evu zyd7EWj}p=zq4n{* z{r7Hb_)$|fbNnmgXuT?MX*mm&3C+Wm!kwUK`!!3nJE4%cQ}Yo`5RSr%vv(Q-FDf^6MSCBc;d7PmEy-VE-ET?Pt6b94Cx}vycs)3zI^XFn zty>nX37i#YuC4^?xZd&pi~DoEgs-&ZCw{r=Dc#pU>U3%ip8sa36dTt6)Jpg-KX!21 zZ3mj@aS)B~)N15fV^KdC$?Ca^-Yfkm5S!{FFj|bu;1#}H_N9@#g+}yye0=7n5W{Be z;3=W=*z{9Xa*F?h1yuj8GWk!zI-ZasV<`U@GRB^Oly{LK!J&s4`xM=2ldV&%AIXpI zp)y{gP6B_7h4I_C4K!&g?$e#T>iAc8;ZC$4SkX}jgdA-rHkV6W)~A6LU@A%Tb^KA# zP=ELz&t;NB9p78{f`v$79%PlB>goB|bnR67(2|D_d^5Fk0oI_hibmAlrq_@$;0AM% z02$eYDar?^he8lCyf!|FoQ1K@96AN2*U9hX18Jad((aT%{-mmH8-9QsIWV&pNp3G*H8G$>w^AQQ6=H z8~61rOoaKo)%yYx_jwz_9W@5%TANYVB0NDYUl0?i*1W`_A9~5|bP>od0@nM{v8l|Y zY7xjj$R;L5h9hT-9r$mhDr^zf2eXE$@@d|TcZG(M*qEQUN1x32lcX7h7IB_61{>+t zK5Pev_U>V8=YP$eKueVF{VeS&)TRnzh@qaf99=<=AzM6}!|lsn-(+;{D$r62uA_aB z(o~YRQ7R^=@RT_`t>V;_2JYG0*SrwIexsh{SXb3p_EmtU^R{Y1~Q55>OGv$#711eEHP#&dubYVmMX-39) zhZgHXcVMtQ6q?{1nTj>d*sW3Lg8bca9%mZB8NIaIEkQrt+=wFWl|D!DBnmGszF|*H z?&+4{|5U#thDAzTS!dL8;|DOGJ4{A_n1@vpw{NJTa9KmUVVwT;Jh;mRf z=#@Y0%hvbXKv)?vPcfTawlHHH5e6rwAVV&_f*4zoE`jf?yWZ?S56>%-!GEw7y{57j zlUYOd=;*wVs1TKt7Ssu4zU>FMlOcb%WAE#CSlo&256(l)9;5!-D`~eQqN}32SM@Y4 zW(MV%3TowPk`yY!Wsy+F+NK$k{ zFIWXj1h=k02xN`kbwVqR8>YJa*Skzl&xbz6Kg1=UVkt`%*bIzs&R#%K>@7F%0TUU3?+ zIXnYD0If2T2Q<;n&)m|o-SFELA<4k~s1@Q;%BS65D6`Uzvay8118)q4$fNfbVT^J&{U`Vhe zH<``m5Y{Ip;4Bm?B3daKB=VQ0NL!faBx(_hHDE1$i&S+b5>nPdh@y9nUS3#>=S*Re zXh$G2{o(hC4Fkir##w8sTerXY(yi1c$5?mlC%jYn15{DI6&mDhyf>h(7AqsZN^m*Z zG(P{>BX#%#fu7U1NAP>8Hw*bNM5wE@8q6lJ(qA13-oO=Hoac>UUWi_okcsCNXiPQq zHzHziQfA|*p)QCr)9KBYggfb!gF2BcTDMD0K=2oacqn`=SsV2`?tb z;kiqzH6IkZ`u3VCWDXPB_x!R`(mfOM?-jPuauE81?4#~6)L+AROVj9;wuocN&D@Ao z18)$i(?k!JuxVKT64NS8aQt-){^+p4LWSyBqgCa|*?c}L-HAwIi1m=VBJ!oxTyq>c zUB^sV*KA=KgMgZ&ByXxT46?!%AXpMrUYqHSsF z(uhY`*tv&~Rmhy8^hs?ftuchAAzMe(-gTLY$;&`q!Xx|y@{>whu>WdbSND5`I*x-c z(J4vK&hNJdoY3XsYxWlhQL(Gq+Mlv=wBjK0gwBDA;HgyYtzDIODXWxv67hRwLBU#I=%=eB z^%fKbgB}DoYhSLz` z8L?Ln(gF9f69GfY!FDVR%=5qLfRJQ_Bql?&6oY%6ROhMOHCi`(HOs@=T>H|26@ml}Z@!D(UmoIQ8)IN2s-7gPN7$M)~`! zT!{uQl!GOYd~LcuH8R>-N=nfSPPVtc1DInzMY zp_;N!F{@%GMNWl!HCczbbSI>>kFK2zLj*bK6+_Sbi;nnJh!iZ$z6Pc6>HvSI(-Pf^c#aCOU<$u*-K5r@^yBBY*GMc0KO!q$ zZ^evsMU(apQuL*voS7vG5Q-71%B41m)aXs=DHh(~H%()H?%`#vcIeM567m$mnZLbN z39&y;cWOU*f)m_P^9Ga14(&@Lyk9hDzy6K-df72jp(-F?*WvVmUtO*|v{$~Kklstc zLf=DtvGs>|w5X;voNq$|6l}rwz045XZs!4sy$y~xGxUzbVeO;1qgn6I>C+WK9oZ&o z)Uk^-d0MBo;KapxZqL5CGEJ9C2gCiltJ9wD-Oh%$Pk54e5*pEYJFBM1wH1CnI5!)? zO}YP?n@1jb-U|}p6!lteJyx*jtHv`T(O0fEp7ZSq*^A(aoqgET_<%u1S(G6YG;=p(xKDKw*WJB(+SHr7~yaey)e;4TM zjm`ai6iD%oy>@}ad_=K66mi7QzM4N>^h@>W4|l!tvXZq^wQfS4Ais)~=o+zvqZ3|s*bhIlvr0jUD}M4yg=zkPe}1^8grr*&3?Z6;U3 zroIzpVXlc>Ls^0sPrNX)eC`;zLHrX=Q45(H{b~3dstMCAi1X#T~*G6EDmf$0gy*&Xcjaqcf7o?YWQUb~* z<=N;^GIXzw+!fKJQj%_EB$~tEby@a4Uj#jseww4rU?^(Z&~-4SFH|8gsr}d-BkA!* z*_ZnBk!r=@%P(J)-vUu(gr`*=bRzWIwZ-$iFc0+896+94vLj4(B zQ1~>_p1zjwmbb0UWI{gfE`szncTZg{_@G$jPrQub zX<>oumyoGgRik!(QXFSxv{&8p1P#-8^i6yVwVPGw(CwIvmv&~GA=376OZS7W(fPwG zSr(!&eI|DT(WgvCM%=3XkK#?(s?_w1^vK^n{l1XxEOXn2nPM=}sLi!5DiCz~q^E4i1;dt$E( z||Zk;WYb~Ntm`nH@3@SFBfXgXAwNRL*Th1$v5Ra{}-% zr@k8kjhbW0Wed+)LJR_Y?97O7&UqL~pB~XySV8)}uORYrHU_%>r9=G=zv$#K)gP+b zJ`zf>pPm2>El;0QH%E)Y98UDv9!-2tR40w{Wv0Yv!rGt$JPtaevBYoH zl+_|S@{Y&r=*vf?;iQ+kv;Px2BC+(t02c<8dq@UdGwCUB$&fQ=#mOhPq+>?C=43lSpSF3ra;K17f*%x zLD6sq9ACPa(%{A^IprE8X?{ansBf;zjDk&0uLb~WIK7aD;_Em6^e1uy=GIwd8= z%sVdfA9Ao+yUi0p<>p(kG0|HX+sJBu>MyxHQe51WT)O*UKO<2}vPEMel=vBJgg;|0 zdE}^7NeCdTg$$H43xjK!OP#NkG9#V+UuZJ(m+9ND`Bk-dP;#ONESot$c+xB&4JgVm zhi9VLuP!a&IRn_qpx(`3Fi#)wUH`8SSBQ&REzQdvkq~NeJnPrZ7zY-MsoxY4%$X6H z+IT^IG&h_wFa=ofO+VDV;)E7PYblN5!5rQTk@_eE;oF^CmpuyY2w(~Juf$KZi(Z7_ z;g)w^ty)pPj!Q-qt2i@0pw!^8ngMtIH2;u-f-k{g64w7&qP=;c)x8vG8)drv<6bAE zN|GBxxo7dC#PRk{qlC+o**Z|a?eiAIl_o5ztHI=fDIDbRZ0b-o9GW0IIvVwqYvs5w z(oHjhACm`{8fQjHle?)Or0kSoP7lis3&s3?Sp&rJDB%?z6J65<6M8BGk7n}B9P1cF$nl|~AImA(8?E1Q@Ivl;}j2Rv9y zmsHj-ZKGa-1@0)=JR<`$GvwiV8HHNCxe)*_b+kP_fF8C^=)tcqgAo0}eQStgf3)yE zA7r45QZ2d}P6Qgbzr2Sn%AM~ai4Y4U=Rdt;Wp5X%e1nI&fG5>+4CZ;)3G)_r1{*gV z&GaXJ`_@sbtuD3g$HI)t`scT`?->r(6^gZrq1Lo+6p1{O!WV~kc{mt<)FZxYR`_+3 zdp+LH(y+2(0+BKQpYKbG3c;13nWpiNn)CzNkvu$1Nc0p z#HF5yn2TV}sxYOPzJGy-$lbSKHYerK`v%BEiuC8U4LwQ;gZfg97;7&BB7_K&?ymf* zwn1R#DorZ(IkBcpeU;7&;7-s~q>z{_&5qaFF{fVcYOUu~=F@QgAdbH{$MArq5FW)6 zj1CMiXayf!s4!}qzv$213y3fY`I$iCjw*BJFUKj(5V-Pl?fRCMlauqVpQ2;cJ+Bs( zfs611M|k_W~6~ZHW~KV{~KTSOk9F0 zu9^18<%5#oa-8ySuA)>CAaN#AZ|`%u`4kBj+g@#v=Qe2Y>~uRLnlIti;#(VY7t!BP zn1W_mcpzNpVZT#ei;LJHx`j}?N;6;NB$E_^ns4<_C4EvI3~g1go}mtw!#_*1A6p3i{9!%4X6FtA(2I-a4k(qNzk*;HMIZLd zKGRxG@d~YW8vO?~1_?)TBR7PnILwQw{uGM$nTWu6Zz0O=)x1==%b7*tit-DkN=jtC z8Gmnt?oen2Xu5*( z4anjGNPhI<^64UMb9x)tK#*sjVm@pFp> zN>`q^RU|A5^`WdY?w+{Wb&yKhrn)|)j(67PgSlV##ve6KeK0X;y+3LfFnNf0S7AS| zqT6IC`Td8EjJ7uM{bMg3AF+sElgvEIO^ez0)?%-UOGAaMh}TRZlC&}+3>&QoAMb?^ zSl$R!=gM_d;nUi#{(1$)ZlJ0BP>DDz=zJ*+E<}1m#X}4ee71Z4-_K73k(`gOw~+f# zgm<>XEZY)u+D|(1q)lu%5fH=!nP7nB7Yg|1Y=1pebO3ofUl!e}xL42*EAac6-1)$w zo-bj%=!iM#MdN%j?swY3HC|(;+;s74y?7`G8W`d@#GfhO3l2x0_rIY7r1@~f2VZ$b zMX^$YTC`_pGhm2mmi0gN!r5D>313VXi0UK!;1&l1Q1{IQ`*`gKU07AKl{KAAcu&j zeNU;XU&)e;_3QkIJ%2`h6x;b6#A_DewqMY^6z_b&c`dJ?@LNy%e6@KA2*X&&~F-{=arYl`~kNWJl{(nC@v;p?fVmTr_uh1uE)^yOmV4}+FxhTrB9Kwd}mEeI}hm#LjCqK-l2nqnahHIJMrHN-z@ zg@4^<+54W-NrhRWQ(off3%r$i&Wg@>*d`p?0$Liv2+`;j59Lo!Y{jX>YBm)dt{2P8 z9TvTJAHTe;Eq!ycP)qRw7Fz2z#2a~`(~EaRb#2xiK*C*SeeU5woMP;ewZ(Abw;=pX z$dm)7W(>uWV5QFwUzK7*0R#lmeLx$dNf*YkiS<|B$kbCe&>gMBA z8)9L$heU=;4`xP#)kr!(v?49LZF}2r5j3qt08i)r`vm+7r9jntM*kIF=u0&q^;7EB znpIwQO26T@poA{4GdZ7*GTw2u%7XoV8#*|?PwITM^)}bAscyWV#+8Gc!(MT9)orwG zy->8RBWgW#9l(2Us1feqVT9+e+RR;$c@n+m#uxXP>U+2qWnyN$cti~ur-_7w-gRoe z#0v)iln}tN{Ytb>uGl^2mGH#>Y+uKmiBsJ=%mrmKL<$Ap{`pL>GwIwDG#4KltYC!W>R z;M2gaa7`1c%=N4I0=w157rd1Ya}D+_(1sPYu#3R z;`{5s?A{rL#ex3)c85xj)GdO#(Yx&{#iuF{Z%`;;h~|^juXh~2juFF9wF`{Eqgrrf zMq|IntvsT$gS_0Q7@Q&?!^SBsI{zh|jRdf8cHotDA-OrzN;6z`p%%#o-rKjQTQ9jg zW*oY!3ce*%|F8e7wf-854|6~5P-HlSIx!}t8{d&q=Is}c!$L1;`5HoKUn|>M%EI+G zkIE#ZY@G_c=Qfplj-RN={|#8W6qsk>^Atu?p%(}3w~#Mrj#V+?-j8ig(G(XF(;Yhh z_?+PrdLkX4(Hr_2hefr)SGJ7um=@+j1O#!5AXfZJ#D_jJfc$B!7}o><1`xqB1BmWr z2x#h?ib?nF=9m7rBW5W~aUcIqfXCVcX87EQc=En0sDWHh5&fv#01w}tFXp1jIXhr- zOJ^`KUpANw1L!%O@l=c&T3Xn^1+_tWv48jo<9f-Bo`G43`?k)Z`*frU^jyMe>GO#x z-7eS1@|A>JF*GnXR_5oFkj+TMqM?w-J@j(@KMz%9jl)h zg*#6uzsz+%BgO?Fgur)V`3q~Q78)~sdM5EPUE*yICf)o@?C1+ z1wb}gKNOrtM6Gn=ksyECZYI(z>~B?CO~-N`dAv>$jw`@NYMFP4(9*JGEVjr_+ALXG zZ;4JOiObW;#Gl`Wuq6u%ez)Jq_sRj#2I(E{K+$EftlHrP0B5z@25b%G-Z{Lh`D?9h z8sMN9M@{Y^UL~FM?&sAeB};ixm|CVQ{jMPS1l@JURg7dL5Ymg|`6~6MYYZpX4eS55 z49`FOB+yk;I#rXcQML1b|BZ^>AqvJb8j(pL^3zzmhO|BsU<1kMvrWcj0&JjONWd5b zU;|}04M-*1b_i;o-69uNllO54E?!Md$deDhxRkxlfdt3IhRGU^FXoe;iYWAI;Jm<3 zD{}saUz>2W-UmmRWB-9%rGPH>H#J@>>>hk=?bB}_!ViRnbI-LD&b5wXz^R>;J*?*{ zWM8=$eENj#wmY(W5_s=Yw#@>LN7>PcQkk3^uXCVCJ@2EE&^HWHCiTBROX0Db8Lcqw zCSUO|bS}wcFB4gHeZj*Qa9&#vz_QY6A42h^!kdo&1zS;_UQkSB4G_s52RuK}V#I5E4<>?VsoQ`cI2hH{eH`Y+L#SO5(T z@XsdbHs^2s&$e;A)>_kPg{!zfwLK+1c>TrjP=C!N1B8ncw~WU7-Jk8QFJDVV09izX zcW=4dP}QYexB+tEh(&;IGKTNR=ortg1zx({s)#nySKN9KDpY8rWtdb+3(d4&)NlT| z820qjqgW7wT)=4#Vq#jFqXl~fY)|ldcgtu21jdbJG?rdu~XvHAo+f8sQ`rd^1fpM4VXv5 z#tWl_6sx#7xUKGW(z5T2P%?V-$t%wnq!aUGl^d969fL!4eO_R}S4IK*?;5ry?C1km zqhnK6Ihcbh*nQj%SbO!aUZ|)Ht`FBs#fo9hQ7?t{moKI}1+cK&UfvWYApHvevko>off%GQ zk4(*+agKFa%f0 zPwV(>6M!;v`ECCaO3DMrOM@kCsS^vonNM<)C5TNMAckJnRB!e~OXqv>CVlP!qQ@flh(i;bPxRnt0 zU-Z;a56Jx~Hek{O3I}u;tjO$JB>m0bR93d0}+Mi8dA@qcw2qTfIuhUlLEo`1? zp$m1mM`}gskV@Tr72QzyPbPi2v* zt~bUJ?To;e`&?SvTc@eKxGGWbTIPWdPSfQoz!FpC>x3^YwyvQQ|@ zeE&(B&p@BS*=R`QE_ZLQPIj))@64_9SxN#)lcorMaEye$WFX}!RD64T;QFJ)>vGW3 z6jN(F*pbp>ElVe3V-5pZEXOL-nAyr|Oylq4@1@$r5X{RJa&pKQMS{5W-H}nsGLx=_ zQ~<kC7;MN*u~OWS$Cc4K4Ntt-x@(-yFgBPUoxe$k+L=(bm}&QZ(-Ycdd!YS8o}KR5O|1h%@eZl@2S6DlL}e{yHwiXR zc`g1E9`foHznQH!%^}~gT`og8aXr&&W*uOJcs9wGXiFY?rEmSb+D1=2oMf-O0|h+} zMinFGG!2i`j!52RNo8L6R+y*vQhKPi?8}7CuSX7+ZNnq}fIpHXx<{TH+U=XJ+k%UmmKA7M!tGWzyU zmmW#|Yo~W;up;=gCyMu5oCu&a7|^lH54B-~66}p&b#t?)+FIecke$t*zK*}Ff?ZOs z#i}UjvNN2pVtt5dE4ed<(S$DcXx>TR**(GH zNkVlAA7$l7sN`1~9AgKzkTz>O0KBtu%~y;duGR;r4cy@w-Q%%*`C_%jJ56HvW?%TXU;F;Z4H5)76T{uj_2S6(o0L~p`=A(Gx6wC9 z4;2BLc$iNoU%U0h@v22icZtfb#`_pV^VDSkRsC1$Wp$DR?;m%K@zRsU1jdKBql`CHBL)vj(`$YG z@h{eSgZE-pF-JYtSq7RDq)Ukq1~u;&238VhA0%+ zt#fj~27{8|ybEoJ2J1%V+nz|Xd$bHz>5rBsDz)dq{O<0bAPgBjQWcHraeU}Q3HUX? zOQ@Gr@DQfeCA9wJsig3yTI0p3$m)%I2Sw~>=m%OS*B4AYM zal^n}&?Y!T=XC@pI@N-Og1e!Nu}sh7 zdJEnNmW48mu*aN2)2$vdBSMo8Ed&lHG%`=^pmFep=b03~I5AeLdpZh@C?{6s5D)(+ z4ZX}y6v%&$>x#1@T!_OHOwocP&R&H}U|NEVmTIN2Yz z+nY_3ajXQCTu@aH1)Ys@56S_J!H6yYql!5@Gr4Y5s{;3>?tAFoop)e%hMOzW!4*Ig zf+Zec%lAk^;U&ze&O3E8a$unq-%gcr_)YUzL<{8BE2QKh&67||l@P_WUPBEOcF0s? zvs#hn&4MaMf`RUNV1VqCs#N$gB*lbS4**J@qHk3>5jq<=wuXl@|IS)rj|uEq9f@W? zl+xIUm~I8_6hMMB7Frta_$9M06G2LLVbQ;(sGU*@)kJ4XhL&8Mg&8|ZH$XzOQ`k5Z zz>dA8n|H#rtcr(jGZ^NY%Rozx*c{Cn0|59jGqOswq`s{@Wt?~%Xo zfodG^lFN}G7O-NhU#TPbh(GoyAaOI1Iw=Hn#gt|4c^?R$K{4i60O7}%oVr=r{m`$M zkGaGuu*|e8_H!Bgq*UJlJ$2iIv><+udxl=&`J0|~VwbniB(41r3i!yDO^q1<&S zsvB?k3M133cG+x7`tZ0nU$6$$RQN^PH+j-*#1%uzqtq(OU zhc2Wt&_}@m+Wqb=npDmN>#kT{9xOCkockdB)0li)|GK-0j3D+fnEmb|wv zE$Fs@El%MIoK0vw<88|0!=Za}l$Y`3>kgp0Wfo^-r6h zC7XomLfqvgpFgE%f!CBLgRDOjjUKSqCJJDd?(;&lqokH-| z{n??EGqfy)Zm|CrbB!#_!;I2L1lW7IA7hv!Dvf^5{(5PymQjP?DNf0dlj+z! zTknc__gtJj^<@gu=nS(luX=Ez;Wg(?h0a(XAA#H+bsayU4rjvGSZD4hPb(!S(e zmb&92^eHE4NVt`E-f?x=SJ|0QF96)k^KRc1eiI4GyC)k{Yo@(u@LcGUi5Q=pJ!RS|9#-|vys=~*-6%MbCHiw`Q zFu)q)Uaeu%quc0FVC4uQa8w{IUVDKRrTB) z#gM@H9-XkD!2*x4HcRa3s3Jn-a@3vx^7nlIMF~+nmb*M7wWwuG!~GP!or#$u(`HXk zJ<2%{5MfUV0oFq9w>G;kMb3vRe0F}DaUn}@uRn>KKO(VT4u`^88mRTEV(nxF_2gD6 zeD))LdWA#)-0RolJ#wIBJk}`C_syZ^lLQs)ibNX@KCQ>$ zb#`GC7LPNRCn%}+g^H+e;isyh@{)Ya_iV zw&HduzP;GgKNq|o*C+f>A7-68H#H{yG$T+9tk2fxR&mmUE@`swU{id6BeUQnnT*+O z&0P5;1OGv9FX_wY8PASS@;iR(Z1#JlOQr;6wvQ;U0SFUi&^gKd`SD`)-?;HCwMSa< zf6m9>$U8x*`rjw0c2ZaL1d?8);JF@^uB6O4z|!l%md(HI@z;OoMsgCevqnE`Yd zmJbXPLBPVam#`k_7!9O#0PkBsj1w<>Yr$xN@zDWAAzN`Fwzg3X5_V%%2?%~PFSy3p z5nvxvG&<_KLIR4&YKlBwoI%KAJJotP{=+El)}8$K)|s)#hwDrQO94Lr9PY#=Mh8Tm z``-d=BOz2D%<|l>wQlsa*|$~eb8>3{xOkrRNRYf~=`K_U@c1n{``xTBuKj$Jz~Ic2 zNLEVvTFl1NAuRt`8+f_kbfU=Vp?;oqI`l~#xcaDv=IjG?uMu>v%{>7L9d`j7qp>-3 zY2227uFDlMd6Nz=EBeiOL1JT86(w?^!}l?kBLssCzHG+9^Zsvibj(Frnm1YCRJ&Lc zKM2;})Q9p1?zERCM8R-JP}eoC6Ct;gwd3>z`lkMEsat5(P^3u`zmLJ{B^E`|Vhc8Qcc3Y^Lx3%J_fBzp0WEG3Ya$cX}|ct=M| zOO%qfO>v2wUa^J>Tde0|qov<^|My=9yMT8z%*GAq@?`+}N#{-x+!G}l8h@8thgh2Z zJ^m`^88U+wiRbU1Cw1m_tak&cE z4Lnzz9^8J1QQ$_w2=8M+DWsHn7gDVpY&tEHrb}FVUmx-)*O4K!Y!+7>Ts4cnY9kIuUT!Xf}>2Ze=9^o`~10jJ#qC)0ibCs;-i=Sala9olkqGoElL!{ z`L-O$`Sf=GHO}D@u1hOmy&b8158$?p5Q(BEvIeK~oWw*}zHcGBZ4ZuhEw2B)*x2-Z zEb!%#wQd#zPvy1Cse}kC)>S71ldpOeg_*{Su}w-H2ls|%(*F(G==Cvt6{4}CT*f0P z(t3l$Z5g<=Y$8Nh16K;YeNqWGC0eo^>#!c&!%bxM6TC(sqX^nE!qIu9k_38!5Y!G` zxPBs{#`IEx=;%;;4DE=^UZzuq>DU{+Kfln(<^~n}T{-9|0vj}oEU|_>^ZA&^@S+Bw zp}pv<3C0F8@)r@yA3}@nBT9L1?rZ)jRJill*a$^51kAMP>X#z(ZT{^Am3s<5NvR-7 zD!3;BEehDflLBH;SKQ{euU}s+YH4fbD+LQXm}I>)e5n)$%v~m}s2pl71kZooRPn8s z%2gEpMthnS-X1`C6=P~Y^$`Z`nN815VA%g0)>Rx-*?vrP-1nxt!e^-u1Q`wU8b@Fo z2jBWHdC0Tg&#!K6Su1}q_G(=EY=__1J#;ftb;CJ6J2Wz~{@&No5s%)_{BrOcm+2@y z3Q!dk9kTq6*BMql+_KV>M(wg*O*2AEe1*Sph4M81!Tr-^;w#V}z_z%I4!{1nyBZ_G zV`9-62CX2Vo~7EMwt%?zO2n@I>yrB>v}CZ@8%-3oAYGwD$3*?{7s$r?TW?Y~qCbcJ zg<&CY$34-jOzW^D0sf-FfA!+0iJfLBM+*uk&=klAyQJy^7DwvpPVvU{t_$8aqD4az z>zFcd4Lw?#iuRkN)iomq^`YZgLVmB!YtKI=V7U|4#Elbt#dsjC6rBIZrS4$q+go2{ zw^hc;x<%PnJ})_QciSJ2U7bq2cb_K-n?r^U=D=D2pTzI#l>vO20Enol^r~}sy4AM6 zi)>tOl{3n6R(|D#xxxl{?}$!Z`aMb^F9dI9d%LwNXCQbu_TwtqF%)G1&Q(9F>$*(P z*@mQinhoa$P`nFkFAWD|Tvs2GrkZ%`?Z%>q&|6)$Jq;wFw9aPj3un!G$$^=l)3Lc} z4BzOs5x#t8*f;#j2YP-7-!$51>;(Iio1h;ABQam{8kIUni%KoL+wWOz;@#(VIgoIF zvt>B%@HnIW)@90iJRWvgQfd?TQt3`lTl2Z3e)}MpNK`UVChI=P@2JO%!HHQAekW)r zxDEJu|G*HR7ei2PQVVOPoOT{`c11=H#Jh}4kt6iSrCwy1Rz#uY&;Oh#l^(wx26PnKZKFJoNH5g;Th1Q|w-dS*sJT z+7x@c)UmFjiYs=kx?uftfyB3m=TVTHga`H%`{NuYprBg=t>GhRLt&L1Lsy{cB9ys} zK6Ok`sZCE!?T7T!=xM13It?2Ay?}=KSE?B7QuV?Wl6|Sk8vSo)_sfXLT^W>&m~L`Avmz8jE?!&N3wGhx<2K zVpr%lCn1n%TqQ<=UZq12`rUQoUQR4DCs?O>W(*LC-4P6+Zf%XuKK5uu#RcxCqtQV3 zGz@O@1@ZBwkpze6ip1x5X*h?Z^Zrge2yyiE=61JlZUXpm4**5#Yx`wxQH+u;XHJ6d z=8(TrB{*6ssTE()4uk9LY!L|zliqfV8GTccA+5BP&G%@>Oy&-Ius>aer=7Pufz2lm zg9U98Mr?cwuJ2+jqQh2CB7r757?iL0d$bD(3)tuw4yy#eLg_1^M3;}>kj|&%F!L4X z+)0ESEB|vu)w``G*kM;AGg3nv>TE7%Vbaz}Tp1Myn&Of{6;dCf!Y=+Qr>=bpz7)t# zka=a;#>P?2A7}UQfsfuHz&C8k(0$?i;8}Qoa3|ymGx_{DRgGDD9qrCzBg%^3CVJ_@ z&nYqdz49L0zK+3`e8;!Wqmro;ArGqx@vVjVl2AkKMj$1cFi*AtBKzL#y)UN0*R0*w6vB z@=4NW^XkCuML|oDM`}}D8Fk?Bc1o)GS^fB09QJY8!jOR@0gz2WCHlEf`_?41CjzuS z=fCN8vDQn+Avcr2&}bE%>w`rgDnRSsa(GZ>{t$iAQ=qT5)BlMZCUSR$^feb_&Hs?< zJoJI{?a>?hz+LFCDwKY- zk_Ig?JfCggx7!TBwy6Z+!QKqDknGE$&Drx#*1WuK3{)zY)^~A-kEIRw6EMw6Dpp#b zyS(yix`zy2QCy7hnHj#Ll~#+%*Hv#1uyQ=VY;n0e8GmfQ#QQ7eEWdHWR2TBzx3Z;h zWjAA?MTnj}bIQQvvpkNTes^c0h|U-BrTxUW7Y1JF2&tRIGS>}HxlxNQM@lv{#KYxg zBBZw@4~hx2fE}0(|8qG8f_6EZOPOHkA#(3~N!ysVTkJi|WPGqS#bFN8IVg-h;K_Ud z1EJb1&56j6>qTmMBr|%dd(RKf6TuAEbYX*yr70@Vqm!%u1O?Sb#DrX|wvSF%uCVIT zX1BD^oyV(G1J_ch5kAmLEiXZ&K@?`}VL}j)&GDWAeANKlP^NzDSjwJ;wKIK8RGqYy ztm-@;K^AOkxSpcBuiWZ;sA+M`q{dWR^GltyAzp->fqlMzH`^^GHU>A( zsB4F*kkq8395?|!KhEvUQ4Mc3A#$q052VICmWz!H?wg&*35Sb#iiwN^k64aQ7X80w zs^9IsQa{BXM0+f5%0~aQ*@<+eq<3GdfrDWwmr298h!0AGABdS1*!XcaR#~^K40lF= z{-FvxF3u9k$E@tbT|`{~Y%BwVKD$4vwsQb-Vul#-j1By@Jb=o?X?Q-{;t_|K!_oXJkZ9Fd1no&=t9r!UmV;=7l$ks-)vfJF) zjMt&K1xva*>9}zZA}eJ;0PfC_`xfcp#0WfXI{u$>_sFY(kmb6!g9D?Pb^a5-(#<-o zMh3Q5Z)2N!|7rWY9XE~hLD4h+lpS}%aOEmYLm%a&eXRA_Qu(B{Jq$N0jGxarb&tD} zubX|OQ4UFWWopOdZsh6npN`4FuEP#9_;5KtAoi6SM*|iH4RI{65uud~znQw`K4Xbm z{kxPEL}l;xzP@IU+jxod8j z08{88qx`U!UY_}Zo@gyN`!%5#_GG<-S#XR)Q9y-3TQndA^6&W%z6*|CHH>k+GAR}i8DpkOFxF2xxPSN6&I<00? zu*`Y2CGn)uB{E0cM>=%4{pn2+;J5-P2b;$&*loj_J?&3CN2^ZS2?0d5r|kFDKC66} zM6`|yT?CPPU&G^jVcymubsRVtMQPP1UH(|#c^-pqXFNLRD`4Q#?XP=7O)@Z4@{CAJ z5s0W_Ww7BK56&e@P1=Wh!VFW{w7id&M5|BhG|cUWiT+O1Q4vVp3XWv|N51zCiDKixrL7aa^ zUb=XC8>@!=4OVtZC4BfqeoSn8{(AVk!yCT|gP}2A`-$5cmfz0DQ3ixX=2z+l{78IQ zqou!f!i9{F_1MtSvXbK*6I;{&{2B`M$7TO6i|3*?+8*V4aO4KxoxK8_D?O2~*N>VW zOF}4|{sjech~*(^h;CA`jOjttMiz9`k-r!d8b^E^O?+VNp#*G(Xmn?E^Qzz6*?59o z87W7w4tKPSJ^&zM&@Y#r{;T7Ab)r*|r4Z@i5KhD)6KeHbFdzAd&YgW#2(ge6QS~A5 z3?4c^4gr6`&5${H1iI3`6~l9SmqhGO->KUy_;EZ!+U&I)%b@^m$VaNQ64a1~;Uife zl?|~qle5oJf~3(NgS_sk=+o5t16o)47?(k_wKpVS_OtJ35i$$>6N$k~-=;i7?jY)T z3uBYD8ab4HqQ{I$h+)beA5f0`P1fJ1syqm35z4*}tkB60chZT@)^Jz3Xv02_(nhS= z2Y%sK_rD+hu-sEK4=J;7I?#R_9~G>e($o=7Ww}MBCR+Rk@YIVxC~#SwmR)z(Mk?#G zF;qFWkO!4v`;(+j;;eQF?VGM;p?14r5kH^4xt)EcCEgAa@A+k4TJht3qFW29-UI9u zt>WK%YG8s9#!#kzuDmh8#3KxfLOP^0NSw4cv2({$td74|FjI{nI|+fMtp4S<<^oUw zOf#4`Gx-P_QTSpBINEI0KW?M|XEfl)4>qPdm*n~dFRT|^WRxt4(|l@n_svI zayEN(`lS6zp5}I_AYHIdz&OZ!;=8JuH2>nc+dwRJy24JAe1eT$6$)#+N#HS;yO(jy z?t7MYt3fQ1i}I+x_aQ6RqPQ=SXLLb9i)xLd)%VFoYc~i+ALqgUt`y&iKP!G@rCvgI zM*s$kF2Du7*PNq51~9f3d(h1PGY!(Bz{BWJ3^l-B?l--7shcRCpCl79sO}Aj&wQo& zmMt=wK?}TpyTUY&$5k%O>OaI$1RhvGK6OdyD&ms4lIC?5RBPbVMGt!q+}q+DVkTZ^ zM!zYtK~Wl^GrxZCKO8F9#TXjbaMNCVl$3H52kLMaXgXQ!1%eJfQ-Ua4BduwixV3wwrqJ6y5k$Tx-v&REW{e< z`zdJasi{kFo9|y@E*I!{m@{KCAdCNKEE%ZR#v=vc#9~kh?=*RujHojUX3P~oxExxg z^3xo=O9G5#Q$myDjM(vYH~^{sryO7`#Q5Rcqp!_aixu)s%z-S1Gv%7??3se{2$ZMpJ{*?S8*-=+IQNJE7KOT zwz*78oNPqU+&lfhcLDxt0nYC?i%N@iV5}5vHmE z*!8gj+@niitR4k6*zA>~IpHZSgy8mPz%ooz`l^e?6bQFpH+?E8Uvvnh;+Sh!Fj^ZS zO#gO0mX?D17I|>0#ee!6cFT`KQFYxy_}Ny(HI=CvVf?ZnA=^pMX@yWja|C0Jf0& zBbu!g(zbk@Gfw*(kXe15Pi+ z(Ntq?7gH4e2S8n!AALW9&aitX8iKS6SfMTt-E+OQd4Jcmb+E^GUGcs3>aH1AI2Q~| zZ97=P$NF5vYcz5yHL7T4qa^DkbOFN?=LG+~6IX(o*{e8u|ZnTZE7EK&H_iI_mw0C0X`4 zPFWzz`dIZRk=gSS{*7ti;}nkFdw^c5rfmWCa*;lqx~Lq#oeIW0aLBVIn;!f>=nSl? zSTyW=-@j3Xsvb{SGBk7XF}xEb1?%He6^pa)AHkjIcF*`2!*oymV(3o3NNbUT+~^!cU?%m>tmtk-Pn;p3Z=2;MuOT_2 z{`6G#>&no`u10J-kX_Q%y+`jqXlUr)rzMXUhou-;Wa0tBN0iwrly0Z(;fW5VTbX{| zk|U=O4}MELweE@2*%4WythfKqhEc(0r1CM_v@$L}$JD2#C%s0Mubjr2BNLH_X4dtEgX2(9ui%D8$*aqei6%Dg0#Ubb}8NpZM zMv72mfWKHbONXYysM;)JV1=YxPX<5u03~pXD(E0SRbzCR&~-0fRQ&P@3Jllh1y?mA zxs2-LI{iBqvYhLK1 z@F>CLl;(iTOGs6~@pzPgYNv!ov=!GW?0od+4rL4u{3Q_8y0pkGR;%wN;>-x65d$st z5_gXJjj8N9P7I9Cl7>>xGu)k$TF=62FI)wavMK?@mWe zYhNhKoI(iZuO?@2Z{y}jfV^bRl*N89E3{UoI%Q2Rcu!zIA#0pp!S~}yMnEnhX3#!gFij`_C=5?%RB>0=2}TC?K%d$hF_W3n#MH` z-60G;8};xP+lND|NRm+%Ed(QQ&08pHF!spN4`Q^CZT1_wDx8!Llmu>jn9vXmQL8S% z`y-9@ZQ@9n0ShJVxL`#rJCbP@fDT|}jt*vG7A6Mw7r%GGMO!Hnnd9@9!c+lc%!^v2 zbi1W|kn^r6h4N-n*Gz>|>JD%Nh4S+lv}!~p8v{Q+qRkf&vtL`Kh--DP_+7TOXVi#k zhl+toF)KFi&^+ugxZQ~ZdBu5jh(5x^n0gdyEC(E$qGW58tqF*cET4-|7Za(3R~ouk zthVeOZa+S@Ww<}y4?TQ3?Iqc7pxBN-j-xxOj=B9bJAdw77M&V;vMcTLqWy^K;hosW zhl8Khs~^-7WmuInl3XZ9zJ%38(ksd$2@8WWrb4e7%lJ z$~TCc?CNwKn^lyC2-f!r9t#lp!y8hdCH)Ykdl!Hf^t0_@A3dG0CpGU`)gi}v$I;yP zpeegrj|UoLz&;z-opD1nTPH2AOXvKbYz4UmMlTi^Kc3*HhM#Ls`{~QP(sLU6u(vZubz3ypmB>4!8EINPn4O$T$F9;t_&BzqDBdtL zLtI{2t9;YoW!vipegut5KbzCD#T4lcBYq#=K>UNyUDAzmoo3@tGeyEt?Z)7$#2MFI z&vD4%8Q)g1c7ZO!UQmklPU+z)h)cqrzRiD6;Z17Sa823Kw4UB9cbpd0tGS9MdQ6uV zpNOr?kME&+1ue22dNd4P<^caE0a0RWYY3P$M{FcL0ut$N?*%D(n%(UsaW(a;664%A zZ#|q=?A6@?FyOTcP3FYG#M!;1msHTjUsm_OGjr#K!;#ntpRb({q@oWiP5cWSN=_JB?F#KzE&%BNzjNSuC_tKs z(ddA>D-Am&q2JPM3~#>|6A5Z}V1 z$wow!sYkN0yBLdAbu~+SKBWF{+63n3cA~kEywLw%5^@HyYQ7ihQ+B7ttc*d25?u)> zVt+~ zt;-ca+00pFsfgnrKyk!nHjJ70IP*+V9q-f31oc)THBDj=LG=3W_bTopwM9yDBeD6P z?TB-<^ya_YKJuk6YO^Rto|!h(b|XEC7-k<+gq)rtPu)c@;!2=93sd98k~?j8{P%aW zI@Iqbzw=p6nlW)prn))lzrnyZ3uX@r*mY^G$Qj7D-V8WshX@fW=J=upAy3f>9gE)e z1~`cF2n#dUd`YGoHwGx59VHyhQ*FsLq@IYm-_PZ5qLPba=1vdc2UAOHvu%H}*LILk zl(vG5tW|yKY9S$=o;#`rAoC}EGxW{8< zZ`9y!=_DzzIBykuZro}{C#*aYp)Q807X+DFFB>|(ebOer^WvYVMHnxMF*>zwgppB2 z`in*cok==)VWTB0qe+VbZ$L-})%x5x>59?wBj^e=Bn1O3pca!#PdC+$=(g^;3r^58 z!S8BMiZQ}}0_Y7h(36mk@iVB=+jg679f@*3w9}-(S5pAGFns+YB`kWeKk|dekECia z8yT@{pjl0oT&Ca``{p^jto7>OpKuT&1y%OHbsB6q45$_@*N%RuM*1mYL{4fwz3P4^ z;iN4ly)FIWKX!)NF5{5pN5wWA{ylrEP4|Ok_v;0NJQJtttIikjh$I^?WaVxnc47y2rJCO_@WRpO_al-#a=fQls5|_QWTREhk*Cj)2eg zquFHYr+3IV@77>95@$!km5KOGUHhWIoyp>vFP#+Lokm9Kk}$h~)pd}7W4Ql+9&Wj! z%+OhquiZZhSWYP(C9cBCk9Zf(L!XR2?_g-!b$E|-XFbaL-PNI~0ereAZT@E;Wv`%p zCT(>KHsYFm&!ttMT_!SGjTPK-8Bwj4d@f9QK z-QQMs-;U&96D5q6MSMaW`;K~~k&})P-}>(#0FO-g#dZ8#@pfd zPB2H@|AQt&eh{25;uZFA=&}d@9k2irhYflgT+{puif6N__II6zE;~^wqK|1TbZcHQ zSC3qyIAAj|wkNto#X!NL&#Up_1(@@5K&VE&KQ4^m^)7huCR(5pn8G)@9fJk$L}Tkv z?JM53Ms%%&?0-sH;A~OGVn!k8{Ye?BGG^xewNQoV>;w&~(ks-FTp1TViUfi%P>lF7 zFmrN__85RNLZNjYs1hv|!?vqssBc+|L#BMEyx)waEtfC%`$A^1oG za+K^t8>?~Lj43PRVVJDvve^3pB!y-tfuv7AGdHB}`1I-hcwhFMsp9H_g!`*4+9u{? z#K%t(=XZ1!+Y|yF2@ z)M2mhwEZcUS~hMo6Dg85-)>qxKV%Lby^K)u0M*oR z$O}gYg##;Zij$MX)j4j&Y=*}=2W1c(xBN~fjc(t&4?_fgjJVAxT8b3AL>j zm061Z7E-$8L4Jdjx|sqp(U2Vf!Yi?Z^3*GRt^ZEpWn9|dM8u%bD-ma^Ac~!OKBXPG zd#Z#&Di{AhH5~p&gz)yOdQh>8YK!@H3KUI@v}GHGiV?Q}HSBAQH723xog{H!*Y_RD zP-E&oY{&TLf1W?zAW<9?V_?1PLL=6|ePz80^5lq+0ovqcOQDB+Brb6m*JS^E1kEl% zQX+wJhebam0Mz;UH74hVNsVx9%-~7RJ_hxVjqVf|f7;ktQIxluRxh@P!jQH($j^AV zi;g@)DKaVesL$5I`?T(oK9q~!f!{1+1~I|d<7nlSs!I(H=v4D5UykObyFbo&*DMb!GMu@V6|aXK(R&{~i2zSsFEB{U{vOLAuB_OWp9iEl zG$9+C6b9i13!-S>st!_h=q0XtD1P|IWW~e&H`;o56j{PDw~ZBVv^8-Xl6^XEuUXq* zd;>HZ61@!gVf&5`=j`l2;rjQAw-*3dSU0&bIOx`Y`^u|~p{d%X-}B}KQWc3SygG1F zBCVbmd~ahivOtTYqbtir9!`^}9;RRx}z@c6ea%4YcQ zT%-MafYSHD@reLA%My7d4HKI6Ss*7AI-2!o0mHNw+z8e?4R5xUu{w;V0AxTllt2?q zN3%B2tOYpfcXhbiSM@k(!pYRXG@pclJG14l({)QWk^SY@37QTk(F|DehSAV+uW;;V z@QGXc!$5L4igh%KE12q;rl^v;2N{_fZSbTo?*jN5-AwLFyG#!6Siv|gZ7YV64(x+_ zQlpeoNfTi&Hl*BEt_c3PD zr`cBzZ!}cu>RT|48XN$2F0g?ZZfQ9EW%fvbZTyb=(kft+ZR0bE5&+08)xQi-tUS|? z4etPM3;BR1=xwS2gj%`@QwyA@6t{hVCr!o^a*t}-xn@l5ySJSL@%)%#Z)IJ=BtfJ3 zB-uR-rOm&e-TjwbqO77TquJp9gUPMH`5tR7V4Sj$eS1kZQCUsgattx%j~ z@TD&EzD)n5Fx#}3HlFUp^UHkZ&~Q>J?wdv`J!W%P^P;(WhcIs^hI-qHjMK68Si%x2 z`YnEuW8jM*zFS9Fy?vO3q6s~f2^{RG!p|Q5qdmI=`phynOfm$#>_c{c^DFKjCpBNq zG<`_&btHq+T-Pkch{e%To< V0TR2_$ESIg6zkU5)W*x{^NiJlZJ*| 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 tQi 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

      s%4EkUY6>^u6>}vaK*lswR(Pcj`;o z+zVJfY$NJ?tS_T$rV_?kUt;*I{cyq>W0P9hk@PlWqfBp5ZJ@jmD)90lK{*EGy z&|~UV3w7*aM<;bAsbx$Qd2`K;tu00tcCGL4djKbzV)c*6bhx_ntMEM{dX$%@rY85| z-guI?t_(t-W_B=Ef9j$zS(#GZ5(a7o03}2#k8lSy?+5}uTDNth{$B=`JV}V3X*?0| zfK&zC(D9_)u;tIY|Llgyf#aCNbh5q?155@SlbjHTxVicF<){r^;z+#n==FmDnLYiY zQl$-Gu((-`a`;hH15O(~#H+%tHafUaHSa^1<_AvYsP&%(KM`dA8G8al^TgSmf*_G; zvVJClL4}b^5<8B6m1KGY;bK(5(@m1i@dAQav&XkGM zk94FKqqB*STwPQl>o-@t(sv5v+0KZ=Dl}NAzgj8g-`p^7)J&*%>%KA0v?ErZeVtk_ zaz8U)_o*)+SPjcgY1|g$U_q1b`WE2-I}X*>XF2PURdMuz3<4%vnH3{Me#W&T?+T)G zjX14Q4utr$<(``~n{*~0y&__5l9aoBHMxttbLfqXY>c?!YCk$+_A_)|!HYA6R7_%Gc@mLq957{-1z13T&D$3TOQapr zqlJcgrLG%xW$z5?`;_-DU+ z1RNdt3t0#{fAY4S)itvHt9PNH<&meIDT?(L@k!@N065hWtyr>Pwig$h^26Wd`@Io}v;CXvk-@R) z@hfd~>R@3Zg^#{QP+jcGajU_S`ILi=I?a|Dk6IONHk2)IuY&F){rnF_lT==;BvQE| zViM%1<4zfAJ;(x^5!cW$9o0~PR9-ZKOOc^)gqVIy3H9MU7Z?Cp?8(;7X39vs^IT0n zvZZIZ9UnBORywY;S0LUX9)`}f1<(m%bO*|UJ>!<75kq<&i(tWL4@Bxu-SFBj3B6{M zfDscE-){4sFkO`pDZ=w9E0P@!RIWjXwjX_ZMbWglNGy(-Xq=M>ig0&($L;hS>N~nq zLllez-jR+VOq2Eb;}0V0nysF*x#!Mjb>Qp&J|ncewUD;oaobVWDa`}vNIITLSXA1+x_&gp=0lmucZeXk z*iYKwOO0pJRtPe4`I4{s;79-|!{q_R1|VgCzz^9AlCL|XY|4B~7#6<*`=GnD!v;lD zhxy5y{jFvTnL6biBy6AT2?ez`X6=XjuGkF_F&0YZsoDBWd`J0TqR>92i@3cJ}b*;=oyXRM5z&t;wg8p)@3E{CNGe}rO^_*OYB zSmBrF2g?JeaT<^xh1uQUPp@w?zCN5ieD4c~bSCozpbkH7awa!aF0I0{ajF)kwWj^h zF}2DIkNgkHf4ujPlq2P;TjW5_Y6382TTOX%+U_z(@N!~)jc7N_W63OGS4V03?8XXU*&1?w-k z9GiQd6(-Uc!K^2seB|B#I$GN^UFB}l&SK8;$C!+E8P`MGi3HY-4~PYkZovv+qEwjE z)G@7Q)>3|PWJs6aoZyHbKq_!e&z>Y?K$iQ?mnS+BBCL{Jo$dIASPFhdQDLh(U#Uzb z1KT&D2dMv+=r!^o8eDr6+ndi_$Fi{YCQor;!HW6T($}aHGxaaRX}>;XM*o#B5|vS3 z5T~Ovx?b(x$Zfp)1Ut*syknF+qO;9;CyhzM_0c~-e~;|f;7H$|>={kH&0;6y@s>RH zT2z^i56Cc+S_}|7nG8OWxm4{1XO_p>w;^GUtxm$3*+RM*g`o>6H*n@+jDJxY$j71U zx*r?GSy#X2YcFYWU|BpJ3Nm8|_Oz>hI2LwTLIDVHE*GfsPaxlWRG?vXWWY=4R;oqM zPOa*p`%ik4`)XmnaR=_S$rqq6g!O1dZ)oa@dhvZYg$kO=?`;66BlE2D>hL9i1(SE7 z|1Zx-RjL3MWkc8x%8e5Z)I->)hW*j;AU+YWQhxi6m;{`@J#GLp-40TIYLChSrr~}1 zAofV%dWXtWmk=mMk?-h8D~K555~2#f`0RLhjU*9n2TCzv0L3VwcTKO{LYG!oxs zt&21=3NU0R6#TUjHDMs$Crp4NgD0SJEH{E{bEn3bL0Eu@Gccvd7)V%fhcpR|navN6 z;n|~L?o;UJ-$dF)LglaGW%UM1;CXOTgl*R(P3k|%Wer;cCm6t5V30{{ak`f0J6}r_ zwFR^f<-DDaijqFB+7!LHnt!HWvopd_%ZTEU3S{mRxKp#-4^#RF24qD@WSO8X0LnHH zlepDPP|c=RCOcC4>_JuZXcNx7lz(v3niO4aocC-^XyDWfz61=?AuSZg)&FTV*M2HBjXu46d-*q#S2eD`d;;623(F zpY7!DFU$zLw%Jmx>>5&;`HxwKXp^g-s$J|q464OK!Qyp|9j21bnDm?f8OVD|eKGt?{Zl8r#3$ zPny8SHD+%6P#+-eU{{O;M?VKv_Q;Lf-WKA}iwJ8n+Vlr!oNk(5P0TL2(# z-(Vo8o+RF%JFg-rYky}E1Z>6$6hwI!)s^hfb!!=ExNBQ|a6KBA0XN3Z3oN+{t(pYuf`ghPoR^k zP{+!Z?3ry!)HJ-WTD-s9*+|7MG1312rC_jwgbnBmLlWRS#5E4nb3>DVWOOirccte_ z)~A-aytBK%@BqLrE}Z#cXs@+T(0-0WL&6Kh({i9#Vpyx_{W~k=8xS%%jqkM?H3QU2Hy5yQmfC~2lU9Y;p z$aG{>FY!$s;fQrfnoCuD)u6LVjrqD6BtnaI{P=oQ#_z7;*hlaewz}MidD*7Pt=ZC6 zs~M^H$r1UTuRb50P-4gVV-$#yFy^Bt_Uo-9B-YI_n=GJRvZ z-us#YzPdeAVfMU8w>V%uN}@CC6%m0hN&SM)3!WyQn*4OY>a>>8G)30|M0if-9nLH5 z_uZ8m1Syu^FiRSrLb(iUbgD_191fJbohp>pe0$&u)wjV26)5<34W;b}8mAbtLgq|^Uz0L58|6y&I{ zT;t(G+8t|uRL+&?q3AT%3^|-X5_p%!)@^?@k&GrW1$DFF3xLHus7Se_5zbgB<8U1_ zphgVb={163%Fl1C5&Y3f-b=>z^0Z4v)}3lGJj=qqodMn+h&IxGbsB2Pt{sFNpWeqR zF#f)y4WhKfsjwZ&NkH@r@E)dUW)(5qk<`GT){Z zA^QUmB(V$G{b>iCxo46-e4VS^XHDMMvC2 zZhjBW?4ilpW&TW73_fwD@Oo^AsJI*^_6GH9ms3D&nx-w8)-WoZSTFXh@+sd{TC?CTr-NZGA1Y@^-~RATN7*1B_wB!jCh>7p_ng3mgUQC% ztR#``W9x{z;z3ww6VqwmmFDojsVMJy6;L+89@yp;4}*Vgzwo?&(cO}qXYfAy&Vxk z9LrDEC2=kJ0|gW1>R>h;@Dk9PFMVcV@3uAD8AYUcz9qNWpiVR2ID%R_67j5h_8NIn zaJs{JshmTX(;Qw$qx!-_O8N&)<~L7iqwRCHhD2^cCz^oFk` zuX~5a$Egi4ok5mu%$KAV^JLj$6tuo;%*|Ie9`zDVzVFjHw@cCnc~f7v3b`JPvdn&3 z6XTA(FaX-vA*HOs{|nX0$EF8{5xeOjv-bgCfX)9wHKgEhxuI^Dyfrtu+Yi{d@0`hh zR8F~2n+02GIY~~Un29|G94LjG!o=PpmEi7OWF9(xi2rBu_7m(ViX~Hf8|zpJYowt zb?!uDHuj4bSne6WXtQFZjfmTZ)6oqI_r$nVwMwi`v~-kYkIKeTq||JcWvcdTx;a9f z*KgiI|B{G_OG4W~tu%a-a{ueS&5WI*aI7RM|6s-sG-B`C?&fD>)+~(ibP$IycDM4Z zCeGtmxm(8sL~&~QLFW4a&IuOkCy+H@yT0m>B`w|GsZ>q;)tjRMRU#5iUjeLZ9Y-OIF`Yn}3LN#$cj|A;S0(kFqq- ztm6%A&jG!PHhU*1K5m9y=Ao*Vh}d|J{OgLi`{pMra+>8(8bOCY6x@b_;U-;v+6EQu zP$OE;6YG%gY`Wa0-ik3g%xL6-8B)IAv<=3pET89V*w5E?a@W6$1UR;0*%QFN);_&_ zzoPRcw;^5&H#Oz|AZDZFO?-pqV|WeKN;bx(3)uHx75u+);`zHjI&f_OY)jvSiJa8G1Nwia^Z+JaHWSZ=1B;6q>pSgNvANAwHXR7E>J;N{n1#1^ zfix$D$OM|(ina;;Wie`I7>_nExU#J9XT<{Qx@89i=~JSmIu8aP4S!2sN(I#PK;qM) z3Oa$*GT>=^D*|Ns6<8EvT3~|bi|=ED&OHt6v?fet5p06^P|8P@NtU?0t);pTl%5pf zl|(fT;HYo$@xduCY}w|qh?xj5&@KlLESdRrbq^^0{wB=#Y3|_fHs_i-Ae&fW@`RAoE za|jBg?;&P=Tk%n4MNL7+IRMmxOMIY_fn~U2Grv&``u5O|(~~RmV6KIVO4!a-K34%0 zM5B3WhRU`5Ej6*YktE@2Ad$?K7D|F<0!csL@px4D(D^SE>p%8>Zg4M7imt|kz7}H~ z%bse8H$qWc*gh3FfvC|$G5~H0vYcu40h19LDyS{ysiO3wjD=dCl=!N@mQP<2 zjFoJkLrHcNoRL19_{zX*f<+7`EFeXOUYSc?W9*OKc$vJnM(=riet!Pz9K-!+VRybP zv%w2cKThZNk5{{iqq+fZbu{425*@ZZZCD9-&i8+D_0>^Pc5T0sLxX^{fJ!M1O2dGl zbgG1Oqclh}Ln_ipBaI-UboYS7fW#n5$IwVKC@TZKeF{AUAv~5%Y+wEtP@3UiuB^EEUVH9J28>_h;Bidsh8_-^=!( z-&Id;&pi}PyIgCYbW(V(k^BD0*1|QGnAMK;;T@CN&EUS&r)rMi8}cR8lrAKZg$DTg zGMwZVpJ`uPHX`;^)$*lHNhoE;Q1GP^<)SoVXwJww3jmazb!qy%vFUr`lT6J-k}y9W8!M&IR);x_QFK&xiwu5};{l;9d zOQRETgAipx786Dl5@oz*xq$drL6)uEsOeMwIEcnNeW=m0xg)Y5$M)jrmRmuABck$e zgdt$wsto9^!df*e)R_IA-&FXca(}%H5is7JWScR#i z9|7aV2foRQg{2ql)vtUW2UARTeq$o9h+LLjj4OXVp23YkSWc&R_ICq?b~X{y8x0#3<I9%gA{fSoyVWDD);hC(^@AMkbW@lPOs(7Pv?cNPUmiCA}20C>G9E%y?tD$ z$G7O~p=Y{{seK2ASFH6KioY@ne1pGbf+60RE}Dk-A?i*8YP}Y_5uO?w!c$9rggDi+cO2c@_W~Y>U7zuji6sO-X*@RZl`7inZX*L@V;1E|E9u6u) z^bOu{i*?*mJ`whyFno`9yDQ<|JFJg~Y&v6-kdX~Ei!v2k`GBaUv+xJU?`DS>s<=%D zSY(QBy1kllBg1`&q*-2&BC&eL1b9i;Ej<6XnHT z8a+s>w%Zabx9E__T6dqV)ncT{kQE7GN{weHi{IM?0&{_yIc7BSx{XxH>0{1MU7lBE zCwiInOwc8zY1hLsr$g$?s^9LSrvD$Gnss+CZ!TjlJP`5S) z@ascwx$!>4Yp&#cf~y?*rPsvFL>_%svT_gg$2ymySsAMNDbP=W9wnFg-aM`fk46I=}G6opPD~2Ft9|0 zMQ+P=H34-@3gMj%uxN*Rg7mNb{;s#=pUz|RvnI;mTkmfwi@N-wpJU z=raWQRq~Rf@c2tC=arW@`T{GJm(?fCz4+^0;%%mnd`=^;73L%r^ z-aMjRmb|_L4L$TjK4}q4U%7cZ_2e~4_8Sf8x=~*0Ip?khuvG?ER+LTN?BU1eE3z;> z(ABg2%l8eVrAsHwj_s@mQrly{JtY@TIONXfV^K$aNF3SaZl`H0&eL|~JW5NR28@~E zE`w~0LT*o4m}a#=HnK`ry9mx38V?#xg`F>W!B;|t?KR^s&r89$g>79Yt>9&&&L|{y z!|UW=s>#cuGZC1@1OneqH={=SeGQ+GMgYKo)lhmx^W`>D^>bgGb5)1fR|b-)sVR45 z^9=mJ)7|Jrh;MA=i)ptv-Wy&(TH6ad-+4BF7h1E93T0jVGg1<<&wbflP-DTH*KLo^ z?(u=9J6(h3^V(RthyH+Us_-smSbCrK{LcL1JMCPBLQkuLX__vkvafOn@if|hB{x2eaQt0Y%9`-~9(fEBrBocfd@B%saOgTX!8NUlI$E@w5 zxKW%U@HIAUj&`~7>?nL|H*p&X(H&i0`N za?o)eXF=OE@72^0JeG>P8-MlL18of|o!qNCkCf7{-b9OzLYQp(W@F6aJ-{eG~3%`d}%*^!um$8Tg90tm6lwjm*_OaK&UHguMNp5>`mn5 zM#fl$>C~T>96rO#nW)}h46t3@lD+g0N#m1Yt<*+$<;qGgb5-4}m$LdIr%7mBa+YqP znLzj%X9Tmj;IG~qrUnpV{@ZU>{1TkZL?*kqX+M*^X2EH{m9&`h^dUj0@Gb;jTv z%pW+1urVnFlU$xI+?EeK>jD;%Pd`3>rn#(sv-eW;hebyqC7^sWsKY_d7eE-DS@Mp+ z(_So5?BT#YT@^%iI%l~B8Ra}Y;r3hodr_*kZa5%RW?_0$+S?*Jxy!mFMb2Tm`p%z) zHlyG0C$Z@cjj)5xAo!r(eOCA;zo_57^K|{II-gD;wDirIsd(UTlHjwPDwSxP|Gdb+ zU!V=ByGDXQyr+XumVu=C7FddAl(>ETccvpkvdeI2$@pV*MAi&ue0X~O)q{(GjZR)P zL3bhr^giAGio++{LCbfhA9}yM7lF+;{nDnLR8hhJE<`y>U+KfO5rjjZ*uV&jLylAu zLC!^wt4}o@oxmf)*C}=G0ici%>@-kf7?KeD9?6K6p6(>-^dCrL+dP<(y5@|qtV!`- zjejwDG~2L~oyO;3y*KMqF~-p(H{9y8gZeZCO+cDsc-ca*vL1i#fS!a^Kyki)C$^C1 z(VRa^G;{0rDomT6hE+P|2Z@r^%HvL4W*>A6)peRO0f9He#>8m;7sPMq`*xdL=ib@W zybo63s1VMGa5AT{3!p1*(N4q5=F=oBqU99Xd|{6Kq}s$s!gv&gFEX_H$|x}a&b{jnjNFPc91@Wjt&`zrXj=$g^U@GT-UG5BQuBPNOz zfwb^`a>7P}Dg|HPo-#Xz|Aq$b{^S5-yPr(E!ypE83YaYMzvkoM^>4_;|f&g(;P=f371+tA)i=*WLW_ju!7C<@K7ypY0{->U07KYTTdKU@AZXCr=E{rm ziZddg?#{eXS>#m(?V<}|PP5%L!KOtjwyO%@*);}u-VIB+v0Og0s*ASz3XxE* zWJADbAUeskRQF-qO6-r4*f>hb@817x$4CugZ|2y~I@6=&ESI=FNT4qQtDWu3Cd4VL zm!g6aqOab$R++WPNEg;?7^Jzu?MXMaLj-i_BkRzhxZ6<^RUIE^-PgLGRjgm=4p*lu zheQ~L9ekQ%kI2dX&h_+Ko>!$R0vyQWaCQ1r?h=EPp<@*aKF+p`aR@(_YC#8O!0ZwE zb8axn2Dd-eO73&V9!6UT+&P$ym+WZ*8^gt$-(Md{?Kk`Ns)zqTB^IBNmLP>%)^>i@ z36n2tU0+|F>K?v57K$0^<<^niBMiO>_b$?i{5)3SJjK@nkH&v$UYHc%!Zhr6&7izC zINo%yp9QC4uUAb~le+xVvw+*4d;!MZ`k$47UKRicGkU4@@^TTi3zTa7ftig*)x1+) zY;lg`-ru_qy@y8*??r&WbW^V&9z}3e$7ev`7n@t?qG?1Q$9w1A2V7!GU06ll=QKZo zyD4lqE+8SBMUD03C^Q| zfuT&7TneTLVFyc_yOoAtf;sb8vwG8xP z$hpR0?=mL;2G}d^gJ@Okt9y0feA8gNF-0KylbK1z#e?33!ZJ}eKkK9?R-8tiL;m-J z5+_=675lC)5!9YMWKXr#zYecf#=0KBYZ-? z@ZnFed*|(Mh80h$EaVUO{c`DtTHcB|BQMT~qz+<{S}3i&cHz$BTw%DFTcP7n$GLnQ zkVbbme+cM=UY-uhN2MboHUlc4knhX4c~XPk93-&Ix2dYXJ?}XGtv1Qm`<4;97-072 z3Ef#kXQzd`*gp?i->Bk85>14Df>KR}5=r_WQSf_vkNMscWAz>`f=saD?CP^Xg6a%K z2JnF+`VR1OT-`xaoSJ;$v%j)QM$Q;Q<(5UfaVS2!^;{IJO<&KE$(rrhc&shh@B>W@ zx}9AL@jvu%&>_Z@%!ndoH@cJk4#kIS-cmr1llVDvRYb5n&I7cn_S=a9s$Qt6n_w|? z2Mcz1>i+2udiM#B429XFMjt_tVf!3mYfAG+b*ju$i+3%adKJWny;oaggl)oM_7-dp zZ<;k-q;`;SM{VPf*Gj`JtG?y_0Xiw#QR=sM=G6x93aJ-Bjzs7D>4h%?_%aC|>;icToD*6%# zpKp>6TEZYPuXDKkm-{k22f2+t)0P>CIYs4v4eQ~3+qe*P&@*|aXE@45M)5u7o2gp| zYn{Vr|IRT(G1u|GyH(6>!lBsgX*$qI%lFWT8Mfk#y6b?VZ$DQ-uHq=U^!uB|;i*bw zNfMVM`uS#9Y!gY4P1PE;74I$lV*4K-x)Fo)jIa~SCGQ{6$14)z4?!|#@n4)cl4cZ- zEk-|PbYF+EOLDXpHVOf9PGd3DDzyW?DqgluQX5vo-_nheWHx=@M5dSnoCs$3;( zb1t#Re8j9-d^JJ#Ad!v;hdGV^`X(=Md*(N^P+b^o39xNMOlKc z?7x0|@R0JlPq?x#UefFtWW!%-Ir5XoYP=*I6TF{OS5&O>-oxQa5_WN~+@x;w^tq@hoAMIBjnHTUY#DuewyiGKOa2l7N59@ zcZ%#8{e4RyN0b1Rr!Q(YGT{@QOhld^D7L7ulBDAM#d?Q9APYA<7q}^Z6@|1NfP$>h zVQCMd3Nd@g^3}YcGa}~zAkbYV&hMsH{uMpYJN(>#+)5ir z%Jl5L8J*GJLydSp{K1@rA8L^!&X~fpe@n2=@5%eY6yCmr>yuKLbPA!+?w2DyJvWo0 z0%MKmOa~!LqVp$BrYAfG|G-%Fx3oARvMw`s=$>bEW*gic=-twqPtcAqKSIhKcdB3{ zI0Zc|RA&8BSEJ>Wvg9e^E=hQKGQl(uK^mhmEokLqKF7m|%G`3!rJV=7(&GOEA5x<~ zr|Wmu`$plG27dMwYY~W22k~?UAjD7Prw1bipwgN!&e`(5{3t;P7s1&Po^dSF`%p6k zug4N(>h?tdO+GN`PU@(4k#b^@NMAV2AtceU)IIMsL1WUJkWZt5{k8d zyHwS7CTmqk?5PFNzo%Duu?=6WwZ=WgUbV8`UHxO5AT6N56vxJGE|X?8#K*qf5MFzeOv=|-o+C+ zT2kIs=}zTBx7uxJr8-F*o5l;t2Ne#vwORL!b9)vQoF^5I$ecME;S8e=g<{^lvsruL zaS2*v7Ub|AUT$6~y^h~|J|h-*LK4RzDP!R~NELru_5t+zXg&s^#3%j2$jB(*7TK2_ z1I0qrLHfwxE=F&Ah;v?eP0ZizEJp%-?PX=uq?RQ>nm%#_$)zs%_bfiER;tRGK^$m{ zO=&|I0gR;B!sx`KO?din)*00{Q@r$$fC^@-5lS-`iSE_Lff_Vm3ZtrXp_zcfr+WE}5@_o{xRClGfl54@#Mq(+fCt8L)RMC( z_s_T;)A$rkG(osoa?&ge#d>?pvkd`CZ5ue(9jSh!cY@+;zo2a3Ri?~1oc*h-Y>An2 zsVRyp14?LF+;=jLBdk0K_E177c4ru+-PxF{p=$VqIFCx7{U#7mjS&{30`d(LI+?ggJ0H?`Tg>clBZP3N5p-z&OK zH|!8B39+f?QvD4tKX~O8P}p$%7XdV*vwD>~RQsOO;{-pIjl{Rr*Qq;h%d^O;YZ?V0 zIl_(Q=CR8lt#_7RV$ZX|tEk57!-H`mxHZgWrg4tM4xrC0Tf^@MvFApQfmd zf63!D00?NHBjRPJgM|c6dK-5*RQLopxh?$Nt}&ehk_X@H5@?A4u&b`o=U`FrSsO|!e|mAuE6y@1&Z)4jeIvc~+HWM^>1JC(*RjmMJj=JBwqRAAteA}b z7V@65R;z{Y7t_r)PqG)Ev^>T;Xxa6OlUu9yUpSH$wn9DAwK;BWaGGwH{^~Ui`R$~o zfKx^(Xsb8y&4Rvv4fh87`JP-=E0*-cq3 z7g`O6yOk3o=G^ibxVKqiC_l98qsbz63zE0sk3J5##jp<{&+lbgmFzrQ^4Qj!~-U_%(pe!e|=&_ z_!;C(Vj31asazyYiT473n)b2M_+2CVF(UGp0Z#75odOz!y9%{Mcwny|-TFmVC*9E> zJTtYNoVDb4=sc4-PqfifQ^LK;j=werBhKcBH0b?1N5AfqH1AY`4qLoOWBM%$li;3k z_OOuaO`#mET4ndn7E)@tL*u}CiG;)_(hPo3Vg ztDP^LR2o#Zwu#P-uE}c7jLj!tk$VOc06@!wN8Jd#>(6NW)6i)Cbi#~OPCss)@KN7; z4*)_@nfTAlX*-vj*Ts)Jdh7IMm9>N$blQoR0+p7H9)3(ec1U?-lxFGo_?MLFX0 zt_nUQEfY`-PWVC4G?j@;vX6snqbH1Ced&lv^%t(fki)}C;Y^RFZ5Hw{D~Te)TH~FH zmvUO1ih%su&vOzJ{TpQ=I_mExZ}8$jR$k4+VLkz5QhmpsebiHZo0YBXs}(I;6>5D^ z0@-pEz50+yhee=6>2Z7T(S7)naTz$rb%OuGf*+XkffsG$(`DimUfu7#(R458qkupW z)p2X$C^j$7#fwq8T+F*$)D2z9kAb;-q&!%im+UofC;G~0>&`#>@)Op3G~j_5y3iLg zT4oP;6V|)hqutY-axb#!Ts3`Y8AEgqkIyDI&gYWAG*gwp*8Ho?X7i=~7__U^Ytm55;RoT%7fqmU)czTg@j-eOQ z1qZE$$zWdg;oToX+G#Cz4?q<>diBz^a-?Rrh#K)cxeF}Q=4&W|Qf7`{iQD>>glZ}L z{M~>Jp*p{@oa<~vrtJBtZ;*oDd;pk7cTqABb`8ZWEgZ<)Y&%%wU4#O0 zJ$CGv`Q41W?h!OTK0fG)iHzkPB>IlSNMPj?2np^<=kXr-%K8Cxb0|~HK4jhxdCwT; zM(~c}b|kPf(W-W=j(yw%_)Z=u#}%vg$9hR18Zc$Hic5~{V>#cFN|*-qzkl?zS5dI6 z`@-D5TDxC&(HG8fA=<10n2~PxSB3&F#Qi^a=64???<_;KO{J%k7X@TTMYTz;Xeb|{ zO)S)of*zrzLk)Zn>xT6QJ#iDm#xrSwyW<@l>L(~^4?94ilf3Uj5U zOh&Goa$a2I3@Z+=oGuo}VDY6qlY%Q-@voxo^kkMfQwRseFzlIEfv;w0JlQADUen%LH>FW57U#zVD7}uD zNJ!(ngACIkx3kdVU4MZ|O~3y-_jz~n459$oNa$OA64R-%(zL*GveW?x=cB3X>*qiJDC!|{0XL|I-n@bRe{ni~Q(CWM_g{_WQ^(oB> zb~*X+*!Wg8q)q;5x=@{c+$iQdFYp^IV}SR?h(nrPM-KJJsiWP}IgFp?d7#=qRN&7^ zuq=z^+=t#@{>hcm9|ohlh#mSN&4M`#6N+Gqc+%Q9*BZ7D7d9?v2$uy3+r1QQ=aOm~ zj0>HmdvwfYoi6RJ7?@mpVsHOglIQ=Y z+KdX+`2khn8NhPbXhwO}g&HG3ZHl3R0qzY1Ax+$>^|TovmRsV~k2ItFbaV)rv1Cv9 zBZeUzFPn^I)bq}6ix?;?#d(2pc&+Bb$mgec{Mf8ym_D4;`JF+ zQRyl*-}ChsRkI==TU&}|?nswA-wU=)wbaReCrQ7)^IfG2pw_HUWD|5;O%GLEX9}Nn zLPT3nXXG28UCk&I=H@f%K1@~fg9gM8qm7lC9VlamCHD8TOpl|opO}Srl<=18R>5SB zmu((+t*84DcT&!tRCOyGxW3u4kkub6(R|4P#We1@&%B?pO}uJ8^D`++Z++S$x zJBXrSj>PQaRJW)7V4DIiGqn>lLLBbZ0Ym9c72t|6fPP*oj4E9%ru%iiT+y^(emp&v ziT+*{ObxpjS^w}`_XKYTBXtSjFGlaj*aG@kzZFF)4cy8bnlQR%H*K1P??v*!k(ZMp zPhJpNb0SZ3$k!9McbfW+l&ymdXm%L(GV~yM)B786FPR#;$XJXHzVVm;G(cddr)Q5;>25#`G*W z_csct7jbYfGJ3R$CLx$U)C68a8@x_*nTNo%UE9`V_f8@veka>sv z*-F<0f$W488%1+bs4lEQBWh#Be?E)P>BoRSTIt!CccPMZBY3;|p1}_BUY%|ZpZ^(H z(so#16@CjJT1a(|N`Wg-ltC+`zNX?{iZF#X583#*%G~02mF}c&0#T2p(2tnN^Ee8u zySvjD=G23q_aKWSq$^D?LSB*=3Z!b$M_yZ;&mZfhz=i%lPCH6C9BXX_4&IZ7YRL&z zwQhfWE^B>v36p`PzdjEMiM4z8j*>ObEq=-tRaEl9Zlb)@akb+>nkfJ3MD-I+IfN)$ z{SOm~fz5MMW8P`!#9{iVR>LET#uwnX+GfpD_aIb1&jP^)ij!SJhKi{V6uBMk5e z^#7Sy%9wg)NIwAe{c87DP{p`bj`8ZJ+`A`;M+onE%EKD`^W988bzZG4kc3_?uH*~0 ztse4iXTiSZLC^5tnXgJfdoynycu4{~TJ^5~VKe$xjNxN%g(x|@AbPd3B1JW-7iZs| zGd5qu4|-l=B2A$K`+ioa(zxUZF#$oY8I2!JUE4lB;URtcGiQ=i&BI~AG(Uo0?UpMl z!X;v1K1&)T<)+OySd9d#0_Hawoc}Vw>}?LNSm?}go#!t`L|>cG#huGIrnFf<0O0UH zLWJ~^Hz8xht1$P@GOPW#On#>pIy2c(Ma=uy1-1h+J9B7ng-J)_;4zsatnM?!l=vun zTi1DckT<{kb+*_BghT@2^>s3Hrnk1I)*Jm8% zLaVPf4wE*-?J`|`vm@wWvdFpFYyAOk;J;BWWN+S&>Ilr!N%-)Ur1)OR$9E5R(r$s~ ztiQQcSMkF8G~Ng_-Ma{@|40Htnf?%#Co5*7(GXt|}eoKBipIZ7W1ZQ<$+B7z^IbAS-vO;w7*yn5)Q+@5aue+o;wFnUb3RizRCx%V8 zy9r7Nn8!>U)21w%6^5GGS~j`P7@S7xz2S;f!c}rHH$Z#()gCxGj+G+Z{vcr-zH=3h z&tHr+Xx?TJHc4Q#%$ZwhTs+Quc39!gb48jjd+zLib&(-{YWj+^HJnT2ryh{#`kNx7JkjB9NsSujX<>lnyt=(JihD96HUJ5VO(a7zfUr-1c*eRnfp9OjsYAU2Qw z&Z%sWVQVS7?XVA@aRAju?QI!QG0V7gc<=KPKO6(}sFo~qgr~GP z=_D5u8j{|r03Rtn(bd_7V-3#C0vUEmLT0)Tq@`Lq1fa*A(}239P5`VUS^lE}iRi1pg>$1zyXfodypImr6>)W57o^oov49ZJnv3%3Kk-z(E!w8n8vQY8_n;ff;T=BYy5?e z&Qo6LD@%80UfLi*-Y*i9LcLw7?~Xlq7+n=46jB3c$BB6Lio`LC(|&qN*>pDd(lXH* zic#&b`ght$AUn4G^_={$*EmnD?Y8>x*Y^U-O0Vu_mh*F#X(SPMz5|0~&-&}m;sdHv zX}mli^&x8H>2@V|OsKvP&V@XjdJIiq^*W7+Q?30_JH*=f>_1u#v0p@jpmf@$YG>84cdqjC!X0%EL(Z1_LXbT{ z$RL)^!;3l~4@GxVp(E&g`yqi0Mg}CcRc!k)Aa@TQwx^x+oIDd9AodH{uKSg=Hkt5q zZhcNtaQ^-M=y*N0$`SGIVmp6On4xJt94Q2|6Lsf1hv%oz6`+A}|*oTqUoDJE>7i_Nlv92Q_k-_MmgPv>5xMPKnwUyth5+_3llNR;0#JNmen5T`L06+eCbi`~m9mtm`%ru;DUcq-*E%-XQ z%KETCzTA7Jd0AU4#D;-AWcR+@@$T`5UYgY(`8Wpiwku&O8K>(nAD0RU&XvtyAdu$} zHt2M>l*bViAfPLI=;HU9izD#Ixni0Okz8|s+U>%-e?%T;-KUS4?A>PRABklU>;_*4 zuwLQv+iD<;AGZH}ocU%+F;ay~| zV{jO7D|?Ar4DGFE#HR-Ry(BCPAWeAi=hB`_A4L`l3xR3+bZjX*Pcx!8&rrSGHsg&@ z$8tzWp0sd0*sGdgUwYbst8;171nVMV5Gr^-l`%p-7EImtAZ#ek49nf^K3hgd9f?1m ztYHtoIF7i_JNijk{^57dhVE>4w-^f)oe>vVx`4@KxdaFx+Pz0F{M+08QDWHT5Vv07 z9M@R)WaoM*I$AnXD`gR&EaG>DrR%ujMjpr&(kG=-dKuy2YqN5f+Q;l_ME*dI1+B#J zcSg0g2B$tG!SPuHtovXwV85p_t8-0~y@TYVQXhTh8eL>-nvD59Eudx$n5Y$tMP7 z$Em5hiz`Clp_{a~5u$3rsDc$QjzL5)z$Plm>EQ={Nn<0(|p27vH_(VNZyk#$muWi@&_tjR7Ct@1Xhj>K>({(yP1g z!4xERq{!wZIj2#Lqcr{sAGnouW@iw_&s0243_6rH9PoU^(YPgctbCYl7m>r4(}#FE zBzNa!UWoo-_Elhb{%T@Dqg}bdkDETNc41YvH4E}m{t__Nh`YR3@&Oxdyu{JJQAfQ6 z8+PH;vdWpNvrfg4Cjvn|`Ha|-rVp_Bci7v+hBt!3)aX-F99PfY5et|$7MZvvu#1a9 zLom0`eJ{C`o=vq(H;)ivcA8wjv7nDOvvx3%C$uDAS+2kEP=9q^<&Pse$Ykg@qNFD8A00Ohh3%>AqQ}NwS zr3JCW*wZ{)RiDtV2(_`m4PUy#Q2hT-s%$tfFL zjJ;4!e~NG(GL3q$<=*vx+o3IB-8YnDFB92r{6xi2KeW;LNtjJWq%J|P{pUN5IL%jg zsREC+0xj!FSv+!Fte~TOKaNW9QH<6`6n3Z#adf=u4PLzA8yUCohN+9WlbT<5aci%w zIJR(^9C6KUiF~=$CG@Kiz|2*;mo}_=4+~Kk$wlJ^W!&~m9f(IKho+-Hk(G`p*fIoy zx8HGYE#R`N$?zT5X84Vn3sB?>k}0xA;_d6LH~^44ll*H!g`iQRYR}c|KgcTKzd+=I z@6N43n{x9u_GhI!{Ys#{D8cNel@F@>6yvdQ{C{UbKulV%AXV8H=9-uJLsWX}(d-RVgHk74X4Bk?UBs&hUM^N>nbEM= zV<9Mqn>vS%OC(=cI-!j;C-tim+6~D)&8xeoCSTurjE5nBhmMWbh{f)egr5`e4C0j1 zx0{D!0z5QG@0!^3c4KLi6=j#w=~fK5sgk|RQkYYT;5}ODOt<<7s&#VQpJCa0C9y=) z{R3hCW9nD!OBwIR%!;@!?73CjK+c=OW=Vqb4@0`|Zldzhy-}#qUpfHr$TTJl<@iC< zanMovIU(rvhB$glH)Pf2`1iAfo+%iV9S}G>RDjPi?;Xw{a+ry>U>6lb)ou%yziYr3 zD8DgS2-vX=+586t%-+03z6yZS_AY^WqC>{{pP%v?^ugHGQdNgxeQrvzH2JkEbPJJFe%rlkR0SB9VbUUK@j$vD+T;mV@*k64ouiLEHxX$Osm?&2ld={yI=|Mt?E57K{qg(Hz(s_x~gwgi0 zLeMOq)LQi%8c+F$uTh(Qr_NMhP3a3Y+4eTHEX7BD`FhTtd@BUXw%n?vcfajC+Jd&S zSJ~YBw$Nq&h16dCs`FU@40qOjP}M=pXm)5Wz%9*%JRkdyjun8F|IxAL&b9e`dw%!f zL;6)85J#|LphqD4==Dlzu4_BSoOjs|hVgz7{Q;62p%%z@!ZXl0y8r(431cqDi^r*7 z;ZYN;8D^KyG)M>&mO3Mc2<||#SuYAXtIy{eEAXZ)uc?F2#5rOwZ}LP#J+>qdPu;Pc zV)x&z{+g$isgid&Ng4k@B+F0EWV%G}4_^i=AjMc5BG?d{i;}Us6 zv@(oespB*cf5vG0-)HN-)R)`uIj+l>5uW_gH4|F1Y3#X*fs;@+iLxuf7>F5G&NQEw zfAcn$t<(0-r@F)OS2q`rAGgB1(j=jxYb*xF}z(Vn*mEulWhRrmKXO%#*E_N!B>N% z9oDZ{rFiGbJ9_2B)lKfmgmr!wVZ3ieR-J7{oF_uYwRTwzZqp*No}5ilnWC#(zgz1N zGCdl!!-0Vk`>n?c<)*NkbZ2a_)Q~^&e-?t8oaV*~BTyCYmZ8UpYeO+9mTRBRkU`yh z(m8(xrnm5|A1Na{(^UHYBQT{Z?A~Y(AlJ9F{;7OZgo+GWl?mK3n zyhS^{ZcdVC!0q0eU7xljj`h=1svc5awp)WV+LN?}P6o=wXJy z9!fr7lFLTAY=*X)I9zb7b`Ng!vmHvp-e{NL!<(mjGa-Z;+J|*E(QBKH&ZtksVE8?A zZ28l>7t%`zb-YT4B>fvk6pjBOtjY75t?}Bvhq~LDB=q#(&SNSN@;hLYHzTuIIurCd;moW0IORC~#G~inV_d^)O~%X>s}&M*-Vd}VKEH^f3?JwT{j1UGi^h)_D_u%AJ?JmbszY72 z6W!-{ORPa38HPcGEbmNL7p|Cl>{Ns#Oh$DQIfkrg>My|ndY~Co3G45^7@I37nUa>1 z&|+#Xi4tR{u`_1l;nRZ2-xNs%Ln=bs`AMx27rL{mBe?HZmZ)DymFTQ${Cm4YA5?Yv z3X}+HiayfU{EzQ2i=}PZS{bwqpeOy9>lMZ+n~`mwNlpo%RB&782zT#`25Da&aUlhr zXB%QMo!vn4f1O7>scAvSmb!TfcUy#h-q?@2UG1Xo0jRf2MR&KQN}w2EY$^$HdWPkm z1q-7!!}B}ToKX?zp^>G{<5hnL23V@UE~|pC)!+9`UTTe!Rm#nb{f3Y?jd-)2I&Ba` zwX;71j9+Q_SHW6W@C?c$g3`$*3PL7d&ZP=(>MGPc*^WIX;B}Al%B7!_na{+* zSe+5Ii!n^JVXp?B_r2C08M_#Tx8K-%u^GaXoJD$*c)w?<`k}5xyFarKY-OtXG9#mJ zN8wF>&yk?f*qsQiWpS?PVn+kIuN2|)RG(j!6P%&O5B!TL|AV|$o=@uL?K}8(`Tn9(F)!=dbieGKdYkgl%mmM=NU?@IoKnLs zlwA$OFn~AA{pgFr!)elaiWvOe2N9eRNW$MUc9|dpbvcq@QE3p^k!~l+_ZBr9mV4#g z`S2L!Vm2Szdos-kC{FVmCebf_rNmbO6iM3Kl&LzSZf}kZq^sV31E{LW{}35ZUf6Ot z-%@1_OnyI)GHdQRH=1%?6k|C2DI{@w>7T(BTbaQMj;?b+kdCk4G^dAGA@`It#d}zd zm(R)T`+)58?b>I`a5b{Q`d7(BSmqJYi?xn#D?$Nm9{Go3zB}o|sr8 z%Us9YQq3V=9VeRW*+)C8AyL&80Qt?|ybq`zN%^O&;${E*lqL~h?fNRE`1wTdW$nKV z=-(MT#*hd;OEFAwPP=Q&dF`>ue8fiLNMP~m^>E!LU=y_q9>8JQxrFFG6Flrwu3VD}f%RX2n6WX2 zz3f3JO%AKzYwXaY^N?Ls>B?XJDB|`05Glx(X`X)9*313Ziw}$IudrAEDQvQ{F>?W- z>r21|@y-ntX^h46h}hyfv9 z9^{Ou{c?MUN!;Q2@27uyJl1t#fZ-_Jx*Pk%xaBpaTN{L>(Pc5&jGsRuiHj2dj$~@* zk1%f&(Ep+9EyJSx*7t9EXpoQ&l@gGah5-=)DUp^AMY<6LhEyaZrCUHylvJb{x?37y z$RTCu8D?PqH{bo+d%K_GcwX^tj)QgI_gdFFuk-v|jsMA&J^_RavCw;l(psEQt?&(B zdDDz3u>aeZxu3Xo%phIZ24miyE-Q_)>>*AuFOo=IGcvnXbIvR&!i5-q_2a#U4ke}S7O02P~YRu`!U651S@obQQdZ~{V2+I-)I?Q{;N9C-qJ-3pl zo9*NT$pvuMei<57hRobQP8zAWP}ij20K$E%>Cax^O1z!jVN`e>`9n}UmD}j6`WMzl zzkQkj>PYcf3s~kA%KSL|%3LpT@P{w1hS7D9YOlCGZEODMHn4_ zJUV%(TAd#Y_-Ec3s@sQ$qQWRYaZa!zWhob?+EPhsyf?LgB3HSR=?SYu`ox2;lcVT} zt4+2b2rUL8fB?z$B}i_biy`U1g#tsX%m#tZ^2{RmgrrLGMzhPkfC|dK`{H`gY2t<; zGh@2%4?)X19|x@!c^Nvi^WcU8Wa>J-X?vx0_Hsh*;ax=qPx`tw@KQ`jQ1Nnq)Pq*Y z@*n=J_^m|Id-PyJ{8k+U!eygoI9u`>cu`hanczS0o^_)j?rB4$`P$L+#W$Y~JkPr= z10hKa%1@u&023o4`<6MY=ErR+{w>)6UobGlYA!E_b=3AbIqm1ZXr)lpXXh6OwH+Yc z7{UoztSRPE>YW)K)bP4}{I)1qH!`i3SI$sGNdOS%hu#m1FQ7i9J$o+3=@vgcsrVv$ zXsF-1O+s!nu-BgHm=f|+6+MPh5`Ec)s=4Jp|ph zw`7LtmwAMH!P!7$BMuMxBM6Mi(HpuO>er6WRj8(foR7HmhrivZ} za31aXElB}+$M|2;$85U+oa&u)e$)<3x0o;>7uqDjD|4WOB*7QUL3tHK1SV+vCF*^6 zd@4z!`YdyDz@%{~jhPwnQ4RyrgK}Wk0bJO`pmv`|g9%p>cuV1Et60 zhY)j;M1obBFqk2Cbd7f4^W+CvoK5S|9be+3I5PG2m+x%>0%9vVmrT@iHL~nC{#kzH z?^g%3#v#R85k&>^tod!YXLAn1IX3?6kYj=tr-~*!$zkD2EE5gF2If_TiE8hO+w#%|^UZnX=3@i9U%G=ER z_wmk$_;n}J*~Eh;#lj<>??TQzVfM-+?W5*F3T7S4D}}ftXZVyI-r=Q-aUph}zokaF z@;&|3&d;GJpWVuh+3*_zoP_z#?We|jI6xfN=3f5mox}U*;G@3JhiKHX6EA7~#{$%Z zin$)F<&AL%TaFGd$plI`g|m!cT|2y>X36j&EDa}_Xdow4-IzZ^F>+TW;T;S1sB()r z$`yVr^J|L!iy}^4lIO$&?gDrFWb%VZh2E~<k)iK+A=6*7&OPinp=$h4}vUZ@MaTDNgNIUsIZehjE^ zp&a4M3~*t3RW2YGVFV=Is$R585NkNUnq{hErT8R9ktM&EiIjgg6i8K1X1?>edE7-@OpV$%-**ZO>ZYYyMbijzb`J%mvvQ`34>O)_2TDLi;3C0ftp z4lu+_vH9u(&&I=iZn=U7HmhLF;y-;~q&-mPhE<)h=`~_1A>KZ`!@j*4MRwT3QZAT) z7f=_ym)P=rrK4L<&L$i1S_4_oVA8hci^jeps6Qov;c$UcjzLN4n98k$N!<{JMxW2I zmT!XCe=bRWdm3h&DP(ZPz)hl_#aH%>OW^O?Z@@ajQl>V4IlDj>o$>hI6%i?22A2}9 zpFCyP+N7s^dmXN0<&!g<4U)P&h9@+b=UifILsadf{Op^}=9sXEWiDdrIjBacd~S#a z!kaJ>Zjv^k#>NcTC|fz7hpe~V0!?HxGhl7~r>a9~FgdGFS z_&ZGp=h5j5_D;YPlp-YH^f{xbZN`sfpkvq7&0xhS3_d~l$RDmx-d~V>)TGzcz@|?3 zJwP>#_X`2ih8?&XHWatc33(a1{pu*(uxRAV7m&P07a) z1Gz=&dsJ*<#8@=A4Vt2>NNadAj#-BM+F*Nx8nAOgpY2}*O3Yl}iqBPEyS0A*f81IZ z7q0b31J1Vhf=LcsL&)oCNmc|=A|$pncs9^Lv$X~QebA2}4Nvo~jTYr4^UruQNXz>t zdNk<5&J%offW3;DtF@{zBg5-$823F(uImJYTaMa1x4D<009B^wSpKa3&f(Fb@ga~1 z^H$pnDGR;Xj8pqUAxf|4ZSUK@%Zu|Ad&($+*IF+>Dg7Hd0_>aLsQ!r=WJ$9GMtMES z<|gr96*(9c6^YMe>YGDl5|HJ5h($XKWbmYDMZx8}XHoFLjRw zL3Z~bb5@(cO$NPc!^1ZGd?ErRa|lJlaSgd_a)OSkr2+9%>?c4R$s5;PO*8vbm)2>z zWhIX_ySCQaAYftRjevb`CBu$VmyPA|yg8<2uv#mFGfH{qNfsYjF#62Xtqrv)C*pjQ zn>5^-;Wc^v4Ia{tV~UhJHq`Q8JBTZ9aX5z`o3lMZ|B~Mg?k1S?)o{UvkLG$CeSngn zUW^1$hO}(oEasxBieiQ=}DBI z1Y-iiQU(11)9CG1#C&8c?In8O(vZ0Z{T!2E`kK#8_pgPInFe8D_9bNTzW3kR#hFv< zdfo4>{ZQxFtBznK;fTNU7(xtz=5=!zptQ4rorBeGj!JV&Ea^Ft#3wS6GO}t+oiGbp2bIlqv2Y#J-aZ^P^o5!}X%t&O8)s>a1PUHZLcZ z^Kd`=)@}9Z^#ixS4dHg32Z+|EHe4P=Rk1LLDop)aW(5r1A$$e(X_ayLnyVcuo;yom^o%yB5NpPzu9~phl3$suQ zL+U3@pF$K}qv;wL0sBP=I(WQIb?5j#5ImT8WP9LYp_tzZ zR0>Aq$;Sa-O{ypMd35>{%lM(?ImbYm!cP_V<<@D8l+h=C(x;z*LCJrYP7C1<+nGoU z58{d^0eI=ZUvnWb%U^jXluuNE_h#fh;-EyBo1Q3IqKB zBwrVrVYuE+WjZT!VXE!NZz(CRL-SQa49l>m3$Y-c(TrCVINM}U^PJBTyGZ4gBYcq( zMIal{s}kLyg|qZ3$Jul-pGV#5pJ)K8edS-#fViCR2!ghuAg2?=y$6iMZSXvh+)AcH zCJV@eg`Ia-p#AboZsqe?=WuLT=a5Oy!1E5=5j*mu5&%|-pvQcAlbWraJJwT~V>NM0@nQYas4BJz1{(phKP^fQ@uwYJVq z-Ra+D|0;%U7#wB1{z9SaT zm3hm|tB;G)#HrU;o|Bexvqg)hSm0*pZbj2ANwKBY7F_f}8`af8g7KQO)g@j}Jln>e z^Melr+ri+d&p;eIw$1w%>)l3h;LN&G9Hzt?7M{b^m`;>;~rD=$ez_1dFb`GacF zZvn6_Y-;AFK}8LGZh7Q3swh;R6t9dv`hT5&=kfR;+-sFmnyW!{mQdJp^o4$oyeet}=!c?&{Vw|8srk&HG)dGLm zWiZyYff*CFRtQ=heSXcOGQG`>eSBq31kMl1i%-Q&tmKvp14OGgA5)dvohzsBrRgNs znuCAR8_{I&Wwjg8KbJ>_Ke8G|IP8=T+>rWg6u0lXjp2cv^o z%m3Lkg?rZEZ;LRNr|!67hs@G_7%17Q&vtLU*Q%6v`uoo>`^mk`{|Q4$D**i$SNMb?!+ zX{J9e`HxN8MHgQOr;1$f-!AQk#EMSKv?|3lqbgL|y+CIeQJv7rQJUjr{((;fW7iwk zv88th5nT(8YdQ$PX~S$B2;fV@*DkTyub!(^H zEz3`*Hil3=HMZ$K8L`K7i{7Iuz@gMIoyp^HU`kIIbn#5~-|>E6*NTx0jlO@F;6A+# zTATpyJ%{3+E3vW=SA-%lac3I@R&ELS=ko209~IJ-MUIQ!U?3EbcmUUe+&DeyK25pY zGw8jc*OBh@3kb6A1P|zbI3pMm2@NkN;8?+IpxjtegFGNGHrzB z+L|ozBIbaNiR=%LQHY4%?#d_MX|j%G)^9Bo;dmzg{+`Z7l6=WOMd)_*7>7OnfL085 zW#<+3aivuoF7`4T+ns-fd6g41Au5gfU?*yi;6%1EfKUwg%xQj7^AK9TMj2`;T0eDp zY60|_xY^vA_VdavI5T0wdvE4k=Z=)i$g%jm2MmWJ0o%TdUW31HV{HcI8?^I&`1~!M zx-)5U{-2Lnm8<$25!bbkm`L-iD(=P?w0qRIM!@jL${;Xay%@g^nsB;3Az06inJ5ZH zX|rrT%kUde=M@=3fx`27RhoFL(q$*LO99i;d17dNyEe>x1QW#wCG<==hQXLFL^*AiAyX?d;h1FjcTj%n*PEqui@~%M5^#l8ab>B*Y!x<8-a*z?i4Dzjos; zn~C~pm}Gbt+PR?et?E86VR5FX5p~YO3tc=pTn_szMsKXE;~lE&pdc0rcO7>IOqJ3* zY*DLycc@f<S~^!g){coAK+wIA)3)j3QOes(ECZz?(k z>88@Ys4NfhWqXvs9=0*KtR$nwPGF05T5VScl485%^#5~V#`i#EMO+X~^riDstxJ$fem?sy=!^|ft2>mFC+FBS0%ms@W0&iS8T7xB+;p&uN>YrO9( zA1R8Gq(z5+q6JN-5No^%Z~6kw8p=Nsu9A%jx|LvC{Sc!pvD=m?TmV_{d*T<$^i|T{ zP?;0m(M#})C_v00ZE|xwtlKJ})~DZjtom=^ZW=o1okxxhqSFv7cqnWz|M>fhWelcC>th(~uEP)D41wxBc0{7LE|20A)@ zU7%jY=QJJOg819TZ;apH@X3NTj6}MDVJveDQX=jSa4&Yo94;8A0%)z|L}yy*hzw441If>pZlfzv+WEv$v_YHXo-B(C_+hWPn(D012ig#7b z(^H3kHjkigFHu4{&2=unQ!-@J;S0PZh1t+O^6~N(X7z;&$8CY{2Vde4PYH3S>!eem znN*LN>$~6oB|;RwG(-pnr|l9=TxD$r>ktt66SWHCfyA!5pU!tnuAlqeg2b2C$dU#s zd&miqlu=Rv+uUe~@aJ4^3e{p`oGyxkXyu#l!gx;42W>qbU)?^;E>IXG6bR;-SJFp#DSn1fkd0f$VhBI4AK}5t+oC0nM*CFzVD9`^s$m)3PA;D zC{hP{8a`FXG&YT_;+%5Zv3@T)o&Js=T%P}nYup~mlt`UdaD_V5so);tU-_QgKmc);X0 z6&?$)0!x@ND2p7cG@&1nR)sGKC4Odwg754r{bVbn>Kiiw82H?`!e1Z=A2jw&r7P{} zg8CjtOdSlgK2RpsK!Vj@AOpGBxGLYNKk;8}QG*|3Dl*Zo73Z{HG2?!_`*%^C9lmBG zADx;mQ!q@*%u2fk4PdI1km>Cj>N0!Bal)2lWx33{hb$y_@re5|sf3@i59029e-D3l zV($(${$on%yG@;$;=1H9xA%aEV91TLA@o~|ch|-@QdO4Qeg5v61l$n(yi+OjQH}7u zFL*QG_LA;;iY+Xk$t4;RIYQ7rH2TkXU780Z1J9k**hnbLJ3@&{B zEF5wIXn1dsi0$jaD1H|MesoFj<1Q;Na<{)cd!(wn6erMI zWd}i{%e=+BN=hW*_Gu7mF0Y6Eo_#Kp6`TlLY-q95EswKrG=V>98MGLIOf1!xJQXi> z*vsGI0}qT;!{A9P9`}(PEbO%>i5lukTsL7=N}qNJwCVqr!YP0zsJz}(S9P4)ryM>P zyd~C3TN2kZnBb(}@xVR~cwQ82%;aGkio#u(DVV%=kMAzWoHhh`)~0n2k4AKMbq+yo zBJ5;1mGCRtMNKqqtC)m3tqOcqK_P_^N5Dr)G&|QYn6&Si*E_k1KLQJJDj{0;_jLVOsH>5!~Y?nE3>fRTH|0zs} z@u8HVEZZJe?asf1f@YVpc}9AZWy4;kubBpLrMPOlRF`08Nv=8;x~y)(M^gz|Jw&6U zbUt%_1kPEsdk?p?V5a`Zee>r}XnGrlf;B%5=P(W>gW)jYnD+U(>x|VyBOGv9fY!(6 z6m^_T`!KoCWdqyWpUJDrNovl{pJMv&&Juw>H{uD8kQJkbA%=H9;@rlynLl{zO>aO%M$keL84af;^zS-mf36O=9vhi!}Mhy zh;RfDqE~3o-vwH#AA>`48x&@_MYu%~G=*(d$Io469htM+qjOoXPlh-;qIO7dPEB?QPgFGIVUWyRYv zwamY?FFPjARL@qhGrROTLrw3u26)FS)4prlWLzFk6P&zzTNEcLS#2*H78_X3b#~u% zu$`3oq@cYYr4~skzAMigOhis(Ihyt~V+3bUFeLlxpzAaAQ7wv>`gqdE1abqLC2YB2J zG<@3U8tD>}#_Ue8NhKJ~p$6K@@X5y$=%YH4en%1g?Kl1cS=bWjs5bwC6Wz}RxR(FB z8^uWCT(i8fB8tzserV?mxWF?{UNnSFvz(HrEpCQ3p-P;KgQR;l#BNBoW1e9I$+%Dr z`_C|C?FV9FFCb}l=@?c7oF6}pC;fk&Jj(b*f^PPo^GE-2@=W}0dPtS*;Xx1NJGnLG zMJPh_vDy#zNvU6_-wS#ow z5IYbJA$5MjkGQz*C3}ORCEP!exDS<As4z(G@ zUlRa?4jPWriNQ*n>*=dSdBLB;U_XKA-oIQml!jCUsShI<3~3CKiP;_b8m@gc6FdK7 zJiPYRJolcpPXC#CxzS}oyFh9~L$P8NZ};Zqe~{a0gah{@+8(0egn)7n-@^Q_vxXOG zkxI;V^M9DzN=(~xXD>WbyP*T)Dq$9#wScff%25Ya;w1VO3+{uZUtoo3zgnvB- z?Im*^KN-?zv80`8>s(n_Zp8t3sR`*E!FzXIemCBK9kLp&w)Qn4|Au?h4!o^<84D?o zADU)epRx||GLz(R)D0ce=PV$20Q-O|)@vYn=qd!JYKe1-EY7#O++koj$ag!0i0Ao# zdX4p$-puGcY^Q216$>4BejRUI0i;zO=7_!gVRu6@M#tNKs18glRt#wgQoC?K*nYxW zX@WFUH;;nu>;EST2i(5u!bp<6J#y^=pBE1Yt5g}6M!RP2;2B-Qm`+^;1%F(cPV-Wk zl|-z){()?Gsx*QlNNfE6i>w}trXl3doM^rJW~GR_5170`{3T+zX{ekR#g93+5ccCH2nQ1-i2k3 zph)c{w{}ev;8Ag0KCa;>3*S+A8kdZ-5=`f{>D7Q7H>fa@jieW7Juo{@lMhitE}yBC z#k&dbk`jFUm=pw(7ZXflP_hgu$HV{M?R}bxkW*psw^ro6cFEO^%aWfw*18{`>swxh zxkBQkzK1R!C;_H9yxvp7Jp%221{E-9ZN>qCTM}4S%pk50?XMSVo)ucKFfMVQLXj-GCwqZt;-u-U3Np+*{ z>rkt1e02o64y5GmMO!?PQaEMhSX@}h$jdG17DNk7-K~#ksf~{sPn$azzM>-h{{pN zWx##btY8b4KC;#d6aIOv{Gb6J!wW=uw&#^8rXnVq61RfSq{_o{vyS>0EhXxT{vfr>n5WC(RfL0(WCE#mEKzUjEr{IX#CY5eezvwRyXB+ z1g=?L?@&)Vdx_VPh` z1*5MfnMYdcG}NodveYwtBKR`f?|3U?)zI0;YX3D~6!@Jn&N5u0&!-mtzTbSKNE=9F z&jw5wspPZ;{r@sye2|Lkc$;}^^sv!O9I#(3n#*lSr4-0~>c#9~IZLUo)8M3WKLO(D z!j?n7GWU-Gd!*>uXk8htF#TDS>_9R0l#AR7<=p^T(!&VEJ}oN=9uP|)%_!KnN(9-w|q zy*PJ8B5uvTS`Mx{C~g@8!gxbgRm2JMM+89l=rpT07^!lgd>u^$5V0;x-${UMW7jIT zCP1KFZY#YI1!Y$Uv(wS33|(&1-yQ%nWxHGCsk2aUhaH$`PUtsRF#anCu1n? z6>Xp`zD*j7!zp#z*k(V_4()fvgBQ5+Fw^*nh@IaH2_vxa>Ki{{s#R%KJM>dm^{$!Q8#$-ag}CLab9|k;{h}A1Tw<+ z>K|HZ7}pwn3I-6A^ED%CkSnlJ2L!(3T8ff9H8xN3@+C5kZv~ zC!BY#0iY-agY`kUZdWsG^*dj%qf4nceR>A_GYaB?_TI}3w<4)&Xov~aIafa5ctyk@ z%Lxcn=?Lfu*V9;3h3NH~sbvhH5h{d)^oauIVbq+r&V!e;_gGJLPqlnQP8(nQNzJ`+ zISUq<%LInbG`??oD4}N7#-T@4yN~vhsw4Jw0_-(t;8nnrPR~hMU;ZHxD4L{QY z*mt_cSC?pMl&{EDh_KG5>mK&^m*dGiry8Jk@bR|YR=JhJds&~d->c61JL!t0Dpa{j zR;VKe$M$g5lVNuYCN2qNz_QQU^It`3=VMe*B`|hGb(xHYB8pus48XUfd_P|*ir6h5 zH3RSL$Pz5kn#YtGSF-yIiPCOw6;TxdNz&AM(t!!yr(cu+;wt-ahUlQEYQV)25|lzDPXbF}1Fy%v zOt-=4rti&6tqf*CflF`9FSPwkVzKz8$tvE9 zB@vH=h%o1qqM@XK-{z1%giw?ybpp3y08GuBRzkYHOHCi800Ij;i_t#FT74_xD5+7- zV~LfF`t+D;*zF^@eOSsOuU;FJ0>1og_p;|C^90_8`Q0#DUv0OwQ{JXx(d4J&;sAqQ zouqIqKeR$$bSr!OX2xmN4Zb+hTIY~-fx`~pjD}>f2O;zt(GG3C6*W?0Xvlf;@k=D4 z@cr5Eau`j{FX38dt0Jp5MV}d6xA;?m)T7U4KPzlhad=EmsxL3jKJ8XEMN%sI2O*we zbtbocszQX)i{|HdW>Ik*ZB!P4!`xwQp>9?O<>mM%yU;G?^#CVl=T4Ir(sV>RWYZg! z=!SRCZgP8IMM(4!)wE-@iIO?B~{lz zEB?vd^2;)5Wz#p2?0U^Lg@S?h$s!k}l8%tGOosIo^?#n*zaHN`_L#z_Uq6SrV0CB> z)KtmHKdj-|tl?V+Nsgzd2)u#~1fEd#i9u{J=IsO}Z;r;OI`ettM8hyKxz0rO2DGSZ z(!xZjuKi%_aTn2J#tmBJ0>wX%QR=?b78F;PZnVm?h)SG#(!R1wYSi;htD2wKt?2y9 ziP0)afy2`NG{sfiKt)`m)pJ&iPzdfFl}IlY!k&DMjL^F)7w!ywskDT^@%sH`bxX(6 z7ru=9Kl@!POsZq@LROwXYjM&>TqLUS5Y$K#SzR45^psnm)KR-uD;KFWp)A`HGX? zK%bUyNIX+QJL|;si@+c6!F#V{(BrjguP(-OXY}DCxsM~1Kijrh7CIh4lz^P&r}hZY zct*>40q!N*sF^+W0)Uii_Hw+k=X5NNIC;i^ojAx-gXaWlAZ1F{=8Z!RZhqMvEA($= z3vbQ!!0<*CM^JtWInH)S=Xt;CeJMA&zvVsUr7Z3+QV1jj&DswE^Ted@3`9zVaasd6 zco8^j9Cv=5I}Y#s2#ZUya#68ra}fe1tJ59JzwCP+0c+f}XtvL!cbPd)JLD5NPq0w5 zFNW;hdnV*qnoC3o{J2?_#|?7m(fzy5L^i%*0sG2L?cTa?q9ZfZlrzl;<4KbwlCDsT z-opL7N&ou5|9MfKG4qTic!Bu}Bb0;9t)2O)pFHAafmp0SUqg?YY0sUtn1tU4CanJ~UNOtBK!b~UVW5*z4N zQmFEZ)DlRi-Sgjy#9PH2x6u$ymTCp03$?C4d)D&Wwf<5#1SR*|f9-kuPSAUWb5{C3 zl%Pf9qAWa${la^%*$4V;7n2`!llk?#65i9S&uZ*V8E2*1123PU8MgTGC@upVk9H0w zHHBLq`7wg?Xk!EE>JKrbGNqqy&=aos-sL4hI4Ivm(fz%hJ1d3Um1++VQi%V;*lrAoasE@(qnJJ`szDrg zNZ*&nbYugL%eNtq>%B^rz-ni|G|F+p3u(mz8$VKhL$wq#+I~>Gt8YESw3hAfx{zvG z$VEC&ImQ^-Cn=$fpF-DENT2QFU%(0yPUpJK7-W(Olc|4d&mt5^mmqjMB<2wQGaRg{ zCqtV>)r1t4`@(o_l#&;ZNx5CwH!B1LWWYu7xjW&h>#V}f2>yHK{?8FXZlpV%Ds zdTeQ-P%GtYFalciJ}=$vc>iZ9VM2g6!vvE9#;Sh5m^LAXoAlbBoFxKTo)|8qv+x=J zp>yX&MQG>vFUW7tUWJn;G=%2y4K}~ourP_Izsh#=wYxYSC+Vt$esQ$``FL6Jdr;~DP4Ni6h+{ZU! z-AOGymkIMCl}ztg3>Tn3RT^v1+%-PB!%2Kpo}n+A#X!IV$~#(Y<5L&uVxzInN|gV< z6Zu~sEPK$YtdPCxUAB)%{y_8J4z?yStFitK7%3upQw9p_`f1TDe%jLI z`dYOS@}1y?*3V&&Cck~#mOK#~7bK<)8yvkklzHHyhUU`>J`ZLF5GIJ%hu)Vb-T*^UXJ?`%}Pj-JhaztKE9Lc4+{RonI zSMmI9UcedQMJESGZ0>uKFKQ$aPlJM1K6WenzFDf^F05$!)8qrsZ7b-GO`mT${HPw# zoKimZXs56K>%BwkQXuALS*v;fiVR>+sv&Ry_!HObST)sSFGK zy5}ADg@BLdW{p|1s3S-bQ|CUf)At=|=N4Rp^*jxUwW47Ou z!TiB@-oU~7u+Alc|2SJR_1a-|5sqnI*4_q#E6r(90eHoCF|BKt`|QblFU@Elg;9vH z7sInGANqOZXZsf172)s+;#O>YlU*Q3HQ~VL_9zas4(s)XV>H~hc_!a!P;|P_ciRR0 zh+OICLfD;6mDcNqWxlJwTU)?HjNd~t#*RmH&;l;+Fl3heA!%maZ__K&obfue+e$tJU=L^q(t9bx}(GVlR!p63bJ)Ls5oG+%Tep z5>BFh52jOl;^q`Y68_8;u~Cpbe86PQzF)Wylkdx2|3`O{_qCTkhfq) zq8Gvo61SYmm>nJ4fQ)vTV~>;C?5lX71gX3MAxBE}jFyA6%tc4*>j@eJJa0z>ufCik z;wfVV=xr9dS+GX{+geLURh6wA_8P+{@WEk!Ee4XmKZ^3K8RS9~wVDvk3y45y5xw-6 zZ#xm*YTkQohj-OirQq)j2}$Sg!{I64Og9Jj=YkkpP+a71LNDg5avxeL9v>@nHjRfR zKfdyPS-T9Na>CD+-SeRs6Y$uWbPi*z{JaWOori*10y>{(Ku8@F9-0twfExb8K!pDB zD;`1+hBXllyL`miYd6A?Oq!&P$FnvVc2>iVHFMW40Zxe|AgXFOHx~_enO(W3J?SQ?(M`}*KM0rS!$0d)3^aBvPu!R}+c zOZnUibG-umIax#{E!n5xi7(ii_4wzrEZ_2^JP#SHvb2EtRYJkr-}Sfj^JOHPbuMIC zy@6TAs|b~?D>MgXGq;2>x79MAOd&Lfv6%o0gGvgY&59!O?$4fRFwD|JmB|C6oblp7 zxSCqhM50FyU%qrKlVk<_L`HcYzN%Y>1Ww*iW7Pt&S6L-OW!Hw>Wwn3&_4Zd;vO89;#UD91 zx(CC|@(v|8A{D%NrH?$cCawZ{QYxVNx8!icFVC6UGP%UL`onMbe$vh^YeklQ`%Gfl zcCnLvf~3{e7s@Vj5n}n8H$%l%HS(esA+NSOQ~7g#z<$DK@_jl;*(Bn#{&K0YWpIR1 zg}Ew=tqNeNc2`UpL*E3+z5d>$J-0J?N~ z*>`i)J7VpC82Q2P;U7&6oHd5f=!h+Epd#(*ef2xoJ&_z39(5;XX3c+RyohCk3{}tp zJDF5e1F?$4kH}$bR(+R8HMqgJOmIj4q#eyMfqxD*Z>Ie17{zw+6WOvt|BTfavxOL@5nGTLlXzJ(eMo)dgs))mTUAv}5n6 zS6Vt{1Q2Di2OuZ-NTzPnAKC9d#|)$=zx1(7AM13oeI93U0WUhjO*fvhY=wca52?UM(!o3Wy<-e*NTwZ=nOi1?l?pdU6yREoC^VSg3=d)50+3xl z%%A5(liTM1Qq~lexkac9;ZY;NJ_l+!BU(0gB=y6QXrfvpHMX!=Fzl{wH zr$YCONlC1S*2+vOkk+tPj3#W%r3cneSP>b@h+^Q2bu*BS(FkhTa2c0^WZWUAN@-ORqSS%W^Lmv?Zbz3zLz{DREhfY5CEm?U+kEseC28f zh#(Q9DY3$>X^H{A;9GSI5FXn9SwWcMM<9@a@XcS%!*i_paj9*l*f2e(x=^hULWU$W z>#MB8g;YjkTJHpn3%Na1UI!i@s!ja!+WUYA00RdaT7XrhGl>B1k~#Sf#bgr^6Yfw}H7e1#OKSmh}lFzmBg0*0~|S4rB0D0peXjgZIr3 z^HlMtgHr@uBXW<)85@db1BzH`Vii8zixJuWm9qUyBfmr=MW;|db`-QPE%LIL+st0! zJi|DwSLhbISy=uvL}dgp7ISj+&lN7k*0NO40YDKf24-eO#LHb7G+tdSY`2ZJ*#CC_ zyEc3!LL(~_qW$4cM+W2TcORXIh{g}g?->apDqCE0t?nnaB|;MvzwQ$O^Mq!&4P z{;Fv$9(g^vGst)fephH&QwGGC#8)6Ae2QM}@b@ z3!m^mv1Z>h!s8E)&vL@qKd6G|6>SX&2p0#R&!reB6G8}6c-u@@z64emM@}gc9iyg2 z)H!ldBA!pjq1pt{y4C4rRS-q!zFQ<>Jq!`PFoUY(<0JU0NQvZycY+%}wtJgn zzp-sKPN-N7QnEchHv*WRzdhD+edf2}^art}Trz)YTl=&@_X829c`o^S8%QUoo8(1+ zoz9pklaoB&&RmqRm;Y>*9jULq&O0qhWbve-*h0zZ!B4h=Lv?l{g2y-JNSV)e&RtMM z@GP^3b)xE7|3EM$4*8(f8oi7PRf4MA%Be_kdt)*GuLtrsI#8lEw)2vgqas&6c;LGC zm+dt$nVVmAlp}Tl0My?;q7q`Zy-7cBZz@I zPR}Ma)RGB;y?iyE4b*#Yhbbhit-#p_qA3+`%iRjyFLI0)kO|-9A?0~bE_Y71mjDl&Ni=pxtZUkC>5YkH zNV(qv)Ikba_^#E*qIku)ARdy*2Jcdss7v~-5*F3Fji=N3&(N4{UEPUx&_2W0#hJ14 z_1^g30{)zq$mMbg8%*oUE~T&EN9+FN=RU*t!Q@7f+4fTaUT|xYYgCQ}ob=0z$~YFhcv_qmZI$N-z~rm<%OT4!=@h;(|C4dv z?bDf36JLrx^U8Dyo=I&{=?n;gEnvkK*HEu{bAyCmspjAOjtzA zjsNjg{{SR{%?f}EWl1>H&cPaV>K@WY7*lQu)YLMR+%OGcY5$c}WFfmV!Bd5Hw^Pw(^_K2gxcwy74?l_B zNlppw1v$2x9{%v#IvFQo@uA-sc$CPP9r9_mpr02}+An!N+*zFLYy-K-K&4y=^Vw|- zOli;Sf&za8INO>0aJp~t>eAI`HM(@1?bVWsa2rPUn@Kf)(gHye#V0@o9J!kBmU#6i z2rl}JNPV|61ifH98F-Lt6uS!zl%>c1P`n()PW)^;R>+d^)^W+McsZsKtp zs$~4nKKw7;y*oF7p3b;!+ejPC>teu^VPdsgGujM)HosFux|y^=Vl*}o*FVoy_=$_Y zu``{)EopEqc2hgsno~g9sQXId=?9F1KA*6?gHFf9TM-gHjH!jbs@$H4b$QQQo$nI% zwJW=^LbAMNPB;EjapEaA5jpLx*;?I}vrec6r_Tu!wV~2|<3b7rbt~vmEw1l4*1nWI zPUdZT4gFrkI^)$8Rr*2jof~ai*;5#)aYG;p_>jntuxFS*aHxR3&k{8{oE*J3g`DNF z+BlG_qjgRhL?cqM{;hYnSd6$4?fK#PW#G5;_@CI;MS4rZ@B=11t{nYxK)qNSq?_Hw zqf6rPAI=Wf06E`3i=rlTR{9pI$D6_*f#Sc?f9Tzf&NAJDyzgF9S)3Y(m8jaz{Y)*M z#Kv)&NAHK<%l(l~^ji-8Y29|dl&w?yVz}@@VR3ck`*>gaFp@G67QYWNpjN}o-cf` zpgI8W?8HyL6BrMJ>@~7na+V{Y>UgOr;&99hxv^E}K&!Gx>M*IwCg0r$0AYX5rzgEt z%S?P)S8kt97G0jwF>}z0#?AHq!~N9a@3V>epamUsbr?c-&-{M*;1S)o?^4Qc`Xq@Z zFW)G*sU>KK2NTEZ*;nrL64uVXh$*|_AYU^mrG&um*%>0>3D_YNgCAFHMg|=WS-E3FwgfKYpjlnLnd|TPg42vK0t#5 zu%b3eAN_JH7LBT2pU%U^7wv%ft=Fm_8`o$@%)#RfaR&$jHWv1LU!baFYzqG+)ST&% z6SB=J!bGi0gW!k0A!DdL<3H?XfGu>!z{UD?h^zSVhHw#)k0hE>mpkQ49M1F(#SIAF z_LwkH8{Q}z+p9-b0wB^fuBRv;Uqa&ZSF3S!$mpOF?YVZhfR9}Xj@e?0iG9(aC3SI^vn?N* zuL*rY%PmD|(2U-gg)-VSg%Lko>0#@ zHVL7_+0elx*UhA^1X;TnZCMVfkV1MCVYpG`V}Cb>JwAHE&BIa%M+(6qJ+@f^tsuc| zH1HH2)`icy0{huSYe;L-a`u8x$i5p-z0uJ31<+M9{X!I6mo`r z09E^BmtXhzkJV7r-kg$}L}XZ?{r+V0=SslN`-c2zS6JIcWV1g=6MCsrs{^ROu<|9Q0{L@DCezDcWZOjp%9d z7nK2B*X4U8SokqR9UY=9Popj$cqiJ;8YEXJv^DOCqF8_IE zuOlk*;=jgY4Tc_8QDe*bweEKG*=S9Pp^YNJ!5Cxo6bdO2g8{>jMJeE}|Kn-Ng2G_n z6E+KbDk!WzBdJo?!AnPkhRXGaqSRY(7B6{aq}^8pGr&r8gB(jAFDu#YO`{)4%dA}~ zQiV9$f>kUO=zjRzs|dJfpop&Vhn&59sh!dmJ=0}A>fEQ5H^K;8 zZ_?=E+#@B>S6#;BhnW|4 zd0-&Red_P=T>;+ zcMO>XN*;Vcarz?C=}P8Z!U1~)J<9dt1~_gMT?v{PCS-sL>FNq>6mx9R5`Wt4N9E;5 zhEMLTBhwuCKr)GWOgv^gc>kfqYqpyO4V6{J;|1~;$&)?*J9Yc7p@@rI+H+=!G)A+sK4k**7T>a{>Ls@GXd{x;8ZuYTY2761Uw~s6i3_0%z4x898K;oR4Y~E={ ztO`9h-%l)X8I8=T0gH19kg8EKohoFZaxuQo0JV%#JzYIs5U=FGQzu{tsp62!vU$|u zD1TOoLlVRNYVvL((w{(euBbsqqgq`@XT$Fvutyc(atTKQDu#_Z^8Zd8;0s*-A%UO| zlT()~BHhT1E?7QJ=1w%w?i{bO%m?0yjFJNVwE!nkb*2;t&irGZZ(W$`L3^4E#?is3 zQLJPQ%|iWW6zp`%9V6uE0L&h3Pl)vKS5z?m%~uwK53lRBHehNREt6QRk2|xiNP+=I zvSTd3c&y_~9&jE@#ht1DS~As+T0&;KwLl+yK7yQ_5!<@C{01-ObROwr%3fD7&Y%eU zo1Wf-9}%^GD%l5Ag%k2WAGsxTITm9pg?1aO`Mf)w$(E5GQtSbCyEmfyn;0 zXWOy-9~UT;iYC@?Bpyh>$x1C6AefZQr5X1hfDc9b=Jv!9yy%xG+V8L?h!=fo+7up= zs)WpV^QE%3G+44{{%KY49^0D);B(VnsPWy2t*ONtJ&paX)^1{hB6&f$ma2#_TwP># zuUM1;&Ns(Zm{6(9LW3}pmp8sDR|^xiIPR!`Som^c&XJkAxoI0LWx-34cuR;DDG?rj z9nS)_Yp<1z1+w#4y7+5W1YB;>!AUgh8>Rtn27)x3!eYk0#5rn#N_vm!&@a3bGmYGP zOCA}H%Z_;y*-cz1R4g4cbiQBjv?x`=C`ZIFlYMeXTsn%Hk@`x}4wLku^vcDqS{;|& zJ5MqNChoJr>JiM5!<)sbu)+ufPJgtldI59}u5ae%R^6m`HPN4@?)RcfFW&T=TC8TLC!*XX zUO!PH6oG%s|3nUmb9ZpqGJNtrfpzb=cTkQ_Bi=lA5O-UJEiK=5_;APf^$z{-i_K3e zb*yt>_0*oW&eheJBt>Bg-%!pDzseK9>4l4(QxXp1?$pEg0d`SZ%LzU?28oX*}YhO1**`z3CrKqs2 zYDIS;03G-p@ZHJq0qQLXBm^;ub|*t}o&Ec;IE4sH9|@p3@Dq-n=nzv=Hk zJu*hxkXV44ujC519fhb(JPM;TOmo6Pzg{5>;HYo?cf6=^%*if%haM9dJfv1lneCf! z($)DrB{o=4<03sBjKN0fxbP+NKICHwgr7MwxkX^bi-c(8lS&D30 z&v$GI{W`2ig3QZ+K3IadgMb?)7lNOL0_bhy`c|@C4PDsu_sapjtxaS-ptt?J9;klt zIR}55mGQZ@@fe+u2+KCE5@w}c{-9K}>hHA~^edHnc8;G|tSEa#a4NQv%%mrq&4&`; zHjfM2l|RjgZOO&~w+@Z_|11ndsm_YgAl( z?S@<>3q<373h)oDtPGnpOQf&j+%k8ro^TdqNT6^?$1Hzj{UG^4L4<>7&oz87l6_2A zMC_NV|Ao(2DIOo`2qR=m^ZQ49K2#~Ly2?tgkNGYZbotLDotVh#h?j*gm6ZyVv<5lL zTOOrQ{d;N#8Zm-y7k1E3EbnNou} zcK@SVs@Hir`|W5|&Qr|;01_r7B$CA7+(*64%kz1!fkH@K`p%8ys#Wlp$t(&eC~h?IPLj=Ar%hr>o@ z!6l?LZ5zt1-7+V2!uD}8$8Zr`4W)G3(^FtnIG}91J9Opl|H<|5-Hwt#wpAs>eql+2 zx-3!^yv0)S1=+2-iI%*}s&Aj{+WDv?<}+P9s&`c@c3MAVQT73;Vz07v!oyL4(~!>| zLeaW-gTp?;gy9WV0a{nM4k^oapCqTE{%{l7Z!F_D|K>#YIv7A((Gj6{d>+<=}x73Jua)`8<*IG zQ`hWh8G=Mr>NLBPj&7d+&c4TjhacaR-hXFUU3C=tiX{(4E_2z!pz%YOuo_Wk!NjzV zwoi6;Q&g}ZoZ;{#hnORt2)?do1t~S$p-AJlTk^?#S+HtYT1+AvNA|^=ZZ5%IMZ}&F zb{X@jnHGK0Aci=^bxP&&M| zwB3oA@as;5noU>C^_$$h;n#tv-D5EaEkQn)2kigXAz!oyM4#ok$C6Ny+Jyd#;b zdbM*QZ01J||DB7e&Ov6hS#*E3e00UtyeAjzx$x9a{Cx4!cI6i{w1cN7JK;!QWGQ9~ ze`xp4iSR2k2l{biTujfr%#)|~d^^HWrp7a|cRsz$LHQOMiwZAP%VrKX{`ZlXr#njqV24O!UW_o4I}KVWb>s;&Vh^4YyVOBp z5@et1LU+*#e?nN}3Q^B%fE3x13`J|AN<&OG(IMc|fe`uqDIA&xo;3$-9# zE)DxYgLtTw--|h9Gete~ z$T;6>mT^sq( z$-NdqBR1NO9~>L@#;X~w6_rf^2@htFWIoc>)a&s03_wZBl(3t9mUn-tD)7{cdWV-* zOkt?wHtwlYh?F_mY686J8&VU?Ls9rCsVCv(tSQ6)Q`@CwkFu&rxZd*{^&q>@V>9qB zHb8&#^ddh|wWAINIt@>FYh)x}kAQKU++yN_KiG`>X0KGcI2q68{cn9|!ZE6! z1k^YEk|M*AK9N3Msne8~^1ePz$b5$N>#p!+U>+s%W@=9VVr2YCzDf0acQDS8#|o>y{0 z-Mb;j{0N@t-mCCq5_w$E(9Js=EfM$-Zy|T@$jxHH-RWt+Kx{UvRNAjY(WT{sr@&<@ zU`9Gizb1W6I#(qH=(U!Wk^JPvL@;Pf!n2FK`UnWeT~&Cq7U(f0vqZOg2I;ocVlyXs z5QRn`Uq?;hgtErB$IR(wtCZ0y%Pl0xkK*)hzc+qsm9!| z9?6>aW%PiC9JJlkCk$ED0|Q43%ifmAa^zb?4<}}x97F=EYqSB&z`orIH@zsRm_De$~g z@cgP4e`_R#oo>~mf~Mp^(wxYgI94O6$qgzN)1}^D>V!auw#v&7b{|lF!W~e>c(Tvt z5;9&pd0{3qf3}~?8{hTSbw}FLjlHUHVaA@_5{5G*)WF3ruaa(&c=#Pv$6k}|>;uSj z%`k8BfCfh<7c;I{_U4GmUIRbNBUoyb+_oC5WBE}_USI<+AJY?kRJ)n7Zf%j*QZALD<#y^&2Zvv0F-mb_7jikT=P4f2Z%J zbwusZl%gSmy*mbKkhbh759%s2Vg@ZJ{H4xOPmZK|VnIs4Nysz%1+~9rvkmDt#^V{D z&c414OjC>$ksdtiKYXCP*G)a1XSMAQ_19k+>qn4IETop*e+mags0^aR)(ZReUL-R7 zV6k!63kT0V(*S~H@#mgBH*9Day8u#7%1>{x*LubWxFK!$#z9PKD7x}N4pN3V+X^K| zovkf4=Y9)=vqtRg@q~#?k;*bM_1Q|5D_wX5_Iwtd8yanfig^Wvz!ybYZ9BZ>(&5~= zdRwVX^~B&=g=YgxyB87LA4;ES>8LHzRI2(r(}2U)Cmm}&l2>GwFLrW@W&XW!(4gXj zx~h1e!*U5D-kzQ21oGYqIOOaJVL%$+@#+q>Ctib4AaBYrF9jS5dXvsx%{fQe60gnl zzJ+nC`!O@eL^i>B12vtFz71+DIp1~->Q$(KsT`fO@TpV8;zQ%5B2<8e4HUXVXcf zTZ1uAHeL1_)}(fqA!=}assY;bJ~gzF9<^B^9@!<$?LauJLsY%oSRB}f4<=g;$n_z) zS$AhetZ9qU5^9U8BU$2LkLfa~RKV51GIfB$EQN3d-G1B6NB$4>W|NI?tkXp72*fWJ z2KX(ymA~Rv-8TK%-L)CbK?Y0?3iB=Ae63fTlTv&EK%)S^%X(SOT24@n+1jf#v8y5a zSmM{%B7T9smj^m6b^gH~wV$GYnA$wZq-@a~7AklX?yy0g#Zq&tb)H53NC6+dSM<}T z4?Hdpp+l%{4H=kr-MPoLPbA`WIRGVP*z;BQhA;ZCUVjZdl=^XLYK)f}V=7cY{X%|8 z;pHT=;{W_;`xq~Q&-Aari8}NVTin@?Jk5$lKW_n+Ua`6m7daL|piVlXg^1@>_mzLQ znk4{&C`b&)M1IoP6nk?l-@lMdc6Cbj|E6%7yxMwDIHkxP&E^NYh)}=_KZSR1*akv1 z$>50=RzCld}EVqseP`q1b$lb*hu1b=f@_GE1*iu=}tNcny`L>HZwpfG~Ig@vSh zJWkP-|yhr^dm**g>`w-m6iNT1CLE~e+ z=eGGJ*qg((0VdMufw!tQ7Ru{ML{%YJI&<~2k$2BtBoe%!{&$s>8a?@s9*R5v|5p!H zWeIVnv~7_rXq(NLB3$+ViNt{9a(mj=QgHUONRd+l!u(Sc9?WAAImLU)w0< z<)LLq3TtU z@y`7>QO6wD;ajffqtc#%f=+^o6c1{sWYA>`y>Pjk)bgd$inETs(K0|?Uf*4o=K!*( z$8qQdr$Dl_r>)ewQosN`M3I={NxrF+bR9$K6>1;DqUsNhAQ?gwl64`7C&bGiC|5Q& zd4f)?V0ObSyQZafi+6so$j2{hT~;>V}E=7k~u9)V}VEVSg1oW!r3fLMW&(q_zDl+9j;bg&qZ#p?DRiuk;T>$Bpx z9bHfLIgYauh|_ziu@cu*+B4gvWltAJ?=>sF; zI1SW9N2 z2Wx_Dx+@hE<6H^P0~Agk8iaX8o~i0a1la#_F@Ah!yxa)$Cs6CAbc85KHYOxNe;J!Y zf&f+N+LVZBW~#s zDOm_8-`gBSd4PY!$F?08%9b^P1n%`8j>}nYM;&WBbJixG%kKBQyA*y04;y$ey`wLK@XyAZ0Qt8qG$J@S- zoT1++VoT;`eggIwyerl&H_eX}Q_u%UiT~>bY=;S8oOd2!HtKe{LR6KRa-s;jfs8i8 z$mOm>)(jJ7&`8Hf@Ii~YOeLlg$q$wjEp*Txqz4{e`?EL6N@gnYFH480)LN_<9@gZL zrhTA!yXYGYt4El)u?~1~EcLI*V>5605bQnPFkY65tb*^?Im7{>duX3~u7^n|GM265 zpX?@CQUtsVqJv({qQ#ous%eS3O5J~V{@WsDgOApZZ|t?Aqu+4U4~Th~w10VhrSVxC z@&uFJQ>fWYk6?5wjtqF(}0$CqcPzMz@!;V09zot%qGBkrqf zu;2^A0{@RqR|?W`NF}I(A4`j%j`t$B2W{DCQ%F9LP8Qk+m8i{Z+Pg-&*Qi&t;-`DK zUzyl$4O_evNACbhq_i^;yyN0q%*#O~(iC<~@>9DjddBPovFf1M3U(B>wwA4|n;)`9 z&wm%e37_ASNhYYL&YaY^<%x)awq*MoNz%m{Q$$QJDP1t69_ zHDpAfWr+0!x*SBzzXJ!tlG$viU@vbyK5^0x_B>-KgY}@HsIid}V|@AWiLTnAC878I z_Bb}8EjXrE70dKSuYX-BI;SxltjO3oEH3YnG-f@MX8qhhg4M*Za0t+0ifS#tSpfbz z|2EdK=3R4tck`*-#Lu~EDm3Z&yls(m$Dd=83wIVA!2ewU2+5xL-461NOe{*?I8@(E z)Oa+Ecp5%dW0i1oGQnJRZ(s7_%(;Msg6;vE(`fIa2Y%g7G1BKDEx}~`TcR3gx0f`R zPiCM+D(R~6Cccpu^RA>ylwmL>as9WXcva8aakIrrhC2B@cy^_lH zbo@%6G0S6B;m%g7e`os@#%G0&O=2XXq0YRMtNB7ogap5kPAT!OTm8kt|1}-(mHPeiU{uu+7nAtCkDxwyg~}#&2knM0j5V?N{Vt+z>QxiC`KFucA#zE zd+`YnuhOPC zOY4LSjspO{P|?wOQrxet0SF#bl|uzTekY8>@d?Nz`uz6Rt}$0;j)dN1p|HNlqP{T} z)#vn!Cs-~hiEf=ds1Yp2$>6p0Uopq84bLJ!ur+)aesh6hwijT5xUxF3sOYkGF#UuCUFqle%UoXv ztL}&-7E>%)Z2U-GcEGJ}sD$p5#pPa>$kG_mEEF-9==Q{Y!zC3X_ai` z5piKsoA$PocS!ma>dZ{=*@L#q0*)xL&QyAcHUP^>RhYMxt~kE`tQ;qmSnH*1Xm~$J zUY~2I@guK&2;y}-ZZ7%~ZW2ejJ6_=Gbm!r>^qMGC|1|=wGUuNXK`3uFX@Ij#-YT0zmLwGo2hhPk#M>K_eUX_Xo&Ynnn_z8saH-H~>2 zk_t=ez_^9s-si~O+Puy%eV$gM2e{sDygi-vO>jfj+pN|wt{pv}U`T+WNKEi=JT|OQh`!XoJkP& z=$}tPKNxrplZlZ%$Y|4^P<2|9?+Q8Ky!WbkdQ=!XRO7M#^79YbJ7o>M0-|_&^FAQ@ z$HH>zK4G~tkA7s&0`sb~-Y~SAG?kQd!t=#u&m#zP`1-p=z!&Ur9J9FE^1q%Vx~WO+ zi6_>ezl_fdTcfh9qXNs#Y)9o|CvHF`1D(&oRWf_}P(M29-_VAiwv-4BiD!R@-NAWZ z@ZR?tv-wV8Dwd~C0+4|k3aIRey5Z{q%O>8&AOr{{fGa4wKFr_q_?tF~PoDXG_<|1p zUV6ZuPsG_*({wb*m_G%z%?nNX`fv4z6i0e_Ya$roBP<-xE>{q}VVsB6q@EnCuvOGd z(L#%G_0ZKPL!{}-6+m@z5nGnHJjf9j?oT|ID;QK}Bs$R>+nMe@`03bUM;GEVn)S@A zz<;@|HFZywk7e=shn_m@xf)v%hxwM&55*IU=^_ci1j{*lCmmjIZ%+~ zqm50Dy`ZjN*7Li;iBNnh8E-lo+!?EGt8<7T-$koe-Y>M#o6A2Wlw2d}&Gf=`lLYab z*d-+6(p6F-Z}*zlGnFd+571!pI_Uk(;-t*Tzcd*q!bUx%D)TTl6?5_~5;z%iObq)_~0hn6CvFZIunGO+_0OpdME<~! zK3&PmNcbtpqx!j89RykFoT8Cof>w>g6dhG}z8y)T8;7@SGv1*o3h^7RQWeBas=BK1 z&C-x)=qB3&vFRt?9doPzuJbC58+cUP{5}X!=Pdp17*bXS1{{Wi$UiPab$C?yv{c$< zi6=G$QB`7AC%rrbrFv4Ce77wTtMg`|l3j4`3JLsMIJD(y#0nX zf*@=c*RceT)he+I*H(Xz;}j!L8p^jgV&{{PIj2ZK-;=dZ*B*RUNcj}5-s{A-*2`yl z1fv1tpto`aT%WyLX>?h$Wb}L=htuSb+wNGj-|9jVaw4+2{6_ixYcn7E-6EOtpbFNm zOK~zqLTMQW-pp5pJjs-e+cY(=^` zuQ&&xbK^nmVk_t9Zh#b}Z*C|6DxXh62)D3A<*H(-@;CiYkViWvwa^5t)cZ;k1Md1>7mw+foEWacLstMAMA{-l?o}gAmikqUoXj5^Nw*Q_ z)kor}Q1QiF3{KK=zvOm(922m!phiWTE*C@~4Ak#PoUO;-k^A}_??St@OBS3>M5V7}Ij85D~h*HEwH|^!Q|1TUQlJ%Y$EE2sDOIK#s74=P4 zW1Z1&3c4@hUyscU_#`sO4n{apae{bV68r!N&1AicNQ6CkSdrb+bV(D>ZBN1Q6&oeI z{{<7vmUD#mm6s)RbiyA;q6&mEM*9OV35d$(P3oR_7i^_5CjQ25%$5%ifIu4SJJ)wXD0kbf5( zmkjRj^5!}RCHz&Wy&`=A>Iqw!HW<+mNO|SF!mW$jk&k%+k#ZJcD&;?-o-u6>vni=x zTz-;-wBll9tN{~U>XH7!xq4bUL`pT7A-Mq?sqC0vf}=ynO^^NO9T!rL&P(E#l@>g^ zquwP|@(4*~iMU3StuMQdXt*s24cENQ7DOMiQxLiHU~84!*!S#Q2OEp~_UzA$r||j` zy+!gO`YObE&x`r!H31oPG*0%1_RjS59jY@(9w?4Y{$3_abCsnwpj(<#lzmsv=w$3; z(HFOo>j>_Cim4XJrN@fIAQNj*Nxq4lFjZ!K!TIJ9`^Px@hnUdv3@`XuQ4G68bb%UK zK$h34#v~+wu7|aaoHnem7cq(c98O-zAzb1o$ep2+HMEGl7b;)9zS`$r$Ma#`>3VKa zvLX(R&hO}{Q9vh++rn|t`1#DT>b?I#fnHpDP8*2i_K(TPm}TBX&a=>_c>zwqv^a=!v`jGm#khTSZ-Hu{Ti zFm69(gfU7$(6Min%Woqn|)o1oemmW5Klxl$6RU@-a7d3--wdS$_|Wr*P)w z7jDcd+P1BC*)7I~bA`<)pC7K?Q#|mkx<}s#TyyE4P!CRvY2XLu2em zEqL569ITmy7dwgT&(9_do}{vZ7+fbZmAWkp+Z7uMHx55N^8O)|qjTNOY-8&m(;zn^1A$-g^4 ze}4nc`$Q;2pjw&DMjlvl@#uTXnDLc{G;=th(%HR$PUm;j_J7_hrCe%Z@5#~FD-!AU ztO;4d=w=dDaaQ4uH#*fb*k+d6LnK&K5aaoPJHin<>mJWW)LRU(uXrmCSGROffb0eP zR1=*BE3gCJ+T}8<-_qBiaRbLz1Lu2P6K`=W2D=C0hwok`RqJs#bj9Nq5v!1m6~&8R z^X?>B_1^I4`*KbA{M;kl+7mNQ~lWyf_SsNz(&7EYxa*P4z%riLC@k_;P#FK ztCgs@xTIfGfs~2IEx-kT1BK~~%_-%fez;=*J)lKaywvG;4Gwio5>TJlq^ zo;fled_Q2Z1%9_anpcJ;SxpxW->HNXUhcgN-L+QxhR;{X?-ONW^hV$o0~4e3sQw#?d(ed%}D%p2D4hmmsgFF>Ygx%V zvqSG(PdAzFz~Am$^62I3=BiAoe&5m4J;3_Br%D7|D)}2>JQ_Iwfa8g2m1OO|G3m5X z93(hIT{RIs4RF8i;mkN`)uz7At{7*7&EUTP6hfn}nGcnllz?%{799_Lg?WNK zSh2_Cc=|T*XN~vDr9byI7+e5!08j+`x5g=mE5ju6ypLHTdtu zUyi5sjgUI#k)8`53GezZq-sz7^sI0gWAtQZ!D%}1XLC(cpJ!v5zv&* zycC%?zqEFa9_=##taQXK|9y(yfS4Je6C~u#c^zCIWk)m&M?aVwbY!2Ac5U-S7sR?B zZLzgcJPC#`NY?P)iS1=uA%K7@MHl~p+ zme3syP4}P^$N(JNy9=IxoamqFMAi)o z>hNvEzKz8u&~TRYmOPmRt?6eXr>>T)tl)Gg9TS$Ow7C@K*_Xy25`;#HN7D(OJ7vuv zz_#_g>Mc|O_jsSaU~|ZdYJ2rf**9JbkD|30(YR0o8e%3Dw<>xHsSTXZ1zmQuf{$M_ z9&<>NXXl=kTHetf=z%&p)9L@X2F?2v}cFr^PAiQ`ATj~zPX{br^10{tgu-L53W z?76_ROcP4Z=!ig->a~)Ei4D_Mf4*zr!O%VW4)ylj1#K6-b|@=iR+D@^kcD_o7BTYE z`P~BKW4(W581sPo^j-z7z%v7>;E}eVVjseq9!-`50nJ5g1=-xd&3n{vOk7;Png<;CtXSGS^4H*q~|^3g3fg{NR$BA~e*9>HcL1 zrL*)0^v-S%dS}VEI7eiGHvJ2vAe1|86iE}Qj3TcBl#AsI5@T}ZaZ^k5SSB1aD7{~m zz@;-1@m!NpS-V)$q`LRG6sr>-+l%+yb2``vmYm_CS3J1=$tYW<0qZ^X=44$09SOmb zga{BiNK69r(l3dj$UXbmm*9?c?!_CMI)-ss=qjtdgj$#iLb*ET=0uk(KP_!ns!%~^ zG;OY-GK<#xtPhq8U_Vs7m^)J^FWJh2M}6c=?%rXSc{I80kcy>EL?@A7-yYsmGtu#% z9gF*3u$99O<)(C=q(Mx1ZSFY})(C<0k*g9+RPP*}lDFs>Ba!6XxWxo`%6P_I`CfZ= zWTgk(2Z(t)t%#WV;Qd;G+R5^O!yGU}rYh#mWVH??_e}jvb+#@s0X8m+cvgyo&fPE! zNJuqjW8CSbeXvY8iT87-QD%CUKO=t#V;T;9=lrCSLpQG-xx6Xqn${P?ow|*1sAbpg4DZUp6B@+h45S#|3T&0-DE$$$*s?dHSWvn5)$!|DxH zfb74%w>sq8B3Fe}+=Lvh`~cOJeFyL9c|ZCOsi03xVaLbAxp4Zv2W2JFd5|fk_bu+z z2x3Aw*}VNo+|Q&AfqNBoI?JYGzvC56&W^+z+BMy%Y+`t$azi8(lXlpIzMdgmF| z&9T{l=@}qELZ{xgrP%X>9j7mUTc;QLkYctPNa(aa11;`VRnD0tl1@+Ye`dvHUb{O=6GpvfR1rMU`^oRz$U(W5~X{gy`;c5?c4@3u1KkHO6~M(WxW^ zw>cCOGK(gx{s?q|n4|S04kZa>d*Ml zh}-_$v*Bo2AYid5L+$jimG}DF>j5}Fim|+@|7%$p`o&64{OkUyAtmAj%1RQlRAW?| zqEirs7Y{!f$X%tx$eP@PMvy;YV=P6~v7^U@Zt-si;r3@n!1aDu2jywn8^^8Vuyx+? z9Ql^nKV>-&gI5hW;A-SYW36ee($cgdK4N(UCm$Dl^0mVU?KARC@qK2ypCC z*o86d;`r)EFrNL@V6I7OBAxAur#DzrKpjuL)j1=PPCD92FYj>@Xsr`V7mO&g+td(hlzfc55CLQwz`Eh?|d0nKnQH*lA zPhD&GcFE$TU1IC|Zu`>>U5VacjJ&nAGPJ@0W?Oo0ob_Z+ob@336cZn4*FYT7HMMd9 zl9hA@tLgi&_uuR1jYhze=~kUe7czd26mIw6N|)zaCIo|#x5bo7Qy%%+MP=Gk)pS#5 zG#M1{XR?sr++E}LmvJbXPH|_+@;NpKj=N{F>-f1*3Pit*k*L_A>61ggrWtO?cww}+ zF8?(9+Z4B$G`^j#x=J~+c0E+D-)+}wKmKH&p_Z%p@KEf2XyEZ^sHZW({CJi0%crr$ zKX8YAhp6stYya$llelI541?UBJ9rG$)@vFWVWz1Ix@QX?(?3ME7NFxk7HAgVpUR67 z0#bnwF^S#(d#iIIp)Mc>M9PL0<_?~9k%=oC*jACxm{a5Fj$8cdIIYp(W^fMj_FOXsy080ji}J{SD?;n(!C8gyNllyeR?rXCeD{dn<) zc~6b!^8~?N{so(vl*J1vUQh<<>0WK4E)cb&_SIDK>oWYgso<#Hr)AG03y&GsBV4rS zNA=QLW&v6A9e%zI32_)>cIeUo>=cObKxr>~-`)>?P0*{VwC!(Ch{|S0?`sK}@{LEr zBF1u3U1*l7ti9{*rC7$bMXd&FR+z{G>eWy7iFyf~M890mzH73FeoP$s z+iXMzaMrfkGXC`4>iW!?t)fi2ofB{y<~R{LH^El_f!#7PM#Z%d6YA#j%Y9*iE}+OO z`X1MW@a|e=((+JtUtyxMizyzfgp{jCL9)yo*Les1p+ z-4V4FS+3MEX;fS;`RbJywcM8Bz5Qnsw+l?i0D=TX45hOa?%!gpviCmX}^$xX)0|(8zbpBp8*OwmjQnIug@ijQZD%nt39UB0DzejQ)>@gE~Md+Puf-pz> z)sYJmc>vkN1EL#5cQs#NoC^C!d9a|6zFb!}QEpIZBs&RqQz zTCOx6NfWrVXilz)y?NMO;ri)M)Y1k0Bj@$&CRGy_Kv4IyPP)4UtKl@p;J1JCuA^~M z-p(Yxzj8$0Qke2k1)uqyOLDmh_#n`r%3_3;{k%WgEx(d>eF14Xsd9l3sf@m6+*`Wu zS;KlbRCNWTMETu|eS&OV5QxrJ>S8ftf#iU_`|SOUW-5 zeY6VU@vPWjLbkV-rX9J^Lo%E%7zp>1pl@c*6W{^b5;nb??f{h2_gPY-<;@4D*t<=a zxiudBxHV^ezP6oF>~sUQcYu~Qz#g&%L=udSDX8S%p>AtQxC_?Yr%j?Iwa!9 z=E{byagptWM9w3|P(XAZHJ5n+xi6!C^uqsIS---GR~*PPtpVL)JaPK_s005*?#>$x zrib^-)SZNe>*kK}UOwY-enGM~9J_xL9{CkFO48B4ubv#AQIe8Ica^oOpl3`jrH8?P zx(L`_=8@yk*)b(uoSEYbPaOYRgOM?y6Hf8webKln-kt5@GqjA;SqgQH3a(dUbnRUu z_`%*ND3*z%eC3u*qdt*ssD$zKp&?m)eMSX$eYg{ygt9lu+r$8!z6T8%!E)n{= zc#JM)!o^aB8DnO^-39?cRSPPQr|t)m5}dtaB(Wq`H2ZKmUxpXRx8p2~;-567-qYA^ zkkE|FP1D*~;U!NonkN!+B+$K>89I~S#hGvaJl1i#*rPR~28w-o@Ul>`2QJ_q4#l}D zU7HY|vPl<+mJ8C=naDp~S@T`=Eg#EM2vE9}IIs1p$`PXlt|)r1QvW|9X#s~S2}ac| zi-=)&qWeKUNjl$q0Ba!s3xU6iNHkcu0P=<1?$C8dfpBFRpr>3I$gg1cGD)YR3SI-! zewB#-A&!kOXFT-%B_cT~DdTV~78x|oMuNiS)-ycoFD zUlF2ylK_Wfuj}p^^0gPF^~UI6g`k1Jc0HU}M@=X4!@bKN>5+%)P+NX@Yx9&Xn%y9K zkB{aWE$!Fty#5}2<(1M9a_eWdA=#j?|-*9icqfy`q zHrkfM6Xp`DMg=U1(Ac#r{&fJ=f}J`#xWv)JWxvZHnTWj2^98Miqm0BXKd(jg;8J`q zFdqY#XwoL1c z4oH#=Kb`Kr!7P6;U#QkVbd9aOGk(B!KH&GQEV11$-YuMP*0yFBnNcX zH=Xenzx?crZ)#wZ5aqx^V@-_jRLB7|ZD-ZM+R&MeZ^X_cWyIWxJ>LlqW9NoDr|`2K z4sZe;;2f;jaJ7!Q$e`@zz?U&1Oc$Uskod+-83T7>p>i_qy5(MbRdyefP+Gp;w|Mjr zzg4sJWbQlySp|bbopV}>UbLS;$K~U5wE>*gfb$=d?%AE+w|;AV@BA7&e5>i6Y130( zUi4%pd+hxoxGoBiK70WTMXxA%a=5?HipO<-p_1KkOY>VU>Ld{T`qHEL8!lIadF1?s ze+*aCw&BYaxLVT3u+;?~_g&wIG~)3EZ(N%Wggk&3`#kac=Uhn&jOI=yy9M(8tpWE> z7U2G&yfHNId3|ddRW4OG_?7U+3=xGn&wG)af8{tYSG@}SG=PG)@dXZt-_aeQ$o*(< z_}`#tp&t)p)c z=C0O9XyCV57;(hd1^fMR2O6e&_P%&*Q+^*4s7@HN&FoTA9qQa3Wk(qHp;~c7RlQny z9s2Z-x5rnLu8fGv7J43$Bht47Y~-n(PmzV0)hdP!okcR`Ie=vjpZX>x)+^KuxJ&#>h`-G(m;Dk z)ZKH25^Gl~K$G}SY9>Ha%i29sFwPFJ z!V3jF;C-Sw9L5y>_DiTr)kB~LreQTi>NpXIi=@{miRvBRa|VpbR4KwK{+Iz-t>tWG z`)cinIA{1#DCP^{YNcQ}{lbCS3YR z{lfdl=wsv(tagoe6+^jeT;D7X$xcM{Z&#N)nWT@5>z>w`6wBmEku5-6r#>S_i|@sy z{iAPO2F2bDP~*c_JvnGg(o(vhJf}2i=kbw0CcfX=^a>q*b||M2t}$A|ed+9U=y*@W zg2VqJvG^5->7_>O%x^$WYCD{P{(q=?%c!XSuxpquX#|l5QBX>xyF-zX?(Rl9W`>lK zknToGy1To(8>AbC7zUo>{XYNuS?})yXV!dT%{k|aeeG-SPYeIGgQcjCbiO4w>~p>H zGyk@P^qz8czmV5HHvZ(_tX*^35L1(yR8A&1P ze*8sdEl{{XJ)MXYB^u5P1NB>~jh&KZ zE1nNCGH7+F2_v=oJj@1POAH>#0Z{g9H7rJ_e#xtJH>T-W;FoG8-iLY752-kW_)8Rg z)7~_$vPxtTl$#h+gGoTir&tL7z> z(vAV6QWi_TRQM0N-h7V>dRa##6ih#S_uJvsU3;@9nECCf&si#uxBI58^VzF}<;7&r zb#hM!cj0?@7g_U)@Xh*X>eTD-gJYFow9y&GPcZIk2Q{Ni{>PFkKx8`4fW6b!3G2Jw zMh^-WHrYvDr<@TlHR*QF$)c|*g61=S3;?F;;oI+hJ=)Q6KaiZshEw8l4q-#jP;_PR}AgN zCkV1-$bNQmme{tmZG`Z2^A-DE?)I;Czxa^uq51HoA1TDmXWhLllg~>sB{lQ6m)`Na z@&>KJy|)JWK6TfjslVpin8MJGRdY>39W+as_gs(t${66;eS4-?c$u@qjZxBXcz5GW z;>J;C$8mU8mS}GM_lNz^e=0uX%f543w!3w3*U1D!iGM3TqXGM<$INH->-vmr>p$9` zP9m-AzkT}_Y9xVfG(l6|1<-zl+5M1^|2xkC^@&9cl-o0jGH??Y>O;jlG{_ zgUrzP9I_N2(iQ1Dti*`Y5JfmXbHmae7zqqTUK̈́<@Ban(O?qEGIA+cTDk3VGX& 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%0Ay8*O9yVvawyo6JYwIH~{`?FYl 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�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

      jfAJ=gty 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 Date: Mon, 6 Sep 2021 20:19:31 +0200 Subject: [PATCH 0789/1182] Cleanup --- README.md | 2 +- docs/README.md | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index cf78466671..fef370ab4f 100644 --- a/README.md +++ b/README.md @@ -81,4 +81,4 @@ $ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/com Have a look through existing [Issues](https://github.com/httpie/httpie/issues) and [Pull Requests](https://github.com/httpie/httpie/pulls) that you could help with. If you'd like to request a feature or report a bug, please [create a GitHub Issue](https://github.com/httpie/httpie/issues) using one of the templates provided. -[See full contribution guide →](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md) +[See contribution guide →](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md) diff --git a/docs/README.md b/docs/README.md index 010fa570bd..8d0c555054 100644 --- a/docs/README.md +++ b/docs/README.md @@ -116,12 +116,6 @@ Python version 3.6 or greater is required. 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. -

      - -[![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%2373DC8C&label=Build&logo=github)](https://github.com/httpie/httpie/actions) - -
      - You can install it on Linux, macOS or Windows with `pip`: ```bash From 60a7ed4e7b5a688e2df1ff1ef307388141036a00 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 6 Sep 2021 20:21:09 +0200 Subject: [PATCH 0790/1182] Cleanup --- docs/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/README.md b/docs/README.md index 8d0c555054..d1329faa8b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,7 @@
      + # HTTPie Documentation +
      HTTPie (pronounced _aitch-tee-tee-pie_) is a command-line HTTP client. @@ -9,6 +11,7 @@ The `http` & `https` commands allow for creating and sending arbitrary HTTP requ They use simple and natural syntax and provide formatted and colorized output.
      + ## About this document This documentation is best viewed at [httpie.io/docs](https://httpie.org/docs). From 778360cde18af224f66f831506a7496d796519f0 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 6 Sep 2021 20:21:49 +0200 Subject: [PATCH 0791/1182] Cleanup --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fef370ab4f..58c8f7be59 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ They use simple and natural syntax and provide formatted and colorized output. ## Getting started -- [Installation instructions →](https://httpie.io/docs#installation) - [Full documentation →](https://httpie.io/docs) +- [Installation instructions →](https://httpie.io/docs#installation) ## Features From 9764cc74a4fb126a8626a7dc025b5f66104b46ee Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 6 Sep 2021 20:23:00 +0200 Subject: [PATCH 0792/1182] Cleanup --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58c8f7be59..fef370ab4f 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ They use simple and natural syntax and provide formatted and colorized output. ## Getting started -- [Full documentation →](https://httpie.io/docs) - [Installation instructions →](https://httpie.io/docs#installation) +- [Full documentation →](https://httpie.io/docs) ## Features From 4eaa4d67c5586ede82ceb1d5710989f693b1f343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 6 Sep 2021 20:23:14 +0200 Subject: [PATCH 0793/1182] v2.5.0 (#1140) [skip ci] --- CHANGELOG.md | 2 +- docs/README.md | 2 +- httpie/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 850784ddc3..f53c6b1a14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). -## [2.5.0-dev](https://github.com/httpie/httpie/compare/2.4.0...master) (unreleased) +## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06) - Added `--raw` to allow specifying the raw request body without extra processing as an alternative to `stdin`. ([#534](https://github.com/httpie/httpie/issues/534)) diff --git a/docs/README.md b/docs/README.md index d1329faa8b..e5b53a8da7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -136,7 +136,7 @@ Verify that now you have the [current development version identifier](https://gi ```bash $ http --version -# 2.5.0-dev +# 2.5.0 ``` ## Usage diff --git a/httpie/__init__.py b/httpie/__init__.py index 3cb9aa38a4..4b0a7e4fe2 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '2.5.0.dev0' +__version__ = '2.5.0' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 1ef127c61dc0ee4e7462b0c1705c05e84eab4e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 7 Sep 2021 10:46:22 +0200 Subject: [PATCH 0794/1182] Packit: Get the current Fedora Rawhide specfile Using the fork is not needed anymore, since Rawhide was updated to 2.5.0 and no longer has patches. --- .packit.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.packit.yaml b/.packit.yaml index c46f0311df..4dfdb1a5a0 100644 --- a/.packit.yaml +++ b/.packit.yaml @@ -2,10 +2,8 @@ # https://packit.dev/docs/configuration/ specfile_path: httpie.spec actions: - # the current Fedora Rawhide specfile has some patches - # so we get it from @hroncok's (= churchyard in Fedora) fork for now - # once we have a new release, we'll use: https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec - post-upstream-clone: "wget https://src.fedoraproject.org/fork/churchyard/rpms/httpie/raw/packit/f/httpie.spec -O httpie.spec" + # get the current Fedora Rawhide specfile: + post-upstream-clone: "wget https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec -O httpie.spec" jobs: - job: copr_build trigger: pull_request From cf21790411c8475e9ce496224101a55d19e00de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Fri, 2 Jul 2021 17:03:23 +0200 Subject: [PATCH 0795/1182] Add the Snap build file for general Linux packaging Based on the work of @elopio and @chipaca. - Added support for the `snapd` protocol URL. - Packaged Unix socket transport plugin. --- docs/README.md | 70 +++++++++++++++++--------------- snapcraft.yaml | 108 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 32 deletions(-) create mode 100644 snapcraft.yaml diff --git a/docs/README.md b/docs/README.md index e5b53a8da7..7bf962aa2c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -57,7 +57,13 @@ $ port install httpie ### Linux -Most Linux distributions provide a package that can be installed using the +HTTPie is available on the [Snap Store](https://snapcraft.io/httpie): + +```bash +$ snap install httpie +``` + +And most Linux distributions provide a package that can be installed using the system package manager, for example: ```bash @@ -351,12 +357,12 @@ There are a few different *request item* types that provide a convenient mechani They are key/value pairs specified after the URL. All have in common that they become part of the actual request that is sent and that their type is distinguished only by the separator used: `:`, `=`, `:=`, `==`, `@`, `=@`, and `:=@`. The ones with an `@` expect a file path as value. -| Item Type | Description | +| Item Type | Description | | -----------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| HTTP Headers `Name:Value` | Arbitrary HTTP header, e.g. `X-API-Token:123` | -| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. | -| Data Fields `field=value`, `field=@file.txt` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) | -| Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:=[1,2,3]` (note the quotes) | +| HTTP Headers `Name:Value` | Arbitrary HTTP header, e.g. `X-API-Token:123` | +| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. | +| Data Fields `field=value`, `field=@file.txt` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) | +| Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:=[1,2,3]` (note the quotes) | | File upload fields `field@/dir/file`, `field@file;type=mime` | Only available with `--form`, `-f` and `--multipart`. For example `screenshot@~/Pictures/img.png`, or `'cv@cv.txt;type=text/markdown'`. With `--form`, the presence of a file field results in a `--multipart` request | Note that the structured data fields aren’t the only way to specify request data: @@ -411,10 +417,10 @@ Host: pie.dev If your command includes some data [request items](#request-items), they are serialized as a JSON object by default. HTTPie also automatically sets the following headers, both of which can be overwritten: -| Header | Value | +| Header | Value | | -------------: | ----------------------------- | | `Content-Type` | `application/json` | -| `Accept` | `application/json, */*;q=0.5` | +| `Accept` | `application/json, */*;q=0.5` | ### Explicit JSON @@ -717,9 +723,9 @@ the [sessions](#sessions) feature. The currently supported authentication schemes are Basic and Digest (see [auth plugins](#auth-plugins) for more). There are two flags that control authentication: -| Flag | Arguments | +| Flag | Arguments | | ----------------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--auth, -a` | Pass a `username:password` pair as the argument. Or, if you only specify a username (`-a username`), you’ll be prompted for the password before the request is sent. To send an empty password, pass `username:`. The `username:password@hostname` URL syntax is supported as well (but credentials passed via `-a` have higher priority) | +| `--auth, -a` | Pass a `username:password` pair as the argument. Or, if you only specify a username (`-a username`), you’ll be prompted for the password before the request is sent. To send an empty password, pass `username:`. The `username:password@hostname` URL syntax is supported as well (but credentials passed via `-a` have higher priority) | | `--auth-type, -A` | Specify the auth mechanism. Possible values are `basic`, `digest`, or the name of any [auth plugins](#auth-plugins) you have installed. The default value is `basic` so it can often be omitted | ### Basic auth @@ -927,13 +933,13 @@ By default, HTTPie only outputs the final response and the whole response message is printed (headers as well as the body). You can control what should be printed via several options: -| Option | What is printed | +| Option | What is printed | | --------------: | -------------------------------------------------------------------------------------------------- | | `--headers, -h` | Only the response headers are printed | -| `--body, -b` | Only the response body is printed | +| `--body, -b` | Only the response body is printed | | `--verbose, -v` | Print the whole HTTP exchange (request and response). This option also enables `--all` (see below) | -| `--print, -p` | Selects parts of the HTTP exchange | -| `--quiet, -q` | Don't print anything to `stdout` and `stderr` | +| `--print, -p` | Selects parts of the HTTP exchange | +| `--quiet, -q` | Don't print anything to `stdout` and `stderr` | ### What parts of the HTTP exchange should be printed @@ -942,10 +948,10 @@ It accepts a string of characters each of which represents a specific part of th | Character | Stands for | | --------: | ---------------- | -| `H` | request headers | -| `B` | request body | -| `h` | response headers | -| `b` | response body | +| `H` | request headers | +| `B` | request body | +| `h` | response headers | +| `b` | response body | Print request and response headers: @@ -1162,13 +1168,13 @@ Syntax highlighting is applied to HTTP headers and bodies (where it makes sense) You can choose your preferred color scheme via the `--style` option if you don’t like the default one. There are dozens of styles available, here are just a few notable ones: -| Style | Description | +| Style | Description | | --------: | ----------------------------------------------------------------------------------------------------------------------------------- | -| `auto` | Follows your terminal ANSI color styles. This is the default style used by HTTPie | +| `auto` | Follows your terminal ANSI color styles. This is the default style used by HTTPie | | `default` | Default styles of the underlying Pygments library. Not actually used by default by HTTPie. You can enable it with `--style=default` | | `monokai` | A popular color scheme. Enable with `--style=monokai` | -| `fruity` | A bold, colorful scheme. Enable with `--style=fruity` | -| … | See `$ http --help` for all the possible `--style` values | +| `fruity` | A bold, colorful scheme. Enable with `--style=fruity` | +| … | See `$ http --help` for all the possible `--style` values | Also, the following formatting is applied: @@ -1178,12 +1184,12 @@ Also, the following formatting is applied: Use one of these options to control output processing: -| Option | Description | +| Option | Description | | ----------------: | ------------------------------------------------------------- | -| `--pretty=all` | Apply both colors and formatting. Default for terminal output | +| `--pretty=all` | Apply both colors and formatting. Default for terminal output | | `--pretty=colors` | Apply colors | | `--pretty=format` | Apply formatting | -| `--pretty=none` | Disables output processing. Default for redirected output | +| `--pretty=none` | Disables output processing. Default for redirected output | You can further control the applied formatting via the more granular [format options](#format-options). @@ -1192,14 +1198,14 @@ You can further control the applied formatting via the more granular [format opt The `--format-options=opt1:value,opt2:value` option allows you to control how the output should be formatted when formatting is applied. The following options are available: -| Option | Default value | Shortcuts | +| Option | Default value | Shortcuts | | ---------------: | :-----------: | ------------------------ | -| `headers.sort` | `true` | `--sorted`, `--unsorted` | -| `json.format` | `true` | N/A | -| `json.indent` | `4` | N/A | -| `json.sort_keys` | `true` | `--sorted`, `--unsorted` | -| `xml.format` | `true` | N/A | -| `xml.indent` | `2` | N/A | +| `headers.sort` | `true` | `--sorted`, `--unsorted` | +| `json.format` | `true` | N/A | +| `json.indent` | `4` | N/A | +| `json.sort_keys` | `true` | `--sorted`, `--unsorted` | +| `xml.format` | `true` | N/A | +| `xml.indent` | `2` | N/A | For example, this is how you would disable the default header and JSON key sorting, and specify a custom JSON indent size: diff --git a/snapcraft.yaml b/snapcraft.yaml new file mode 100644 index 0000000000..dbe8b9efaa --- /dev/null +++ b/snapcraft.yaml @@ -0,0 +1,108 @@ +name: httpie +title: HTTPie +summary: Modern, user-friendly command-line HTTP client for the API era +description: | + HTTPie *aitch-tee-tee-pie* is a user-friendly command-line HTTP client + for the API era. + It comes with JSON support, syntax highlighting, persistent sessions, + wget-like downloads, plugins, and more. + + The project's goal is to make CLI interaction with web services as + human-friendly as possible. HTTPie is designed for testing, debugging, + and generally interacting with APIs & HTTP servers. + The http & https commands allow for creating and sending arbitrary HTTP + requests. They use simple and natural syntax and provide formatted and + colorized output. + + Main features: + - Built-in JSON support + - Colorized and formatted terminal output + - Sensible defaults for the API era + - Persistent sessions + - Forms and file uploads + - HTTPS, proxies, and authentication support + - Support for arbitrary request data and headers + - Wget-like downloads + - Extensions API + - Expressive and intuitive syntax + - Linux, macOS, and Windows support + - All that & more in 2 simple commands: http + https + + Links + - Documentation: https://httpie.io/docs + - Try in browser: https://httpie.io/run + - GitHub: https://github.com/httpie/httpie + - Twitter: https://twitter.com/httpie + - Discord: https://httpie.io/chat +license: BSD-3-Clause-LBNL + +# Automatically change the current version based on the source code +adopt-info: httpie + +# https://snapcraft.io/docs/snapcraft-top-level-metadata#heading--icon +# icon: + +base: core20 +confinement: strict +grade: stable + +parts: + httpie: + source: . + plugin: python + + # Guess the current version from sources + override-pull: | + snapcraftctl pull + snapcraftctl set-version $(grep '__version__' httpie/__init__.py | cut -d"'" -f2) + + override-build: | + snapcraftctl build + + echo "Adding HTTPie plugins ..." + python -m pip install httpie-unixsocket + python -m pip install httpie-snapdsocket + + echo "Removing no more needed modules ..." + python -m pip uninstall -y pip wheel + + override-prime: | + snapcraftctl prime + + echo "Removing useless files ..." + packages=$SNAPCRAFT_PRIME/lib/python3.8/site-packages + rm -rfv $packages/_distutils_hack + rm -rfv $packages/pkg_resources/tests + rm -rfv $packages/requests_unixsocket/test* + rm -rfv $packages/setuptools + + echo "Compiling pyc files ..." + python -m compileall -f $packages + + echo "Copying extra files ..." + cp $SNAPCRAFT_PART_SRC/extras/httpie-completion.bash $SNAPCRAFT_PRIME/bin/ + +plugs: + dot-config-httpie: + interface: personal-files + write: + - $HOME/.config/httpie + +apps: + http: + command: bin/http + plugs: &plugs + - dot-config-httpie + - home + - network + - removable-media + completer: bin/httpie-completion.bash + environment: + LC_ALL: C.UTF-8 + + https: + command: bin/https + plugs: *plugs + completer: bin/httpie-completion.bash + environment: + LC_ALL: C.UTF-8 From 84ef9f588c1143a3912089771824e88bc2040c18 Mon Sep 17 00:00:00 2001 From: Omer Akram Date: Tue, 7 Sep 2021 19:57:05 +0500 Subject: [PATCH 0796/1182] Use lzo compression for snap (#1146) --- snapcraft.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/snapcraft.yaml b/snapcraft.yaml index dbe8b9efaa..e9e1fe322b 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -45,6 +45,7 @@ adopt-info: httpie base: core20 confinement: strict grade: stable +compression: lzo parts: httpie: From 978258ec5b929735a6880f267ad8f085fe495219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 8 Sep 2021 10:04:49 +0200 Subject: [PATCH 0797/1182] Add Alpine Linux installation instructions --- docs/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/README.md b/docs/README.md index 7bf962aa2c..c7af40a1db 100644 --- a/docs/README.md +++ b/docs/README.md @@ -91,6 +91,11 @@ $ emerge httpie $ pacman -S httpie ``` +```bash +# Alpine Linux +$ apk add httpie +``` + ```bash # Solus $ eopkg install httpie From a586fca246043f1191af11dc1d8270e22dd9294b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 8 Sep 2021 11:01:27 +0200 Subject: [PATCH 0798/1182] Update brew formula to 2.5.0 (#1144) * Update brew formula to 2.5.0 * Can use `idna` 3.2 * Sort requirements to ease reproductible builds And also to have the same output as `brew bump-formula-pr`. * Sync `bottles` with official Formula And keep the `high_sierra` one. * Add a workflow to check the Formula --- .../workflows/packaging_mac_check_formula.yml | 18 +++++ Makefile | 9 ++- extras/brew-deps.py | 13 ++-- extras/httpie.rb | 67 ++++++++++--------- 4 files changed, 69 insertions(+), 38 deletions(-) create mode 100644 .github/workflows/packaging_mac_check_formula.yml diff --git a/.github/workflows/packaging_mac_check_formula.yml b/.github/workflows/packaging_mac_check_formula.yml new file mode 100644 index 0000000000..c3f69a0fb1 --- /dev/null +++ b/.github/workflows/packaging_mac_check_formula.yml @@ -0,0 +1,18 @@ +name: Check Brew Formula + +on: + pull_request: + paths: + - extras/httpie.rb + +jobs: + check-formula: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Brew + run: | + brew developer on + brew update + - name: Build and test the Formula + run: make brew-test diff --git a/Makefile b/Makefile index fa15e8fafd..52b5a8b419 100644 --- a/Makefile +++ b/Makefile @@ -182,7 +182,14 @@ brew-deps: extras/brew-deps.py brew-test: + @echo $(H1)Uninstalling httpie$(H1END) - brew uninstall httpie - brew install --build-from-source ./extras/httpie.rb + + @echo $(H1)Building from source…$(H1END) + - brew install --build-from-source ./extras/httpie.rb + + @echo $(H1)Verifying…$(H1END) brew test httpie + + @echo $(H1)Auditing…$(H1END) brew audit --strict httpie diff --git a/extras/brew-deps.py b/extras/brew-deps.py index 422e5a1731..5a7b711ff2 100755 --- a/extras/brew-deps.py +++ b/extras/brew-deps.py @@ -15,21 +15,22 @@ VERSIONS = { # By default, we use the latest packages. But sometimes Requests has a maximum supported versions. # Take a look here before making a release: - 'idna': '2.10', + 'idna': '3.2', } +# Note: Keep that list sorted. PACKAGES = [ + 'certifi', + 'charset-normalizer', + 'defusedxml', 'httpie', + 'idna', 'Pygments', + 'PySocks', 'requests', 'requests-toolbelt', - 'certifi', 'urllib3', - 'idna', - 'chardet', - 'PySocks', - 'defusedxml', ] diff --git a/extras/httpie.rb b/extras/httpie.rb index 623301081f..25d45ce4cc 100644 --- a/extras/httpie.rb +++ b/extras/httpie.rb @@ -9,55 +9,45 @@ class Httpie < Formula desc "User-friendly cURL replacement (command-line HTTP client)" homepage "https://httpie.io/" - url "https://files.pythonhosted.org/packages/17/3a/90fb6702e600f5ba7d38d147bbc0b0a1e47159e3e244737319c98c140420/httpie-2.4.0.tar.gz" - sha256 "4d1bf5779cf6c9007351cfcaa20bd19947267dc026af09246db6006a8927d8c6" + url "https://files.pythonhosted.org/packages/90/64/7ea8066309970f787653bdc8c5328272a5c4d06cbce3a07a6a5c3199c3d7/httpie-2.5.0.tar.gz" + sha256 "fe6a8bc50fb0635a84ebe1296a732e39357c3e1354541bf51a7057b4877e47f9" license "BSD-3-Clause" head "https://github.com/httpie/httpie.git" bottle do - rebuild 1 - sha256 cellar: :any_skip_relocation, arm64_big_sur: "a01ce8767f6ea88eb8e7894347ba64eb29294053a8ee91eed44dfaf0ab5e7ea2" - sha256 cellar: :any_skip_relocation, big_sur: "bdffeff349595ed3c528ed791d568e308b0877246b49e05e867143ba3415a70f" - sha256 cellar: :any_skip_relocation, catalina: "ba0627d70f0ee49c64677f5554881ebd56371f47d45196b6564680089ce69152" - sha256 cellar: :any_skip_relocation, mojave: "0b87901e88bdcf53c55c5138677087b4621c5aaf1fca67b53b730d5a2fd5a40a" + sha256 cellar: :any_skip_relocation, arm64_big_sur: "a0c123788163512698a0d284cfd6cb8125d8355aa59c3e4639df90b4388f94b5" + sha256 cellar: :any_skip_relocation, big_sur: "4e4bc9dd47e194bd45e9c0e36039942aed76a465871980924f0f27e83681d918" + sha256 cellar: :any_skip_relocation, catalina: "72dfebccff912bdb3913860983faf59c07c74db737ad4bf56143713236803821" + sha256 cellar: :any_skip_relocation, mojave: "4733686b9a1564835b6662e758dd39dd80fcb940b684af57485392bb9d6bf04e" + sha256 cellar: :any_skip_relocation, x86_64_linux: "914d67f6d9f732a7888ba2e35cf9c00525fb24917b6610544125b7bba545c7fc" sha256 cellar: :any_skip_relocation, high_sierra: "87e7348b6fb40fd8e4f7597937952469601962189e62d321b8cb4fa421e035ef" end depends_on "python@3.9" - resource "Pygments" do - url "https://files.pythonhosted.org/packages/e1/86/8059180e8217299079d8719c6e23d674aadaba0b1939e25e0cc15dcf075b/Pygments-2.7.4.tar.gz" - sha256 "df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337" - end - - resource "requests" do - url "https://files.pythonhosted.org/packages/6b/47/c14abc08432ab22dc18b9892252efaf005ab44066de871e72a38d6af464b/requests-2.25.1.tar.gz" - sha256 "27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804" - end - - resource "requests-toolbelt" do - url "https://files.pythonhosted.org/packages/28/30/7bf7e5071081f761766d46820e52f4b16c8a08fef02d2eb4682ca7534310/requests-toolbelt-0.9.1.tar.gz" - sha256 "968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0" + resource "certifi" do + url "https://files.pythonhosted.org/packages/6d/78/f8db8d57f520a54f0b8a438319c342c61c22759d8f9a1cd2e2180b5e5ea9/certifi-2021.5.30.tar.gz" + sha256 "2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee" end - resource "certifi" do - url "https://files.pythonhosted.org/packages/06/a9/cd1fd8ee13f73a4d4f491ee219deeeae20afefa914dfb4c130cfc9dc397a/certifi-2020.12.5.tar.gz" - sha256 "1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c" + resource "charset-normalizer" do + url "https://files.pythonhosted.org/packages/e7/4e/2af0238001648ded297fb54ceb425ca26faa15b341b4fac5371d3938666e/charset-normalizer-2.0.4.tar.gz" + sha256 "f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3" end - resource "urllib3" do - url "https://files.pythonhosted.org/packages/d7/8d/7ee68c6b48e1ec8d41198f694ecdc15f7596356f2ff8e6b1420300cf5db3/urllib3-1.26.3.tar.gz" - sha256 "de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" + resource "defusedxml" do + url "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz" + sha256 "1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69" end resource "idna" do - url "https://files.pythonhosted.org/packages/ea/b7/e0e3c1c467636186c39925827be42f16fee389dc404ac29e930e9136be70/idna-2.10.tar.gz" - sha256 "b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6" + url "https://files.pythonhosted.org/packages/cb/38/4c4d00ddfa48abe616d7e572e02a04273603db446975ab46bbcd36552005/idna-3.2.tar.gz" + sha256 "467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" end - resource "chardet" do - url "https://files.pythonhosted.org/packages/ee/2d/9cdc2b527e127b4c9db64b86647d567985940ac3698eeabc7ffaccb4ea61/chardet-4.0.0.tar.gz" - sha256 "0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa" + resource "Pygments" do + url "https://files.pythonhosted.org/packages/b7/b3/5cba26637fe43500d4568d0ee7b7362de1fb29c0e158d50b4b69e9a40422/Pygments-2.10.0.tar.gz" + sha256 "f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6" end resource "PySocks" do @@ -65,6 +55,21 @@ class Httpie < Formula sha256 "3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0" end + resource "requests" do + url "https://files.pythonhosted.org/packages/e7/01/3569e0b535fb2e4a6c384bdbed00c55b9d78b5084e0fb7f4d0bf523d7670/requests-2.26.0.tar.gz" + sha256 "b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" + end + + resource "requests-toolbelt" do + url "https://files.pythonhosted.org/packages/28/30/7bf7e5071081f761766d46820e52f4b16c8a08fef02d2eb4682ca7534310/requests-toolbelt-0.9.1.tar.gz" + sha256 "968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0" + end + + resource "urllib3" do + url "https://files.pythonhosted.org/packages/4f/5a/597ef5911cb8919efe4d86206aa8b2658616d676a7088f0825ca08bd7cb8/urllib3-1.26.6.tar.gz" + sha256 "f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" + end + def install virtualenv_install_with_resources end From 4d7d6b66cf1bd5f3331b666114134821b29b2075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 8 Sep 2021 11:03:15 +0200 Subject: [PATCH 0799/1182] Trigger official documentation build when documentation is updated here --- .github/workflows/update_documentation.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/update_documentation.yml diff --git a/.github/workflows/update_documentation.yml b/.github/workflows/update_documentation.yml new file mode 100644 index 0000000000..3772269b73 --- /dev/null +++ b/.github/workflows/update_documentation.yml @@ -0,0 +1,18 @@ +name: Update documentation + +on: + push: + branches: + - master + paths: + - docs/README.md + release: + types: + - published + +jobs: + trigger-doc-build: + runs-on: ubuntu-latest + steps: + - name: Trigger new documentation build + run: curl -X POST ${{ secrets.DOCS_UPDATE_VERCEL_HOOK }} From 4c8633c6e51f388523ab4fa649040934402a4fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 8 Sep 2021 16:41:55 +0200 Subject: [PATCH 0800/1182] Split the monolithic workflow into specific ones (#1149) * Split the monolithic workflow into specific ones * Rename workflows, improve commands * Update pip from the venv * Fix Windows setup * Lowercase macos-latest * Fix Windows run, again --- .github/workflows/build.yml | 35 ---------------- .github/workflows/code-style.yml | 21 ++++++++++ .github/workflows/coverage.yml | 24 +++++++++++ ...la.yml => packaging-mac-check-formula.yml} | 1 + .github/workflows/tests.yml | 40 +++++++++++++++++++ ...mentation.yml => update-documentation.yml} | 0 Makefile | 3 ++ 7 files changed, 89 insertions(+), 35 deletions(-) delete mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/code-style.yml create mode 100644 .github/workflows/coverage.yml rename .github/workflows/{packaging_mac_check_formula.yml => packaging-mac-check-formula.yml} (85%) create mode 100644 .github/workflows/tests.yml rename .github/workflows/{update_documentation.yml => update-documentation.yml} (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 25fd07f37b..0000000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Build -on: [push, pull_request] -jobs: - extras: - # Run coverage and extra tests only once - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: 3.9 - - run: python -m pip install --upgrade pip setuptools wheel - - run: make install - - run: make codestyle - - run: make test-cover - - run: make codecov-upload - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_REPO_TOKEN }} - - run: make test-dist - test: - # Run core HTTPie tests everywhere - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macOS-latest, windows-latest] - python-version: [3.6, 3.7, 3.8, 3.9, "3.10.0-rc.1"] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - run: python -m pip install --upgrade pip setuptools wheel - - run: python -m pip install --upgrade '.[dev]' - - run: python -m pytest --verbose ./httpie ./tests diff --git a/.github/workflows/code-style.yml b/.github/workflows/code-style.yml new file mode 100644 index 0000000000..d006c85d3d --- /dev/null +++ b/.github/workflows/code-style.yml @@ -0,0 +1,21 @@ +name: Code style + +on: + pull_request: + paths: + - .github/workflows/code-style.yml + - extras/*.py + - httpie/**/*.py + - setup.py + - tests/**/*.py + +jobs: + code-style: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.9 + - run: make venv + - run: make codestyle diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000000..8c0f94f07a --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,24 @@ +name: Coverage + +on: + pull_request: + paths: + - .github/workflows/coverage.yml + - httpie/**/*.py + - setup.* + - tests/**/*.py + +jobs: + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.9 + - run: make install + - run: make test-cover + - run: make codecov-upload + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_REPO_TOKEN }} + - run: make test-dist diff --git a/.github/workflows/packaging_mac_check_formula.yml b/.github/workflows/packaging-mac-check-formula.yml similarity index 85% rename from .github/workflows/packaging_mac_check_formula.yml rename to .github/workflows/packaging-mac-check-formula.yml index c3f69a0fb1..f1c72f598a 100644 --- a/.github/workflows/packaging_mac_check_formula.yml +++ b/.github/workflows/packaging-mac-check-formula.yml @@ -3,6 +3,7 @@ name: Check Brew Formula on: pull_request: paths: + - .github/workflows/packaging-mac-check-formula.yml - extras/httpie.rb jobs: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000000..ae532223b8 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,40 @@ +name: Tests + +on: + push: + branches: + - master + paths: + - httpie/**/*.py + - setup.* + pull_request: + paths: + - .github/workflows/tests.yml + - httpie/**/*.py + - setup.* + - tests/**/*.py + +jobs: + test: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: [3.6, 3.7, 3.8, 3.9, "3.10.0-rc.2"] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Windows setup + if: matrix.os == 'windows-latest' + run: | + python -m pip install --upgrade pip wheel + python -m pip install --upgrade '.[dev]' + python -m pytest --verbose ./httpie ./tests + - name: Linux & Mac setup + if: matrix.os != 'windows-latest' + run: | + make install + make test diff --git a/.github/workflows/update_documentation.yml b/.github/workflows/update-documentation.yml similarity index 100% rename from .github/workflows/update_documentation.yml rename to .github/workflows/update-documentation.yml diff --git a/Makefile b/Makefile index 52b5a8b419..a020d65977 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,9 @@ all: uninstall-httpie install test install: venv + @echo $(H1)Updating package tools$(H1END) + $(VENV_PIP) install --upgrade pip wheel + @echo $(H1)Installing dev requirements$(H1END) $(VENV_PIP) install --upgrade --editable '.[dev]' From 7c9f415107c3bc17e36e073238d852ff123d9260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 9 Sep 2021 15:52:24 +0200 Subject: [PATCH 0801/1182] Add a workflow to check documentations (#1151) * Add a workflow to check documentations * Fix markdown issues * Install Ruby 2.7 * Finally, handle and fix GitHub templates * Minor improvement in the feature request template * Verbose mode to be sure all files are checked --- .github/ISSUE_TEMPLATE/bug_report.md | 24 +++++++--- .github/ISSUE_TEMPLATE/feature_request.md | 16 +++++-- .github/workflows/documentations.yml | 21 ++++++++ CODE_OF_CONDUCT.md | 4 +- CONTRIBUTING.md | 4 +- Makefile | 5 ++ README.md | 8 ++-- docs/README.md | 58 +++++++++++------------ docs/linter/mdl-styles.rb | 39 +++++++++++++++ setup.py | 1 - tests/test_docs.py | 35 -------------- 11 files changed, 130 insertions(+), 85 deletions(-) create mode 100644 .github/workflows/documentations.yml create mode 100644 docs/linter/mdl-styles.rb delete mode 100644 tests/test_docs.py diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index d3866e8431..7e5758695b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,34 +7,44 @@ assignees: '' --- -**Checklist** +## Checklist - [ ] I've searched for similar issues. - [ ] I'm using the latest version of HTTPie. --- -**What are the steps to reproduce the problem?** +## Minimal reproduction code and steps 1. 2. 3. +--- + +## Expected result -**What is the expected result?** +… + +--- +## Current result -**What happens instead?** +… +--- -**Debug output** +## Debug output Please re-run the command with `--debug`, then copy the entire command & output and paste both below: -``` +```bash $ http --debug ``` +--- + +## Additional information, screenshots, or code examples -**Provide any additional information, screenshots, or code examples below:** +… diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 9de0b1604a..329c06a2ae 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -6,19 +6,25 @@ labels: "new, enhancement" assignees: '' --- -**Checklist** + +## Checklist - [ ] I've searched for similar feature requests. --- -**What enhancement would you like to see?** +## Enhancement request + +… +--- -**What problem does it solve?** +## Problem it solves -E.g. “I'm always frustrated when [...]”, “I’m trying to do […] so that […]”. +E.g. “I'm always frustrated when […]”, “I’m trying to do […] so that […]”. +--- -**Provide any additional information, screenshots, or code examples below:** +## Additional information, screenshots, or code examples +… diff --git a/.github/workflows/documentations.yml b/.github/workflows/documentations.yml new file mode 100644 index 0000000000..e24acfc9fc --- /dev/null +++ b/.github/workflows/documentations.yml @@ -0,0 +1,21 @@ +name: Check documentations + +on: + pull_request: + paths: + - "*.md" + - "**/*.md" + +jobs: + doc: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.7 + - name: Install the linter + run: sudo gem install mdl + - name: Check files + run: make doc-check diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 156e17407d..973efd8bc8 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -68,7 +68,7 @@ members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), -version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +version 1.4, available at For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 76a8206236..7dd42c50ee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,7 +44,7 @@ Consider also adding a [CHANGELOG](https://github.com/httpie/httpie/blob/master/ #### Getting the code -Go to https://github.com/httpie/httpie and fork the project repository. +Go to and fork the project repository. ```bash # Clone your fork @@ -89,7 +89,7 @@ a hack but it works™.) You should now see `(httpie)` next to your shell prompt, and the `http` command should point to your development copy: -``` +```bash (httpie) ~/Code/httpie $ which http /Users//Code/httpie/venv/bin/http (httpie) ~/Code/httpie $ http --version diff --git a/Makefile b/Makefile index a020d65977..94f5fd9767 100644 --- a/Makefile +++ b/Makefile @@ -138,6 +138,11 @@ codecov-upload: @echo +doc-check: + @echo $(H1)Running documentations checks$(H1END) + mdl --verbose --git-recurse --style docs/linter/mdl-styles.rb . + + ############################################################################### # Publishing to PyPi ############################################################################### diff --git a/README.md b/README.md index fef370ab4f..47d0b8b17d 100644 --- a/README.md +++ b/README.md @@ -44,25 +44,25 @@ They use simple and natural syntax and provide formatted and colorized output. Hello World: -``` +```bash $ https httpie.io/hello ``` Custom [HTTP method](https://httpie.io/docs#http-method), [HTTP headers](https://httpie.io/docs#http-headers) and [JSON](https://httpie.io/docs#json) data: -``` +```bash $ http PUT pie.dev/put X-API-Token:123 name=John ``` Build and print a request without sending it using [offline mode](https://httpie.io/docs#offline-mode): -``` +```bash $ http --offline pie.dev/post hello=offline ``` Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comment) to post a comment on an [Issue](https://github.com/httpie/httpie/issues/83) with [authentication](https://httpie.io/docs#authentication): -``` +```bash $ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comments body='HTTPie is awesome! :heart:' ``` diff --git a/docs/README.md b/docs/README.md index c7af40a1db..959b30e7c4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -101,7 +101,7 @@ $ apk add httpie $ eopkg install httpie ``` -### Windows, etc. +### Windows, universal A universal installation method (that works on Linux, macOS and Windows, and always provides the latest version) is to use [pip](https://pypi.org/project/pip/): @@ -1474,40 +1474,40 @@ To set a cookie within a Session there are three options: 1. Get a `Set-Cookie` header in a response from a server -```bash -$ http --session=./session.json pie.dev/cookie/set?foo=bar -``` + ```bash + $ http --session=./session.json pie.dev/cookie/set?foo=bar + ``` 2. Set the cookie name and value through the command line as seen in [cookies](#cookies) -```bash -$ http --session=./session.json pie.dev/headers Cookie:foo=bar -``` + ```bash + $ http --session=./session.json pie.dev/headers Cookie:foo=bar + ``` 3. Manually set cookie parameters in the JSON file of the session -```json -{ - "__meta__": { - "about": "HTTPie session file", - "help": "https://httpie.org/doc#sessions", - "httpie": "2.2.0-dev" - }, - "auth": { - "password": null, - "type": null, - "username": null - }, - "cookies": { - "foo": { - "expires": null, - "path": "/", - "secure": false, - "value": "bar" - } - } -} -``` + ```json + { + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.org/doc#sessions", + "httpie": "2.2.0-dev" + }, + "auth": { + "password": null, + "type": null, + "username": null + }, + "cookies": { + "foo": { + "expires": null, + "path": "/", + "secure": false, + "value": "bar" + } + } + } + ``` Cookies will be set in the session file with the priority specified above. For example, a cookie set through the command line will overwrite a cookie of the same name stored in the session file. diff --git a/docs/linter/mdl-styles.rb b/docs/linter/mdl-styles.rb new file mode 100644 index 0000000000..a5938b7211 --- /dev/null +++ b/docs/linter/mdl-styles.rb @@ -0,0 +1,39 @@ +# Load all rules by default +all + +# +# Tweak rules +# + +# MD002 First header should be a top level header +# Because we use HTML to hide them on the website. +exclude_rule 'MD002' + +# MD013 Line length +exclude_rule 'MD013' + +# MD014 Dollar signs used before commands without showing output +exclude_rule 'MD014' + +# Tell the linter to use ordered lists: +# 1. Foo +# 2. Bar +# 3. Baz +# +# Instead of: +# 1. Foo +# 1. Bar +# 1. Baz +rule 'MD029', :style => :ordered + +# MD033 Inline HTML +# TODO: Tweak elements when https://github.com/markdownlint/markdownlint/issues/118 will be done? +exclude_rule 'MD033' + +# MD034 Bare URL used +# TODO: Remove when https://github.com/markdownlint/markdownlint/issues/328 will be fixed. +exclude_rule 'MD034' + +# MD041 First line in file should be a top level header +# Because we use HTML to hide them on the website. +exclude_rule 'MD041' diff --git a/setup.py b/setup.py index d841aa3acd..acde80a0eb 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,6 @@ 'flake8-deprecated', 'flake8-mutable', 'flake8-tuple', - 'mdformat', 'pytest-cov', 'twine', 'wheel', diff --git a/tests/test_docs.py b/tests/test_docs.py deleted file mode 100644 index 9a5afbf7e9..0000000000 --- a/tests/test_docs.py +++ /dev/null @@ -1,35 +0,0 @@ -import os - -import pytest -from httpie.compat import is_windows - -from .utils import TESTS_ROOT - - -ROOT = TESTS_ROOT.parent -SOURCE_DIRECTORIES = [ - 'docs', - 'extras', - 'httpie', - 'tests', -] - - -def md_filenames(): - yield from ROOT.glob('*.md') - for directory in SOURCE_DIRECTORIES: - yield from (ROOT / directory).glob('**/*.md') - - -filenames = sorted(md_filenames()) -assert filenames - - -@pytest.mark.skipif(is_windows and 'CI' in os.environ, - reason='Does not pass on GitHub.') -@pytest.mark.parametrize('filename', filenames) -def test_md_file_syntax(filename): - mdformat = pytest.importorskip('mdformat._cli') - args = ['--end-of-line', 'lf', '--number'] - err = f'Running "python -m mdformat {" ".join(args)} {filename}; git diff" should help.' - assert mdformat.run(args + ['--check', str(filename)]) == 0, err From 513e5080e4c33f39f60cb4bc1606eb08b55ee6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 9 Sep 2021 16:06:03 +0200 Subject: [PATCH 0802/1182] Add the release workflow It has to be triggered manually for now. --- .github/workflows/release.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..41ba517367 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,28 @@ +name: Release + +on: + # Add a "Trigger" button to manually start the workflow. + workflow_dispatch: + inputs: + branch: + description: "The branch, tag or SHA to release from" + required: true + default: "master" + # It could be fully automated by uncommenting following lines. + # Let's see later if we are confident enough to try it :) + # release: + # types: + # - published + +jobs: + new-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.9 + - run: make publish + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} From a45b94fda604877a9f94d6a2e0ece7893eeb3956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 9 Sep 2021 16:36:28 +0200 Subject: [PATCH 0803/1182] Complete CentOS installation instructions --- docs/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.md b/docs/README.md index 959b30e7c4..53f99f3416 100644 --- a/docs/README.md +++ b/docs/README.md @@ -78,6 +78,7 @@ $ dnf install httpie ```bash # CentOS, RHEL, ... +$ yum install epel-release $ yum install httpie ``` From b38352858fcf19dee770765f3607276efe5d7e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Fri, 10 Sep 2021 09:55:07 +0200 Subject: [PATCH 0804/1182] [snap] Remove personal-files interface Use of the `personal-files` interface is reserved for vetted publishers. The interface requires a validation, but we need to publish at least one package first. So let's skip that part, release a version and ask for the interface access in a second time. Also add a workflow to build & test the snap package. --- .github/workflows/packaging-linux-snap.yml | 25 +++++++++++++++++++ ...eck-formula.yml => packaging-mac-brew.yml} | 10 ++++---- snapcraft.yaml | 2 +- 3 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/packaging-linux-snap.yml rename .github/workflows/{packaging-mac-check-formula.yml => packaging-mac-brew.yml} (57%) diff --git a/.github/workflows/packaging-linux-snap.yml b/.github/workflows/packaging-linux-snap.yml new file mode 100644 index 0000000000..101964011c --- /dev/null +++ b/.github/workflows/packaging-linux-snap.yml @@ -0,0 +1,25 @@ +name: Linux snap + +on: + pull_request: + paths: + - .github/workflows/packaging-linux-snap.yml + - snapcraft.yaml + +jobs: + snap: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Build + uses: snapcore/action-build@v1 + id: snapcraft + - name: Install + run: sudo snap install --dangerous ${{ steps.snapcraft.outputs.snap }} + - name: Test + run: | + httpie.http --version + httpie.https --version + # Auto-aliases cannot be tested when installing a snap outside the store. + # http --version + # https --version diff --git a/.github/workflows/packaging-mac-check-formula.yml b/.github/workflows/packaging-mac-brew.yml similarity index 57% rename from .github/workflows/packaging-mac-check-formula.yml rename to .github/workflows/packaging-mac-brew.yml index f1c72f598a..0aeeec25b3 100644 --- a/.github/workflows/packaging-mac-check-formula.yml +++ b/.github/workflows/packaging-mac-brew.yml @@ -1,19 +1,19 @@ -name: Check Brew Formula +name: Mac brew on: pull_request: paths: - - .github/workflows/packaging-mac-check-formula.yml + - .github/workflows/packaging-mac-brew.yml - extras/httpie.rb jobs: - check-formula: + brew: runs-on: macos-latest steps: - uses: actions/checkout@v2 - - name: Setup Brew + - name: Setup brew run: | brew developer on brew update - - name: Build and test the Formula + - name: Build and test the formula run: make brew-test diff --git a/snapcraft.yaml b/snapcraft.yaml index e9e1fe322b..f4636a8142 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -93,7 +93,7 @@ apps: http: command: bin/http plugs: &plugs - - dot-config-httpie + # - dot-config-httpie - home - network - removable-media From 30c595b770301781fd95052bc6e3c09971449c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Fri, 10 Sep 2021 10:58:42 +0200 Subject: [PATCH 0805/1182] [snap] Comment out the problematic interface It seems it just needs to be present for the snap to be rejected. --- snapcraft.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/snapcraft.yaml b/snapcraft.yaml index f4636a8142..54fc4c7c9c 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -83,11 +83,11 @@ parts: echo "Copying extra files ..." cp $SNAPCRAFT_PART_SRC/extras/httpie-completion.bash $SNAPCRAFT_PRIME/bin/ -plugs: - dot-config-httpie: - interface: personal-files - write: - - $HOME/.config/httpie +# plugs: +# dot-config-httpie: +# interface: personal-files +# write: +# - $HOME/.config/httpie apps: http: From 7734e47280c321c08e2d762dd47fe29a5c85482d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 10 Sep 2021 11:17:10 +0200 Subject: [PATCH 0806/1182] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 47d0b8b17d..cf2cce743d 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ They use simple and natural syntax and provide formatted and colorized output. - Persistent sessions - `wget`-like downloads -[See for all features →](https://httpie.io/docs) +[See for features →](https://httpie.io/docs) ## Examples From 7c1d26a8fadb1ab00609e37573c764f8d8ff7a7d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 10 Sep 2021 11:17:23 +0200 Subject: [PATCH 0807/1182] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cf2cce743d..75b0576cdf 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ They use simple and natural syntax and provide formatted and colorized output. - Persistent sessions - `wget`-like downloads -[See for features →](https://httpie.io/docs) +[See all features →](https://httpie.io/docs) ## Examples From 0115a4a46662b563a0f22f957e502c84b6f5c4f0 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 10 Sep 2021 18:50:45 +0200 Subject: [PATCH 0808/1182] Create config.json --- docs/config.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/config.json diff --git a/docs/config.json b/docs/config.json new file mode 100644 index 0000000000..2291f3235f --- /dev/null +++ b/docs/config.json @@ -0,0 +1,5 @@ +{ + "website": { + "master_and_released_docs_differ_after_commit": null + } +} From f06d87001262bc4d8762cda4c8ba9ec9c091c372 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 10 Sep 2021 20:04:52 +0200 Subject: [PATCH 0809/1182] Update and rename documentations.yml to check-markdown.yml --- .github/workflows/{documentations.yml => check-markdown.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{documentations.yml => check-markdown.yml} (93%) diff --git a/.github/workflows/documentations.yml b/.github/workflows/check-markdown.yml similarity index 93% rename from .github/workflows/documentations.yml rename to .github/workflows/check-markdown.yml index e24acfc9fc..4e0b88ad16 100644 --- a/.github/workflows/documentations.yml +++ b/.github/workflows/check-markdown.yml @@ -1,4 +1,4 @@ -name: Check documentations +name: Check markdown on: pull_request: From a51068a44ddce62f7a53e816be58a8f6ffd4d510 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 10 Sep 2021 20:05:23 +0200 Subject: [PATCH 0810/1182] Update update-documentation.yml --- .github/workflows/update-documentation.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/update-documentation.yml b/.github/workflows/update-documentation.yml index 3772269b73..812a773c8b 100644 --- a/.github/workflows/update-documentation.yml +++ b/.github/workflows/update-documentation.yml @@ -6,6 +6,7 @@ on: - master paths: - docs/README.md + - docs/config.json release: types: - published From 2b5f8f48bffef7715d6194d47732a6d52ee59340 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 10 Sep 2021 20:06:29 +0200 Subject: [PATCH 0811/1182] Update update-documentation.yml --- .github/workflows/update-documentation.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-documentation.yml b/.github/workflows/update-documentation.yml index 812a773c8b..81a5c989d1 100644 --- a/.github/workflows/update-documentation.yml +++ b/.github/workflows/update-documentation.yml @@ -10,7 +10,8 @@ on: release: types: - published - + - unpublished + - deleted jobs: trigger-doc-build: runs-on: ubuntu-latest From 4f84362d7365fc830d4e762024e749a73e39542d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 10 Sep 2021 23:58:33 +0200 Subject: [PATCH 0812/1182] Update config.json --- docs/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.json b/docs/config.json index 2291f3235f..4375a5a5e7 100644 --- a/docs/config.json +++ b/docs/config.json @@ -1,5 +1,5 @@ { "website": { - "master_and_released_docs_differ_after_commit": null + "master_and_released_docs_differ_after": null } } From 10081b9fcc6c2a00c54652b8850a29e031e1324b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 11 Sep 2021 17:17:15 +0200 Subject: [PATCH 0813/1182] Update README.md --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 53f99f3416..004fddfd84 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@
      -# HTTPie Documentation +# HTTPie documentation
      From 9984447f180ea71a8e6bc6fcfe81efdfad836271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 13 Sep 2021 12:33:32 +0200 Subject: [PATCH 0814/1182] Reverse results in bug report temlpate Ir seems weird to ask for the expected result before knowing the current one. --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7e5758695b..b79fe2df0b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -22,13 +22,13 @@ assignees: '' --- -## Expected result +## Current result … --- -## Current result +## Expected result … From 8f7f4a6ef4213a2b605262087e6c0ed79a9f18bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 13 Sep 2021 12:36:01 +0200 Subject: [PATCH 0815/1182] Remove some horizontal lines in the bug report And add myself to assignees. --- .github/ISSUE_TEMPLATE/bug_report.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b79fe2df0b..9b0f05023c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -3,7 +3,7 @@ name: Bug report about: Report a possible bug in HTTPie title: '' labels: "new, bug" -assignees: '' +assignees: 'BoboTiG' --- @@ -20,14 +20,10 @@ assignees: '' 2. 3. ---- - ## Current result … ---- - ## Expected result … @@ -43,8 +39,6 @@ $ http --debug ``` ---- - ## Additional information, screenshots, or code examples … From ba6fd0bc147d081064e62a07285f0c1cd19cdc1e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 14 Sep 2021 01:01:46 +0200 Subject: [PATCH 0816/1182] Add a blog post link --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f53c6b1a14..ce38f5a3c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06) +Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0) + - Added `--raw` to allow specifying the raw request body without extra processing as an alternative to `stdin`. ([#534](https://github.com/httpie/httpie/issues/534)) - Added support for XML formatting. ([#1129](https://github.com/httpie/httpie/issues/1129)) From 9dd0203bae1725ee0a4fd08252c740af8e15e9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 15 Sep 2021 14:25:46 +0200 Subject: [PATCH 0817/1182] Use HTTPie for the documentation build request (#1150) Co-authored-by: Jakub Roztocil --- .github/workflows/update-documentation.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-documentation.yml b/.github/workflows/update-documentation.yml index 81a5c989d1..d9af12e38f 100644 --- a/.github/workflows/update-documentation.yml +++ b/.github/workflows/update-documentation.yml @@ -16,5 +16,7 @@ jobs: trigger-doc-build: runs-on: ubuntu-latest steps: + - name: Install HTTPie + run: sudo snap install --edge httpie - name: Trigger new documentation build - run: curl -X POST ${{ secrets.DOCS_UPDATE_VERCEL_HOOK }} + run: http --ignore-stdin POST ${{ secrets.DOCS_UPDATE_VERCEL_HOOK }} From e2ba214ac02905ab0ada72c582c9e95023c49496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 15 Sep 2021 16:50:44 +0200 Subject: [PATCH 0818/1182] [snap] Improve OS integration (#1157) Get back read-write access to `$HOME/.config/httpie` and `$HOME/.httpie`. --- snapcraft.yaml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/snapcraft.yaml b/snapcraft.yaml index 54fc4c7c9c..ef72a810c8 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -83,17 +83,22 @@ parts: echo "Copying extra files ..." cp $SNAPCRAFT_PART_SRC/extras/httpie-completion.bash $SNAPCRAFT_PRIME/bin/ -# plugs: -# dot-config-httpie: -# interface: personal-files -# write: -# - $HOME/.config/httpie +plugs: + dot-config-httpie: + interface: personal-files + write: + - $HOME/.config/httpie + dot-httpie: + interface: personal-files + write: + - $HOME/.httpie apps: http: command: bin/http plugs: &plugs - # - dot-config-httpie + - dot-config-httpie + - dot-httpie - home - network - removable-media From 529aa78ee176b6548c5ec93352302d8fd175d978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 20 Sep 2021 17:36:03 +0200 Subject: [PATCH 0819/1182] Expand the pytest configuration (#1161) And rely on it to run tests. --- Makefile | 4 ++-- setup.cfg | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 94f5fd9767..9e46a5a250 100644 --- a/Makefile +++ b/Makefile @@ -80,11 +80,11 @@ venv: test: @echo $(H1)Running tests$(HEADER_EXTRA)$(H1END) - $(VENV_BIN)/python -m pytest $(COV) ./httpie $(COV) ./tests --doctest-modules --verbose ./httpie ./tests + $(VENV_BIN)/python -m pytest $(COV) @echo -test-cover: COV=--cov +test-cover: COV=--cov=httpie --cov=tests test-cover: HEADER_EXTRA=' (with coverage)' test-cover: test diff --git a/setup.cfg b/setup.cfg index 43e4702961..2deb39a788 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,8 +7,10 @@ [tool:pytest] # -norecursedirs = tests/fixtures .* -addopts = --tb=native --doctest-modules +testpaths = httpie tests +norecursedirs = tests/fixtures +addopts = --tb=native --doctest-modules --verbose +xfail_strict = True [flake8] From 273134123a206a450072b8b984380fa3c8b5314b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 21 Sep 2021 10:40:09 +0200 Subject: [PATCH 0820/1182] Bump the version to 2.6.0.dev0 (#1162) [skip ci] --- CHANGELOG.md | 2 ++ docs/README.md | 2 +- httpie/__init__.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce38f5a3c8..847e70b519 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). +## [2.6.0.dev0](https://github.com/httpie/httpie/compare/2.5.0...master) (unreleased) + ## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06) Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0) diff --git a/docs/README.md b/docs/README.md index 004fddfd84..02383417c6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -148,7 +148,7 @@ Verify that now you have the [current development version identifier](https://gi ```bash $ http --version -# 2.5.0 +# 2.6.0.dev0 ``` ## Usage diff --git a/httpie/__init__.py b/httpie/__init__.py index 4b0a7e4fe2..af8f4e01a9 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '2.5.0' +__version__ = '2.6.0.dev0' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From e6c5cd3e4b66642f1b0bf234c7e74759354355b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 21 Sep 2021 11:15:43 +0200 Subject: [PATCH 0821/1182] Improve JSON output when there is leading data before the actual JSON body (#1130) In some special cases, to prevent against Cross Site Script Inclusion (XSSI) attacks, the JSON response body starts with a magic prefix line that must be stripped before feeding the rest of the response body to the JSON parser. Such prefix is now simply ignored from the parser but still printed in the terminal. * Fix Windows tests --- CHANGELOG.md | 2 ++ httpie/output/formatters/colors.py | 56 +++++------------------------- httpie/output/formatters/json.py | 7 ++-- httpie/output/lexers/__init__.py | 0 httpie/output/lexers/http.py | 49 ++++++++++++++++++++++++++ httpie/output/lexers/json.py | 31 +++++++++++++++++ httpie/output/utils.py | 36 +++++++++++++++++++ tests/test_json.py | 40 +++++++++++++++++++++ 8 files changed, 170 insertions(+), 51 deletions(-) create mode 100644 httpie/output/lexers/__init__.py create mode 100644 httpie/output/lexers/http.py create mode 100644 httpie/output/lexers/json.py create mode 100644 httpie/output/utils.py create mode 100644 tests/test_json.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 847e70b519..ec56074ab6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.6.0.dev0](https://github.com/httpie/httpie/compare/2.5.0...master) (unreleased) +- Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) + ## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06) Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index ff182d2387..d0187337b0 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -9,10 +9,12 @@ from pygments.formatters.terminal import TerminalFormatter from pygments.formatters.terminal256 import Terminal256Formatter from pygments.lexer import Lexer +from pygments.lexers.data import JsonLexer from pygments.lexers.special import TextLexer from pygments.lexers.text import HttpLexer as PygmentsHttpLexer from pygments.util import ClassNotFound +from ..lexers.json import EnhancedJsonLexer from ...compat import is_windows from ...context import Environment from ...plugins import FormatterPlugin @@ -60,6 +62,7 @@ def __init__( http_lexer = PygmentsHttpLexer() formatter = TerminalFormatter() else: + from ..lexers.http import SimplifiedHTTPLexer http_lexer = SimplifiedHTTPLexer() formatter = Terminal256Formatter( style=self.get_style_class(color_scheme) @@ -151,55 +154,12 @@ def get_lexer( else: lexer = pygments.lexers.get_lexer_by_name('json') - return lexer - - -class SimplifiedHTTPLexer(pygments.lexer.RegexLexer): - """Simplified HTTP lexer for Pygments. - - It only operates on headers and provides a stronger contrast between - their names and values than the original one bundled with Pygments - (:class:`pygments.lexers.text import HttpLexer`), especially when - Solarized color scheme is used. + # Use our own JSON lexer: it supports JSON bodies preceded by non-JSON data + # as well as legit JSON bodies. + if isinstance(lexer, JsonLexer): + lexer = EnhancedJsonLexer() - """ - name = 'HTTP' - aliases = ['http'] - filenames = ['*.http'] - tokens = { - 'root': [ - # Request-Line - (r'([A-Z]+)( +)([^ ]+)( +)(HTTP)(/)(\d+\.\d+)', - pygments.lexer.bygroups( - pygments.token.Name.Function, - pygments.token.Text, - pygments.token.Name.Namespace, - pygments.token.Text, - pygments.token.Keyword.Reserved, - pygments.token.Operator, - pygments.token.Number - )), - # Response Status-Line - (r'(HTTP)(/)(\d+\.\d+)( +)(\d{3})( +)(.+)', - pygments.lexer.bygroups( - pygments.token.Keyword.Reserved, # 'HTTP' - pygments.token.Operator, # '/' - pygments.token.Number, # Version - pygments.token.Text, - pygments.token.Number, # Status code - pygments.token.Text, - pygments.token.Name.Exception, # Reason - )), - # Header - (r'(.*?)( *)(:)( *)(.+)', pygments.lexer.bygroups( - pygments.token.Name.Attribute, # Name - pygments.token.Text, - pygments.token.Operator, # Colon - pygments.token.Text, - pygments.token.String # Value - )) - ] - } + return lexer class Solarized256Style(pygments.style.Style): diff --git a/httpie/output/formatters/json.py b/httpie/output/formatters/json.py index 65cbcd1989..bc6151e42f 100644 --- a/httpie/output/formatters/json.py +++ b/httpie/output/formatters/json.py @@ -17,15 +17,16 @@ def format_body(self, body: str, mime: str) -> str: ] if (self.kwargs['explicit_json'] or any(token in mime for token in maybe_json)): + from ..utils import load_prefixed_json try: - obj = json.loads(body) + data_prefix, json_obj = load_prefixed_json(body) except ValueError: pass # Invalid JSON, ignore. else: # Indent, sort keys by name, and avoid # unicode escapes to improve readability. - body = json.dumps( - obj=obj, + body = data_prefix + json.dumps( + obj=json_obj, sort_keys=self.format_options['json']['sort_keys'], ensure_ascii=False, indent=self.format_options['json']['indent'] diff --git a/httpie/output/lexers/__init__.py b/httpie/output/lexers/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/httpie/output/lexers/http.py b/httpie/output/lexers/http.py new file mode 100644 index 0000000000..4c2b00d252 --- /dev/null +++ b/httpie/output/lexers/http.py @@ -0,0 +1,49 @@ +import pygments + + +class SimplifiedHTTPLexer(pygments.lexer.RegexLexer): + """Simplified HTTP lexer for Pygments. + + It only operates on headers and provides a stronger contrast between + their names and values than the original one bundled with Pygments + (:class:`pygments.lexers.text import HttpLexer`), especially when + Solarized color scheme is used. + + """ + name = 'HTTP' + aliases = ['http'] + filenames = ['*.http'] + tokens = { + 'root': [ + # Request-Line + (r'([A-Z]+)( +)([^ ]+)( +)(HTTP)(/)(\d+\.\d+)', + pygments.lexer.bygroups( + pygments.token.Name.Function, + pygments.token.Text, + pygments.token.Name.Namespace, + pygments.token.Text, + pygments.token.Keyword.Reserved, + pygments.token.Operator, + pygments.token.Number + )), + # Response Status-Line + (r'(HTTP)(/)(\d+\.\d+)( +)(\d{3})( +)(.+)', + pygments.lexer.bygroups( + pygments.token.Keyword.Reserved, # 'HTTP' + pygments.token.Operator, # '/' + pygments.token.Number, # Version + pygments.token.Text, + pygments.token.Number, # Status code + pygments.token.Text, + pygments.token.Name.Exception, # Reason + )), + # Header + (r'(.*?)( *)(:)( *)(.+)', pygments.lexer.bygroups( + pygments.token.Name.Attribute, # Name + pygments.token.Text, + pygments.token.Operator, # Colon + pygments.token.Text, + pygments.token.String # Value + )) + ] + } diff --git a/httpie/output/lexers/json.py b/httpie/output/lexers/json.py new file mode 100644 index 0000000000..a235c4f3a3 --- /dev/null +++ b/httpie/output/lexers/json.py @@ -0,0 +1,31 @@ +import re + +from pygments.lexer import bygroups, using, RegexLexer +from pygments.lexers.data import JsonLexer +from pygments.token import Token + +PREFIX_TOKEN = Token.Error +PREFIX_REGEX = r'[^{\["]+' + + +class EnhancedJsonLexer(RegexLexer): + """ + Enhanced JSON lexer for Pygments. + + It adds support for eventual data prefixing the actual JSON body. + + """ + name = 'JSON' + flags = re.IGNORECASE | re.DOTALL + tokens = { + 'root': [ + # Eventual non-JSON data prefix followed by actual JSON body. + # FIX: data prefix + number (integer or float) are not correctly handled. + ( + fr'({PREFIX_REGEX})' + r'((?:[{\["]|true|false|null).+)', + bygroups(PREFIX_TOKEN, using(JsonLexer)) + ), + # JSON body. + (r'.+', using(JsonLexer)), + ], + } diff --git a/httpie/output/utils.py b/httpie/output/utils.py new file mode 100644 index 0000000000..5ae7f603d5 --- /dev/null +++ b/httpie/output/utils.py @@ -0,0 +1,36 @@ +import json +import re +from typing import Tuple + +from .lexers.json import PREFIX_REGEX + + +def load_prefixed_json(data: str) -> Tuple[str, json.JSONDecoder]: + """Simple JSON loading from `data`. + + """ + # First, the full data. + try: + return '', json.loads(data) + except ValueError: + pass + + # Then, try to find the start of the actual body. + data_prefix, body = parse_prefixed_json(data) + try: + return data_prefix, json.loads(body) + except ValueError: + raise ValueError('Invalid JSON') + + +def parse_prefixed_json(data: str) -> Tuple[str, str]: + """Find the potential JSON body from `data`. + + Sometimes the JSON body is prefixed with a XSSI magic string, specific to the server. + Return a tuple (data prefix, actual JSON body). + + """ + matches = re.findall(PREFIX_REGEX, data) + data_prefix = matches[0] if matches else '' + body = data[len(data_prefix):] + return data_prefix, body diff --git a/tests/test_json.py b/tests/test_json.py new file mode 100644 index 0000000000..4d210f23e0 --- /dev/null +++ b/tests/test_json.py @@ -0,0 +1,40 @@ +import json + +import pytest +import responses + +from httpie.cli.constants import PRETTY_MAP +from httpie.compat import is_windows +from httpie.output.formatters.colors import ColorFormatter + +from .utils import MockEnvironment, http, URL_EXAMPLE + +TEST_JSON_XXSI_PREFIXES = (r")]}',\n", ")]}',", 'while(1);', 'for(;;)', ')', ']', '}') +TEST_JSON_VALUES = ({}, {'a': 0, 'b': 0}, [], ['a', 'b'], 'foo', True, False, None) # FIX: missing int & float +TEST_PREFIX_TOKEN_COLOR = '\x1b[38;5;15m' if is_windows else '\x1b[04m\x1b[91m' + + +@pytest.mark.parametrize('data_prefix', TEST_JSON_XXSI_PREFIXES) +@pytest.mark.parametrize('json_data', TEST_JSON_VALUES) +@pytest.mark.parametrize('pretty', PRETTY_MAP.keys()) +@responses.activate +def test_json_formatter_with_body_preceded_by_non_json_data(data_prefix, json_data, pretty): + """Test JSON bodies preceded by non-JSON data.""" + body = data_prefix + json.dumps(json_data) + content_type = 'application/json' + responses.add(responses.GET, URL_EXAMPLE, body=body, + content_type=content_type) + + colored_output = pretty in ('all', 'colors') + env = MockEnvironment(colors=256) if colored_output else None + r = http('--pretty=' + pretty, URL_EXAMPLE, env=env) + + indent = None if pretty in ('none', 'colors') else 4 + expected_body = data_prefix + json.dumps(json_data, indent=indent) + if colored_output: + fmt = ColorFormatter(env, format_options={'json': {'format': True, 'indent': 4}}) + expected_body = fmt.format_body(expected_body, content_type) + # Check to ensure the non-JSON data prefix is colored only one time, + # meaning it was correctly handled as a whole. + assert TEST_PREFIX_TOKEN_COLOR + data_prefix in expected_body, expected_body + assert expected_body in r From d7ed45bbcda825af558c44b6b41eff4f99a092e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 21 Sep 2021 19:07:59 +0200 Subject: [PATCH 0822/1182] Fix duplicate keys preservation of JSON data (#1163) * Fix duplicate keys preservation of JSON data * Update issue number * Fix type annotations * Changes after review * Rewording --- CHANGELOG.md | 1 + httpie/cli/requestitems.py | 4 +- httpie/output/utils.py | 5 ++- httpie/utils.py | 58 +++++++++++++++++++++++-- tests/fixtures/__init__.py | 1 + tests/fixtures/test_with_dupe_keys.json | 1 + tests/test_cli.py | 29 ++++++------- tests/test_json.py | 48 ++++++++++++++++++++ 8 files changed, 124 insertions(+), 23 deletions(-) create mode 100644 tests/fixtures/test_with_dupe_keys.json diff --git a/CHANGELOG.md b/CHANGELOG.md index ec56074ab6..ee0a89f6d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.6.0.dev0](https://github.com/httpie/httpie/compare/2.5.0...master) (unreleased) +- Fixed duplicate keys preservation of JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163)) - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) ## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06) diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index 30b4956274..1dd6594ccd 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -15,7 +15,7 @@ RequestQueryParamsDict, ) from .exceptions import ParseError -from ..utils import get_content_type, load_json_preserve_order +from ..utils import get_content_type, load_json_preserve_order_and_dupe_keys class RequestItems: @@ -150,6 +150,6 @@ def load_text_file(item: KeyValueArg) -> str: def load_json(arg: KeyValueArg, contents: str) -> JSONType: try: - return load_json_preserve_order(contents) + return load_json_preserve_order_and_dupe_keys(contents) except ValueError as e: raise ParseError(f'{arg.orig!r}: {e}') diff --git a/httpie/output/utils.py b/httpie/output/utils.py index 5ae7f603d5..875e885586 100644 --- a/httpie/output/utils.py +++ b/httpie/output/utils.py @@ -2,6 +2,7 @@ import re from typing import Tuple +from ..utils import load_json_preserve_order_and_dupe_keys from .lexers.json import PREFIX_REGEX @@ -11,14 +12,14 @@ def load_prefixed_json(data: str) -> Tuple[str, json.JSONDecoder]: """ # First, the full data. try: - return '', json.loads(data) + return '', load_json_preserve_order_and_dupe_keys(data) except ValueError: pass # Then, try to find the start of the actual body. data_prefix, body = parse_prefixed_json(data) try: - return data_prefix, json.loads(body) + return data_prefix, load_json_preserve_order_and_dupe_keys(body) except ValueError: raise ValueError('Invalid JSON') diff --git a/httpie/utils.py b/httpie/utils.py index 7c8a598ce8..c155aac503 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -1,19 +1,69 @@ import json import mimetypes +import re +import sys import time from collections import OrderedDict from http.cookiejar import parse_ns_headers from pprint import pformat -from typing import List, Optional, Tuple -import re +from typing import Any, List, Optional, Tuple import requests.auth RE_COOKIE_SPLIT = re.compile(r', (?=[^ ;]+=)') +Item = Tuple[str, Any] +Items = List[Item] + + +class JsonDictPreservingDuplicateKeys(OrderedDict): + """A specialized JSON dict preserving duplicate keys. + + """ + + # Python versions prior to 3.8 suffer from an issue with multiple keys with the same name. + # `json.dumps(obj, indent=N, sort_keys=True)` will output sorted keys when they are unique, and + # duplicate keys will be outputted as they were defined in the original data. + # See for the behavior change between Python versions. + SUPPORTS_SORTING = sys.version_info >= (3, 8) + + def __init__(self, items: Items): + self._items = items + self._ensure_items_used() + + def _ensure_items_used(self) -> None: + """HACK: Force `json.dumps()` to use `self.items()` instead of an empty dict. + + Two JSON encoders are available on CPython: pure-Python (1) and C (2) implementations. + + (1) The pure-python implementation will do a simple `if not dict: return '{}'`, + and we could fake that check by implementing the `__bool__()` method. + Source: + - + + (2) On the other hand, the C implementation will do a check on the number of + items contained inside the dict, using a verification on `dict->ma_used`, which + is updated only when an item is added/removed from the dict. For that case, + there is no workaround but to add an item into the dict. + Sources: + - + - + - + + To please both implementations, we simply add one item to the dict. + + """ + if self._items: + self['__hack__'] = '__hack__' + + def items(self) -> Items: + """Return all items, duplicate ones included. + + """ + return self._items -def load_json_preserve_order(s): - return json.loads(s, object_pairs_hook=OrderedDict) +def load_json_preserve_order_and_dupe_keys(s): + return json.loads(s, object_pairs_hook=JsonDictPreservingDuplicateKeys) def repr_dict(d: dict) -> str: diff --git a/tests/fixtures/__init__.py b/tests/fixtures/__init__.py index ca1f0337fd..cf979e5f11 100644 --- a/tests/fixtures/__init__.py +++ b/tests/fixtures/__init__.py @@ -16,6 +16,7 @@ def patharg(path): FIXTURES_ROOT = Path(__file__).parent FILE_PATH = FIXTURES_ROOT / 'test.txt' JSON_FILE_PATH = FIXTURES_ROOT / 'test.json' +JSON_WITH_DUPE_KEYS_FILE_PATH = FIXTURES_ROOT / 'test_with_dupe_keys.json' BIN_FILE_PATH = FIXTURES_ROOT / 'test.bin' XML_FILES_PATH = FIXTURES_ROOT / 'xmldata' XML_FILES_VALID = list((XML_FILES_PATH / 'valid').glob('*_raw.xml')) diff --git a/tests/fixtures/test_with_dupe_keys.json b/tests/fixtures/test_with_dupe_keys.json new file mode 100644 index 0000000000..480d789078 --- /dev/null +++ b/tests/fixtures/test_with_dupe_keys.json @@ -0,0 +1 @@ +{"key":15,"key":15,"key":3,"key":7} diff --git a/tests/test_cli.py b/tests/test_cli.py index 6d4998f936..f2a7260ffa 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,20 +1,21 @@ """CLI argument parsing related tests.""" import argparse -import json import pytest from requests.exceptions import InvalidSchema import httpie.cli.argparser -from .fixtures import ( - FILE_CONTENT, FILE_PATH, FILE_PATH_ARG, JSON_FILE_CONTENT, - JSON_FILE_PATH_ARG, -) -from httpie.status import ExitStatus from httpie.cli import constants from httpie.cli.definition import parser from httpie.cli.argtypes import KeyValueArg, KeyValueArgType from httpie.cli.requestitems import RequestItems +from httpie.status import ExitStatus +from httpie.utils import load_json_preserve_order_and_dupe_keys + +from .fixtures import ( + FILE_CONTENT, FILE_PATH, FILE_PATH_ARG, JSON_FILE_CONTENT, + JSON_FILE_PATH_ARG, +) from .utils import HTTP_OK, MockEnvironment, StdinBytesIO, http @@ -97,17 +98,15 @@ def test_valid_items(self): # Parsed data raw_json_embed = items.data.pop('raw-json-embed') - assert raw_json_embed == json.loads(JSON_FILE_CONTENT) + assert raw_json_embed == load_json_preserve_order_and_dupe_keys(JSON_FILE_CONTENT) items.data['string-embed'] = items.data['string-embed'].strip() assert dict(items.data) == { - "ed": "", - "string": "value", - "bool": True, - "list": ["a", 1, {}, False], - "obj": { - "a": "b" - }, - "string-embed": FILE_CONTENT, + 'ed': '', + 'string': 'value', + 'bool': True, + 'list': ['a', 1, {}, False], + 'obj': load_json_preserve_order_and_dupe_keys('{"a": "b"}'), + 'string-embed': FILE_CONTENT, } # Parsed query string parameters diff --git a/tests/test_json.py b/tests/test_json.py index 4d210f23e0..8d73c77965 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -6,13 +6,29 @@ from httpie.cli.constants import PRETTY_MAP from httpie.compat import is_windows from httpie.output.formatters.colors import ColorFormatter +from httpie.utils import JsonDictPreservingDuplicateKeys +from .fixtures import JSON_WITH_DUPE_KEYS_FILE_PATH from .utils import MockEnvironment, http, URL_EXAMPLE TEST_JSON_XXSI_PREFIXES = (r")]}',\n", ")]}',", 'while(1);', 'for(;;)', ')', ']', '}') TEST_JSON_VALUES = ({}, {'a': 0, 'b': 0}, [], ['a', 'b'], 'foo', True, False, None) # FIX: missing int & float TEST_PREFIX_TOKEN_COLOR = '\x1b[38;5;15m' if is_windows else '\x1b[04m\x1b[91m' +JSON_WITH_DUPES_RAW = '{"key": 15, "key": 15, "key": 3, "key": 7}' +JSON_WITH_DUPES_FORMATTED_SORTED = '''{ + "key": 3, + "key": 7, + "key": 15, + "key": 15 +}''' +JSON_WITH_DUPES_FORMATTED_UNSORTED = '''{ + "key": 15, + "key": 15, + "key": 3, + "key": 7 +}''' + @pytest.mark.parametrize('data_prefix', TEST_JSON_XXSI_PREFIXES) @pytest.mark.parametrize('json_data', TEST_JSON_VALUES) @@ -38,3 +54,35 @@ def test_json_formatter_with_body_preceded_by_non_json_data(data_prefix, json_da # meaning it was correctly handled as a whole. assert TEST_PREFIX_TOKEN_COLOR + data_prefix in expected_body, expected_body assert expected_body in r + + +@responses.activate +def test_duplicate_keys_support_from_response(): + """JSON with duplicate keys should be handled correctly.""" + responses.add(responses.GET, URL_EXAMPLE, body=JSON_WITH_DUPES_RAW, + content_type='application/json') + args = ('--pretty', 'format', URL_EXAMPLE) + + # Check implicit --sorted + if JsonDictPreservingDuplicateKeys.SUPPORTS_SORTING: + r = http(*args) + assert JSON_WITH_DUPES_FORMATTED_SORTED in r + + # Check --unsorted + r = http(*args, '--unsorted') + assert JSON_WITH_DUPES_FORMATTED_UNSORTED in r + + +def test_duplicate_keys_support_from_input_file(): + """JSON file with duplicate keys should be handled correctly.""" + args = ('--verbose', '--offline', URL_EXAMPLE, + f'@{JSON_WITH_DUPE_KEYS_FILE_PATH}') + + # Check implicit --sorted + if JsonDictPreservingDuplicateKeys.SUPPORTS_SORTING: + r = http(*args) + assert JSON_WITH_DUPES_FORMATTED_SORTED in r + + # Check --unsorted + r = http(*args, '--unsorted') + assert JSON_WITH_DUPES_FORMATTED_UNSORTED in r From 507514b7958fe2e65ad8466fc4039c54093d7a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 23 Sep 2021 10:37:23 +0200 Subject: [PATCH 0823/1182] Add workflow to test with pyOpenSSL active (#1164) * Add workflow to test with pyOpenSSL active Original patch by @gmelodie. * Fix tests on Windows with Python 3.6 --- .github/workflows/tests.yml | 5 +++++ setup.py | 1 + tests/conftest.py | 18 ++++++++++++++++++ tests/test_ssl.py | 18 +++++++++++++++++- 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ae532223b8..ff164f9bc4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,6 +21,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: [3.6, 3.7, 3.8, 3.9, "3.10.0-rc.2"] + pyopenssl: [0, 1] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 @@ -33,8 +34,12 @@ jobs: python -m pip install --upgrade pip wheel python -m pip install --upgrade '.[dev]' python -m pytest --verbose ./httpie ./tests + env: + HTTPIE_TEST_WITH_PYOPENSSL: ${{ matrix.pyopenssl }} - name: Linux & Mac setup if: matrix.os != 'windows-latest' run: | make install make test + env: + HTTPIE_TEST_WITH_PYOPENSSL: ${{ matrix.pyopenssl }} diff --git a/setup.py b/setup.py index acde80a0eb..22c14212c2 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,7 @@ 'flake8-deprecated', 'flake8-mutable', 'flake8-tuple', + 'pyopenssl', 'pytest-cov', 'twine', 'wheel', diff --git a/tests/conftest.py b/tests/conftest.py index ff79ed174b..a65df162f5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,6 @@ +import os import socket + import pytest from pytest_httpbin import certs @@ -41,3 +43,19 @@ def httpbin_with_chunked_support(_httpbin_with_chunked_support_available): if _httpbin_with_chunked_support_available: return HTTPBIN_WITH_CHUNKED_SUPPORT pytest.skip(f'{HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN} not resolvable') + + +@pytest.fixture(autouse=True, scope='session') +def pyopenssl_inject(): + """ + Injects `pyOpenSSL` module to make sure `requests` will use it. + + """ + if os.getenv('HTTPIE_TEST_WITH_PYOPENSSL', '0') == '1': + try: + import urllib3.contrib.pyopenssl + urllib3.contrib.pyopenssl.inject_into_urllib3() + except ModuleNotFoundError: + pytest.fail('Missing "pyopenssl" module.') + + yield diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 7b3807d9d9..e71924488a 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -1,11 +1,14 @@ +import os +import ssl + import pytest import pytest_httpbin.certs import requests.exceptions -import ssl import urllib3 from httpie.ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS from httpie.status import ExitStatus + from .utils import HTTP_OK, TESTS_ROOT, http @@ -17,6 +20,7 @@ ssl_errors = ( requests.exceptions.SSLError, OpenSSL.SSL.Error, + ValueError, # TODO: Remove with OSS-65 ) except ImportError: ssl_errors = ( @@ -54,6 +58,8 @@ def test_ssl_version(httpbin_secure, ssl_version): root = root.__context__ if isinstance(root, ssl.SSLError) and root.reason == "TLSV1_ALERT_PROTOCOL_VERSION": pytest.skip(f'Unsupported TLS version: {ssl_version}') + elif 'No such protocol' in str(e): # TODO: Remove with OSS-65 + pytest.skip(f'Unsupported TLS version: {ssl_version}') else: raise @@ -149,3 +155,13 @@ def test_ciphers_none_can_be_selected(httpbin_secure): # # http: error: Error: [('SSL routines', '(UNKNOWN)SSL_internal', 'no cipher match')] assert 'cipher' in r.stderr + + +def test_pyopenssl_presence(): + using_pyopenssl = os.getenv('HTTPIE_TEST_WITH_PYOPENSSL', '0') + if using_pyopenssl == '0': + assert not urllib3.util.ssl_.IS_PYOPENSSL + assert not urllib3.util.IS_PYOPENSSL + else: + assert urllib3.util.ssl_.IS_PYOPENSSL + assert urllib3.util.IS_PYOPENSSL From cae83b3f9e2077afee85992e8135cae70bb91cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 23 Sep 2021 10:46:06 +0200 Subject: [PATCH 0824/1182] Add FreeBSD installation instructions Closes #761. --- docs/README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 02383417c6..7f63101105 100644 --- a/docs/README.md +++ b/docs/README.md @@ -34,7 +34,7 @@ You are invited to submit fixes and improvements to the docs by editing [this fi - Custom headers - Persistent sessions - Wget-like downloads -- Linux, macOS and Windows support +- Linux, macOS, Windows, and FreeBSD support - Plugins - Documentation - Test coverage @@ -102,9 +102,18 @@ $ apk add httpie $ eopkg install httpie ``` +### FreeBSD + +On FreeBSD, HTTPie is available in the ports collection. A prebuilt package +can be installed via [pkg(8)](https://man.freebsd.org/pkg/8>): + +```bash +$ pkg install www/py-httpie +``` + ### Windows, universal -A universal installation method (that works on Linux, macOS and Windows, and always provides the latest version) is to use [pip](https://pypi.org/project/pip/): +A universal installation method (that works on Linux, macOS, Windows, FreeBSD, and always provides the latest version) is to use [pip](https://pypi.org/project/pip/): ```bash # Make sure we have an up-to-date version of pip and setuptools: @@ -131,7 +140,7 @@ Python version 3.6 or greater is required. 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. -You can install it on Linux, macOS or Windows with `pip`: +You can install it on Linux, macOS, Windows, or FreeBSD with `pip`: ```bash $ python -m pip install --upgrade https://github.com/httpie/httpie/archive/master.tar.gz From 1535d0c9768f2a6a0c031cc09eecb589b599c13a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 23 Sep 2021 12:27:03 +0200 Subject: [PATCH 0825/1182] Mention XML when explaining formatting --- docs/README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index 7f63101105..8814114bf9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1191,12 +1191,6 @@ There are dozens of styles available, here are just a few notable ones: | `fruity` | A bold, colorful scheme. Enable with `--style=fruity` | | … | See `$ http --help` for all the possible `--style` values | -Also, the following formatting is applied: - -- HTTP headers are sorted by name. -- JSON data is indented, sorted by keys, and unicode escapes are converted - to the characters they represent. - Use one of these options to control output processing: | Option | Description | @@ -1206,6 +1200,14 @@ Use one of these options to control output processing: | `--pretty=format` | Apply formatting | | `--pretty=none` | Disables output processing. Default for redirected output | + +Formatting has the following effects: + +- HTTP headers are sorted by name. +- JSON data is indented, sorted by keys, and unicode escapes are converted + to the characters they represent. +- XML and XHTML data is indented. + You can further control the applied formatting via the more granular [format options](#format-options). ### Format options From 474093acdf4d3724d54620637fc0f93f787ba7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 23 Sep 2021 17:15:14 +0200 Subject: [PATCH 0826/1182] Include plugin info in `--debug` output (#1165) * Include plugin info in `--debug` output * Adapt issue number * Fix docs --- CHANGELOG.md | 1 + docs/README.md | 1 - httpie/core.py | 2 ++ httpie/plugins/manager.py | 11 ++++++++++- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee0a89f6d4..ecdc4f489c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed duplicate keys preservation of JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163)) - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) +- Installed plugins are now listed in `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165)) ## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06) diff --git a/docs/README.md b/docs/README.md index 8814114bf9..c578afad15 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1200,7 +1200,6 @@ Use one of these options to control output processing: | `--pretty=format` | Apply formatting | | `--pretty=none` | Disables output processing. Default for redirected output | - Formatting has the following effects: - HTTP headers are sorted by name. diff --git a/httpie/core.py b/httpie/core.py index 9c9e3ce406..c3567219be 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -227,6 +227,8 @@ def print_debug_info(env: Environment): ]) env.stderr.write('\n\n') env.stderr.write(repr(env)) + env.stderr.write('\n\n') + env.stderr.write(repr(plugin_manager)) env.stderr.write('\n') diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index 23acd53f8b..420fb36bf2 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -4,6 +4,7 @@ from pkg_resources import iter_entry_points +from ..utils import repr_dict from . import AuthPlugin, ConverterPlugin, FormatterPlugin from .base import BasePlugin, TransportPlugin @@ -65,5 +66,13 @@ def get_converters(self) -> List[Type[ConverterPlugin]]: def get_transport_plugins(self) -> List[Type[TransportPlugin]]: return self.filter(TransportPlugin) + def __str__(self): + return repr_dict({ + 'adapters': self.get_transport_plugins(), + 'auth': self.get_auth_plugins(), + 'converters': self.get_converters(), + 'formatters': self.get_formatters(), + }) + def __repr__(self): - return f'' + return f'<{type(self).__name__} {self}>' From bce2b3a98e7a680e363e07f629ba9c3819926541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 23 Sep 2021 17:17:29 +0200 Subject: [PATCH 0827/1182] Sort changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecdc4f489c..ad89327c07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.6.0.dev0](https://github.com/httpie/httpie/compare/2.5.0...master) (unreleased) -- Fixed duplicate keys preservation of JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163)) - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) - Installed plugins are now listed in `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165)) +- Fixed duplicate keys preservation of JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163)) ## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06) From 8f8851f1dbd511d3bc0ea0f6da7459045610afce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Fri, 24 Sep 2021 10:37:59 +0200 Subject: [PATCH 0828/1182] Remove trailing comma in test --- tests/test_binary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_binary.py b/tests/test_binary.py index 2c39a89c85..ca51aa1686 100644 --- a/tests/test_binary.py +++ b/tests/test_binary.py @@ -21,7 +21,7 @@ def test_binary_stdin(self, httpbin): def test_binary_file_path(self, httpbin): env = MockEnvironment(stdin_isatty=True, stdout_isatty=False) r = http('--print=B', 'POST', httpbin.url + '/post', - '@' + BIN_FILE_PATH_ARG, env=env, ) + '@' + BIN_FILE_PATH_ARG, env=env) assert r == BIN_FILE_CONTENT def test_binary_file_form(self, httpbin): From 9c89c703ae6bee1168e2d4895bd9a5dcde68de37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 27 Sep 2021 13:58:19 +0200 Subject: [PATCH 0829/1182] Allow to overwrite the response Content-Type from options (#1134) * Allow to override the response `Content-Type` from options * Apply suggestions from code review Co-authored-by: Jakub Roztocil * Rename the option from `--response.content-type` to `--response-as` * Update CHANGELOG.md Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 2 ++ docs/README.md | 29 ++++++++++++----- httpie/cli/argparser.py | 5 ++- httpie/cli/constants.py | 2 ++ httpie/cli/definition.py | 14 +++++++++ httpie/output/processing.py | 1 + httpie/output/streams.py | 15 +++++++-- httpie/output/utils.py | 54 +++++++++++++++++++++++++++++++ tests/test_output.py | 19 +++++++++++ tests/test_xml.py | 63 ++++++++++++++++++++++++++++++++++--- 10 files changed, 187 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad89327c07..ca49cefb7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.6.0.dev0](https://github.com/httpie/httpie/compare/2.5.0...master) (unreleased) - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) +- Added `--format-options=response.as:CONTENT_TYPE` to allow overriding the response `Content-Type`. ([#1134](https://github.com/httpie/httpie/issues/1134)) +- Added `--response-as` shortcut for setting the response `Content-Type`-related `--format-options`. ([#1134](https://github.com/httpie/httpie/issues/1134)) - Installed plugins are now listed in `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165)) - Fixed duplicate keys preservation of JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163)) diff --git a/docs/README.md b/docs/README.md index c578afad15..d4cfd53382 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1214,14 +1214,15 @@ You can further control the applied formatting via the more granular [format opt The `--format-options=opt1:value,opt2:value` option allows you to control how the output should be formatted when formatting is applied. The following options are available: -| Option | Default value | Shortcuts | -| ---------------: | :-----------: | ------------------------ | -| `headers.sort` | `true` | `--sorted`, `--unsorted` | -| `json.format` | `true` | N/A | -| `json.indent` | `4` | N/A | -| `json.sort_keys` | `true` | `--sorted`, `--unsorted` | -| `xml.format` | `true` | N/A | -| `xml.indent` | `2` | N/A | +| Option | Default value | Shortcuts | +| ---------------: | :-----------: | ----------------------------------------- | +| `headers.sort` | `true` | `--sorted`, `--unsorted` | +| `json.format` | `true` | N/A | +| `json.indent` | `4` | N/A | +| `json.sort_keys` | `true` | `--sorted`, `--unsorted` | +| `response.as` | `''` | [`--response-as`](#response-content-type) | +| `xml.format` | `true` | N/A | +| `xml.indent` | `2` | N/A | For example, this is how you would disable the default header and JSON key sorting, and specify a custom JSON indent size: @@ -1236,6 +1237,18 @@ sorting-related format options (currently it means JSON keys and headers): This is something you will typically store as one of the default options in your [config](#config) file. +#### Response `Content-Type` + +The `--response-as=value` option is a shortcut for `--format-options response.as:value`, +and it allows you to override the response `Content-Type` sent by the server. +That makes it possible for HTTPie to pretty-print the response even when the server specifies the type incorrectly. + +For example, the following request will force the response to be treated as XML: + +```bash +$ http --response-as=application/xml pie.dev/get +``` + ### Binary data Binary data is suppressed for terminal output, which makes it safe to perform requests to URLs that send back binary data. diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index d3b2fe7eea..5456330e54 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -457,7 +457,10 @@ def _process_download_options(self): self.error('--continue requires --output to be specified') def _process_format_options(self): + format_options = self.args.format_options or [] + if self.args.response_as is not None: + format_options.append('response.as:' + self.args.response_as) parsed_options = PARSED_DEFAULT_FORMAT_OPTIONS - for options_group in self.args.format_options or []: + for options_group in format_options: parsed_options = parse_format_options(options_group, defaults=parsed_options) self.args.format_options = parsed_options diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index a1b78d33b2..969a2d6079 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -85,11 +85,13 @@ PRETTY_STDOUT_TTY_ONLY = object() +EMPTY_FORMAT_OPTION = "''" DEFAULT_FORMAT_OPTIONS = [ 'headers.sort:true', 'json.format:true', 'json.indent:4', 'json.sort_keys:true', + 'response.as:' + EMPTY_FORMAT_OPTION, 'xml.format:true', 'xml.indent:2', ] diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 28ca35ea6a..ab059dafaa 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -309,6 +309,20 @@ ''' ) +output_processing.add_argument( + '--response-as', + metavar='CONTENT_TYPE', + help=''' + Override the response Content-Type for formatting purposes, e.g.: + + --response-as=application/xml + + It is a shortcut for: + + --format-options=response.as:CONTENT_TYPE + ''' +) + output_processing.add_argument( '--format-options', diff --git a/httpie/output/processing.py b/httpie/output/processing.py index ddee9ca9c3..25d9c45ab1 100644 --- a/httpie/output/processing.py +++ b/httpie/output/processing.py @@ -33,6 +33,7 @@ def __init__(self, groups: List[str], env=Environment(), **kwargs): :param kwargs: additional keyword arguments for processors """ + self.options = kwargs['format_options'] available_plugins = plugin_manager.get_formatters_grouped() self.enabled_plugins = [] for group in groups: diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 44269e3b90..9bb646bfae 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -2,11 +2,12 @@ from itertools import chain from typing import Callable, Iterable, Union +from ..cli.constants import EMPTY_FORMAT_OPTION from ..context import Environment from ..constants import UTF8 -from ..models import HTTPMessage +from ..models import HTTPMessage, HTTPResponse from .processing import Conversion, Formatting - +from .utils import parse_header_content_type BINARY_SUPPRESSED_NOTICE = ( b'\n' @@ -136,7 +137,15 @@ def __init__( super().__init__(**kwargs) self.formatting = formatting self.conversion = conversion - self.mime = self.msg.content_type.split(';')[0] + self.mime = self.get_mime() + + def get_mime(self) -> str: + mime = parse_header_content_type(self.msg.content_type)[0] + if isinstance(self.msg, HTTPResponse): + forced_content_type = self.formatting.options['response']['as'] + if forced_content_type != EMPTY_FORMAT_OPTION: + mime = parse_header_content_type(forced_content_type)[0] or mime + return mime def get_headers(self) -> bytes: return self.formatting.format_headers( diff --git a/httpie/output/utils.py b/httpie/output/utils.py index 875e885586..f53aab215b 100644 --- a/httpie/output/utils.py +++ b/httpie/output/utils.py @@ -35,3 +35,57 @@ def parse_prefixed_json(data: str) -> Tuple[str, str]: data_prefix = matches[0] if matches else '' body = data[len(data_prefix):] return data_prefix, body + + +def parse_header_content_type(line): + """Parse a Content-Type like header. + Return the main Content-Type and a dictionary of options. + >>> parse_header_content_type('application/xml; charset=utf-8') + ('application/xml', {'charset': 'utf-8'}) + >>> parse_header_content_type('application/xml; charset = utf-8') + ('application/xml', {'charset': 'utf-8'}) + >>> parse_header_content_type('application/html+xml;ChArSeT="UTF-8"') + ('application/html+xml', {'charset': 'UTF-8'}) + >>> parse_header_content_type('application/xml') + ('application/xml', {}) + >>> parse_header_content_type(';charset=utf-8') + ('', {'charset': 'utf-8'}) + >>> parse_header_content_type('charset=utf-8') + ('', {'charset': 'utf-8'}) + >>> parse_header_content_type('multipart/mixed; boundary="gc0pJq0M:08jU534c0p"') + ('multipart/mixed', {'boundary': 'gc0pJq0M:08jU534c0p'}) + >>> parse_header_content_type('Message/Partial; number=3; total=3; id="oc=jpbe0M2Yt4s@foo.com"') + ('Message/Partial', {'number': '3', 'total': '3', 'id': 'oc=jpbe0M2Yt4s@foo.com'}) + """ + # Source: https://github.com/python/cpython/blob/bb3e0c2/Lib/cgi.py#L230 + + def _parseparam(s: str): + # Source: https://github.com/python/cpython/blob/bb3e0c2/Lib/cgi.py#L218 + while s[:1] == ';': + s = s[1:] + end = s.find(';') + while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2: + end = s.find(';', end + 1) + if end < 0: + end = len(s) + f = s[:end] + yield f.strip() + s = s[end:] + + # Special case: 'key=value' only (without starting with ';'). + if ';' not in line and '=' in line: + line = ';' + line + + parts = _parseparam(';' + line) + key = parts.__next__() + pdict = {} + for p in parts: + i = p.find('=') + if i >= 0: + name = p[:i].strip().lower() + value = p[i + 1:].strip() + if len(value) >= 2 and value[0] == value[-1] == '"': + value = value[1:-1] + value = value.replace('\\\\', '\\').replace('\\"', '"') + pdict[name] = value + return key, pdict diff --git a/tests/test_output.py b/tests/test_output.py index 0d0ee2f01b..dfa202285a 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -377,6 +377,9 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 10, 'format': True }, + 'response': { + 'as': "''", + }, 'xml': { 'format': True, 'indent': 2, @@ -396,6 +399,9 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 4, 'format': True }, + 'response': { + 'as': "''", + }, 'xml': { 'format': True, 'indent': 2, @@ -417,6 +423,9 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 4, 'format': True }, + 'response': { + 'as': "''", + }, 'xml': { 'format': True, 'indent': 2, @@ -435,6 +444,7 @@ def test_parse_format_options_errors(self, options_string, expected_error): ( [ '--format-options=json.indent:2', + '--format-options=response.as:application/xml; charset=utf-8', '--format-options=xml.format:false', '--format-options=xml.indent:4', '--unsorted', @@ -449,6 +459,9 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 2, 'format': True }, + 'response': { + 'as': 'application/xml; charset=utf-8', + }, 'xml': { 'format': False, 'indent': 4, @@ -470,6 +483,9 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 2, 'format': True }, + 'response': { + 'as': "''", + }, 'xml': { 'format': True, 'indent': 2, @@ -492,6 +508,9 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 2, 'format': True }, + 'response': { + 'as': "''", + }, 'xml': { 'format': True, 'indent': 2, diff --git a/tests/test_xml.py b/tests/test_xml.py index 7c35221925..43a6d8fb76 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -9,20 +9,21 @@ from .fixtures import XML_FILES_PATH, XML_FILES_VALID, XML_FILES_INVALID from .utils import http, URL_EXAMPLE -SAMPLE_XML_DATA = 'text' +XML_DATA_RAW = 'text' +XML_DATA_FORMATTED = pretty_xml(parse_xml(XML_DATA_RAW)) @pytest.mark.parametrize( 'options, expected_xml', [ - ('xml.format:false', SAMPLE_XML_DATA), - ('xml.indent:2', pretty_xml(parse_xml(SAMPLE_XML_DATA))), - ('xml.indent:4', pretty_xml(parse_xml(SAMPLE_XML_DATA), indent=4)), + ('xml.format:false', XML_DATA_RAW), + ('xml.indent:2', XML_DATA_FORMATTED), + ('xml.indent:4', pretty_xml(parse_xml(XML_DATA_RAW), indent=4)), ] ) @responses.activate def test_xml_format_options(options, expected_xml): - responses.add(responses.GET, URL_EXAMPLE, body=SAMPLE_XML_DATA, + responses.add(responses.GET, URL_EXAMPLE, body=XML_DATA_RAW, content_type='application/xml') r = http('--format-options', options, URL_EXAMPLE) @@ -83,3 +84,55 @@ def test_invalid_xml(file): # No formatting done, data is simply printed as-is r = http(URL_EXAMPLE) assert xml_data in r + + +@responses.activate +def test_content_type_from_format_options_argument(): + """Test XML response with a incorrect Content-Type header. + Using the --format-options to force the good one. + """ + responses.add(responses.GET, URL_EXAMPLE, body=XML_DATA_RAW, + content_type='plain/text') + args = ('--format-options', 'response.as:application/xml', + URL_EXAMPLE) + + # Ensure the option is taken into account only for responses. + # Request + r = http('--offline', '--raw', XML_DATA_RAW, *args) + assert XML_DATA_RAW in r + + # Response + r = http(*args) + assert XML_DATA_FORMATTED in r + + +@responses.activate +def test_content_type_from_shortcut_argument(): + """Test XML response with a incorrect Content-Type header. + Using the --format-options shortcut to force the good one. + """ + responses.add(responses.GET, URL_EXAMPLE, body=XML_DATA_RAW, + content_type='text/plain') + args = ('--response-as', 'application/xml', URL_EXAMPLE) + + # Ensure the option is taken into account only for responses. + # Request + r = http('--offline', '--raw', XML_DATA_RAW, *args) + assert XML_DATA_RAW in r + + # Response + r = http(*args) + assert XML_DATA_FORMATTED in r + + +@responses.activate +def test_content_type_from_incomplete_format_options_argument(): + """Test XML response with a incorrect Content-Type header. + Using the --format-options to use a partial Content-Type without mime type. + """ + responses.add(responses.GET, URL_EXAMPLE, body=XML_DATA_RAW, + content_type='text/plain') + + # The provided Content-Type is simply ignored, and so no formatting is done. + r = http('--response-as', 'charset=utf-8', URL_EXAMPLE) + assert XML_DATA_RAW in r From 727b8a2c05c34a3c89bd408d20decc9eb39041ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 27 Sep 2021 16:55:10 +0200 Subject: [PATCH 0830/1182] Sort available style choices (#1166) --- httpie/cli/definition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index ab059dafaa..9bea2bffa0 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -252,7 +252,7 @@ dest='style', metavar='STYLE', default=DEFAULT_STYLE, - choices=AVAILABLE_STYLES, + choices=sorted(AVAILABLE_STYLES), help=''' Output coloring style (default is "{default}"). It can be One of: From fe96b2af20b3388acf92b138a5e5169153aa0b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 28 Sep 2021 12:53:53 +0200 Subject: [PATCH 0831/1182] Use httpie.io/docs everywhere [skip ci] --- httpie/cli/argparser.py | 2 +- httpie/cli/definition.py | 4 ++-- httpie/sessions.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 5456330e54..5739e9d357 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -311,7 +311,7 @@ def _ensure_one_data_source(self, *other_sources): self.error('Request body (from stdin, --raw or a file) and request ' 'data (key=value) cannot be mixed. Pass ' '--ignore-stdin to let key/value take priority. ' - 'See https://httpie.org/doc#scripting for details.') + 'See https://httpie.io/docs#scripting for details.') def _guess_method(self): """Set `args.method` if not specified to either POST or GET diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 9bea2bffa0..4fb9c184c4 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -30,7 +30,7 @@ parser = HTTPieArgumentParser( prog='http', - description=f'{__doc__.strip()} ', + description=f'{__doc__.strip()} ', epilog=dedent(''' For every --OPTION there is also a --no-OPTION that reverts OPTION to its default value. @@ -96,7 +96,7 @@ ':' HTTP headers: - Referer:http://httpie.org Cookie:foo=bar User-Agent:bacon/1.0 + Referer:https://httpie.io Cookie:foo=bar User-Agent:bacon/1.0 '==' URL parameters to be appended to the request URI: diff --git a/httpie/sessions.py b/httpie/sessions.py index 2876935a48..7ecb6e7b72 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -52,7 +52,7 @@ def get_httpie_session( class Session(BaseConfigDict): - helpurl = 'https://httpie.org/doc#sessions' + helpurl = 'https://httpie.io/docs#sessions' about = 'HTTPie session file' def __init__(self, path: Union[str, Path]): From b50f9aa7e776152707a014cf4fd6add82e40ec52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 28 Sep 2021 12:54:16 +0200 Subject: [PATCH 0832/1182] Use PYthon 3 documentation [skip ci] --- httpie/sessions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/sessions.py b/httpie/sessions.py index 7ecb6e7b72..0a04fb7446 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -112,7 +112,7 @@ def cookies(self) -> RequestsCookieJar: @cookies.setter def cookies(self, jar: RequestsCookieJar): - # + # stored_attrs = ['value', 'path', 'secure', 'expires'] self['cookies'] = {} for cookie in jar: From 71adcd97d03ee29a63c6c3db166580beb0e663cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 29 Sep 2021 20:22:19 +0200 Subject: [PATCH 0833/1182] Improve handling of prettified responses without correct content-type encoding (#1110) * Improve handling of responses without correct content-type charset * [skip ci] Minor tweaks in tests * [skip ci] Add documentation Co-authored-by: claudiatd * Improve unknown encoding test [skip ci] * Review mime and options retrieval * Add full content-type example in help output * Simplify decoder * [skip ci] s/charset/encoding/ * Tweaks * [skip ci] Fix type annotation * [skip ci] s/charset/encoding/ * Tweaks * Fix type annoation * Improvement * Introduce `codec.encode()` * [skip ci] Tweak changelog Co-authored-by: claudiatd --- CHANGELOG.md | 1 + docs/README.md | 12 ++++ httpie/cli/definition.py | 2 + httpie/codec.py | 37 ++++++++++++ httpie/models.py | 11 ---- httpie/output/formatters/xml.py | 2 +- httpie/output/streams.py | 35 +++++++---- setup.py | 1 + tests/test_errors.py | 7 +++ tests/test_unicode.py | 102 +++++++++++++++++++++++++++++++- 10 files changed, 184 insertions(+), 26 deletions(-) create mode 100644 httpie/codec.py diff --git a/CHANGELOG.md b/CHANGELOG.md index ca49cefb7d..df49ee28a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) - Added `--format-options=response.as:CONTENT_TYPE` to allow overriding the response `Content-Type`. ([#1134](https://github.com/httpie/httpie/issues/1134)) - Added `--response-as` shortcut for setting the response `Content-Type`-related `--format-options`. ([#1134](https://github.com/httpie/httpie/issues/1134)) +- Improved handling of prettified responses without correct `Content-Type` encoding. ([#1110](https://github.com/httpie/httpie/issues/1110)) - Installed plugins are now listed in `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165)) - Fixed duplicate keys preservation of JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163)) diff --git a/docs/README.md b/docs/README.md index d4cfd53382..ed3153705b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1249,6 +1249,18 @@ For example, the following request will force the response to be treated as XML: $ http --response-as=application/xml pie.dev/get ``` +And the following requests will force the response to use the [big5](https://docs.python.org/3/library/codecs.html#standard-encodings) encoding: + +```bash +$ http --response-as='charset=big5' pie.dev/get +``` + +```bash +$ http --response-as='text/plain; charset=big5' pie.dev/get +``` + +Given the encoding is not sent by the server, HTTPie will auto-detect it. + ### Binary data Binary data is suppressed for terminal output, which makes it safe to perform requests to URLs that send back binary data. diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 4fb9c184c4..77be93a9dd 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -316,6 +316,8 @@ Override the response Content-Type for formatting purposes, e.g.: --response-as=application/xml + --response-as=charset=utf-8 + --response-as='application/xml; charset=utf-8' It is a shortcut for: diff --git a/httpie/codec.py b/httpie/codec.py new file mode 100644 index 0000000000..61057166c2 --- /dev/null +++ b/httpie/codec.py @@ -0,0 +1,37 @@ +from typing import Union + +from charset_normalizer import from_bytes + +from .constants import UTF8 + +Bytes = Union[bytearray, bytes] + + +def detect_encoding(content: Bytes) -> str: + """Detect the `content` encoding. + Fallback to UTF-8 when no suitable encoding found. + + """ + match = from_bytes(bytes(content)).best() + return match.encoding if match else UTF8 + + +def decode(content: Bytes, encoding: str) -> str: + """Decode `content` using the given `encoding`. + If no `encoding` is provided, the best effort is to guess it from `content`. + + Unicode errors are replaced. + + """ + if not encoding: + encoding = detect_encoding(content) + return content.decode(encoding, 'replace') + + +def encode(content: str, encoding: str) -> bytes: + """Encode `content` using the given `encoding`. + + Unicode errors are replaced. + + """ + return content.encode(encoding, 'replace') diff --git a/httpie/models.py b/httpie/models.py index f4ddb03b50..21034a04d0 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -30,11 +30,6 @@ def headers(self) -> str: def encoding(self) -> Optional[str]: """Return a `str` with the message's encoding, if known.""" - @property - def body(self) -> bytes: - """Return a `bytes` with the message's body.""" - raise NotImplementedError() - @property def content_type(self) -> str: """Return the message content type.""" @@ -86,12 +81,6 @@ def headers(self): def encoding(self): return self._orig.encoding or UTF8 - @property - def body(self): - # Only now the response body is fetched. - # Shouldn't be touched unless the body is actually needed. - return self._orig.content - class HTTPRequest(HTTPMessage): """A :class:`requests.models.Request` wrapper.""" diff --git a/httpie/output/formatters/xml.py b/httpie/output/formatters/xml.py index e5ce5c23f1..2909f7c0e7 100644 --- a/httpie/output/formatters/xml.py +++ b/httpie/output/formatters/xml.py @@ -25,7 +25,7 @@ def pretty_xml(document: 'Document', } if standalone is not None and sys.version_info >= (3, 9): kwargs['standalone'] = standalone - body = document.toprettyxml(**kwargs).decode() + body = document.toprettyxml(**kwargs).decode(kwargs['encoding']) # Remove blank lines automatically added by `toprettyxml()`. return '\n'.join(line for line in body.splitlines() if line.strip()) diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 9bb646bfae..1c6afaa821 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -1,7 +1,8 @@ from abc import ABCMeta, abstractmethod from itertools import chain -from typing import Callable, Iterable, Union +from typing import Any, Callable, Dict, Iterable, Tuple, Union +from .. import codec from ..cli.constants import EMPTY_FORMAT_OPTION from ..context import Environment from ..constants import UTF8 @@ -114,8 +115,8 @@ def iter_body(self) -> Iterable[bytes]: for line, lf in self.msg.iter_lines(self.CHUNK_SIZE): if b'\0' in line: raise BinarySuppressedError() - yield line.decode(self.msg.encoding) \ - .encode(self.output_encoding, 'replace') + lf + line = codec.decode(line, self.msg.encoding) + yield codec.encode(line, self.output_encoding) + lf class PrettyStream(EncodedStream): @@ -137,15 +138,23 @@ def __init__( super().__init__(**kwargs) self.formatting = formatting self.conversion = conversion - self.mime = self.get_mime() + self.mime, mime_options = self._get_mime_and_options() + self.encoding = mime_options.get('charset') or '' - def get_mime(self) -> str: - mime = parse_header_content_type(self.msg.content_type)[0] - if isinstance(self.msg, HTTPResponse): - forced_content_type = self.formatting.options['response']['as'] - if forced_content_type != EMPTY_FORMAT_OPTION: - mime = parse_header_content_type(forced_content_type)[0] or mime - return mime + def _get_mime_and_options(self) -> Tuple[str, Dict[str, Any]]: + # Defaults from the `Content-Type` header. + mime, options = parse_header_content_type(self.msg.content_type) + + if not isinstance(self.msg, HTTPResponse): + return mime, options + + # Override from the `--response-as` option. + forced_content_type = self.formatting.options['response']['as'] + if forced_content_type == EMPTY_FORMAT_OPTION: + return mime, options + + forced_mime, forced_options = parse_header_content_type(forced_content_type) + return (forced_mime or mime, forced_options or options) def get_headers(self) -> bytes: return self.formatting.format_headers( @@ -176,9 +185,9 @@ def process_body(self, chunk: Union[str, bytes]) -> bytes: if not isinstance(chunk, str): # Text when a converter has been used, # otherwise it will always be bytes. - chunk = chunk.decode(self.msg.encoding, 'replace') + chunk = codec.decode(chunk, self.encoding) chunk = self.formatting.format_body(content=chunk, mime=self.mime) - return chunk.encode(self.output_encoding, 'replace') + return codec.encode(chunk, self.output_encoding) class BufferedPrettyStream(PrettyStream): diff --git a/setup.py b/setup.py index 22c14212c2..ef2d5e8660 100644 --- a/setup.py +++ b/setup.py @@ -25,6 +25,7 @@ 'wheel', ] install_requires = [ + 'charset_normalizer>=2.0.0', 'defusedxml>=0.6.0', 'requests[socks]>=2.22.0', 'Pygments>=2.5.2', diff --git a/tests/test_errors.py b/tests/test_errors.py index c33b8f803e..abbf7235a4 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -39,3 +39,10 @@ def test_max_headers_limit(httpbin_both): def test_max_headers_no_limit(httpbin_both): assert HTTP_OK in http('--max-headers=0', httpbin_both + '/get') + + +def test_charset_argument_unknown_encoding(httpbin_both): + with raises(LookupError) as e: + http('--response-as', 'charset=foobar', + 'GET', httpbin_both + '/get') + assert 'unknown encoding: foobar' in str(e.value) diff --git a/tests/test_unicode.py b/tests/test_unicode.py index d1ea81720d..2a12180e41 100644 --- a/tests/test_unicode.py +++ b/tests/test_unicode.py @@ -2,9 +2,17 @@ Various unicode handling related tests. """ -from .utils import http, HTTP_OK +import pytest +import responses + +from httpie.cli.constants import PRETTY_MAP +from httpie.constants import UTF8 + +from .utils import http, HTTP_OK, URL_EXAMPLE from .fixtures import UNICODE +ENCODINGS = [UTF8, 'windows-1250'] + def test_unicode_headers(httpbin): # httpbin doesn't interpret UFT-8 headers @@ -109,3 +117,95 @@ def test_unicode_digest_auth(httpbin): http('--auth-type=digest', '--auth', f'test:{UNICODE}', f'{httpbin.url}/digest-auth/auth/test/{UNICODE}') + + +@pytest.mark.parametrize('encoding', ENCODINGS) +@responses.activate +def test_GET_encoding_detection_from_content_type_header(encoding): + responses.add(responses.GET, + URL_EXAMPLE, + body='\nFinanciën'.encode(encoding), + content_type=f'text/xml; charset={encoding.upper()}') + r = http('GET', URL_EXAMPLE) + assert 'Financiën' in r + + +@pytest.mark.parametrize('encoding', ENCODINGS) +@responses.activate +def test_GET_encoding_detection_from_content(encoding): + body = f'\nFinanciën' + responses.add(responses.GET, + URL_EXAMPLE, + body=body.encode(encoding), + content_type='text/xml') + r = http('GET', URL_EXAMPLE) + assert 'Financiën' in r + + +@responses.activate +def test_GET_encoding_provided_by_format_options(): + responses.add(responses.GET, + URL_EXAMPLE, + body='▒▒▒'.encode('johab'), + content_type='text/plain') + r = http('--format-options', 'response.as:text/plain; charset=johab', + 'GET', URL_EXAMPLE) + assert '▒▒▒' in r + + +@responses.activate +def test_GET_encoding_provided_by_shortcut_option(): + responses.add(responses.GET, + URL_EXAMPLE, + body='▒▒▒'.encode('johab'), + content_type='text/plain') + r = http('--response-as', 'text/plain; charset=johab', + 'GET', URL_EXAMPLE) + assert '▒▒▒' in r + + +@pytest.mark.parametrize('encoding', ENCODINGS) +@responses.activate +def test_GET_encoding_provided_by_empty_shortcut_option_should_use_content_detection(encoding): + body = f'\nFinanciën' + responses.add(responses.GET, + URL_EXAMPLE, + body=body.encode(encoding), + content_type='text/xml') + r = http('--response-as', '', 'GET', URL_EXAMPLE) + assert 'Financiën' in r + + +@pytest.mark.parametrize('encoding', ENCODINGS) +@responses.activate +def test_POST_encoding_detection_from_content_type_header(encoding): + responses.add(responses.POST, + URL_EXAMPLE, + body='Všichni lidé jsou si rovni.'.encode(encoding), + content_type=f'text/plain; charset={encoding.upper()}') + r = http('--form', 'POST', URL_EXAMPLE) + assert 'Všichni lidé jsou si rovni.' in r + + +@pytest.mark.parametrize('encoding', ENCODINGS) +@responses.activate +def test_POST_encoding_detection_from_content(encoding): + responses.add(responses.POST, + URL_EXAMPLE, + body='Všichni lidé jsou si rovni.'.encode(encoding), + content_type='text/plain') + r = http('--form', 'POST', URL_EXAMPLE) + assert 'Všichni lidé jsou si rovni.' in r + + +@pytest.mark.parametrize('encoding', ENCODINGS) +@pytest.mark.parametrize('pretty', PRETTY_MAP.keys()) +@responses.activate +def test_stream_encoding_detection_from_content_type_header(encoding, pretty): + responses.add(responses.GET, + URL_EXAMPLE, + body='\nFinanciën'.encode(encoding), + stream=True, + content_type=f'text/xml; charset={encoding.upper()}') + r = http('--pretty=' + pretty, '--stream', 'GET', URL_EXAMPLE) + assert 'Financiën' in r From b6a694afbc26733e190ef86b8286ae9c718991de Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 30 Sep 2021 14:39:18 +0200 Subject: [PATCH 0834/1182] master/latest docs differ since --response-as --- docs/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.json b/docs/config.json index 4375a5a5e7..36d9dc3724 100644 --- a/docs/config.json +++ b/docs/config.json @@ -1,5 +1,5 @@ { "website": { - "master_and_released_docs_differ_after": null + "master_and_released_docs_differ_after": '8f8851f1dbd511d3bc0ea0f6da7459045610afce' } } From 2423f893e5237b7c2ab05f6ba74aba09fb06257a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 30 Sep 2021 14:39:32 +0200 Subject: [PATCH 0835/1182] Update config.json --- docs/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.json b/docs/config.json index 36d9dc3724..2ba18b9d13 100644 --- a/docs/config.json +++ b/docs/config.json @@ -1,5 +1,5 @@ { "website": { - "master_and_released_docs_differ_after": '8f8851f1dbd511d3bc0ea0f6da7459045610afce' + "master_and_released_docs_differ_after": "8f8851f1dbd511d3bc0ea0f6da7459045610afce" } } From 4ef31ecf71a8e1107329a49ed205c8b2cdffef65 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Oct 2021 16:43:29 +0200 Subject: [PATCH 0836/1182] Update utils.py --- httpie/utils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/httpie/utils.py b/httpie/utils.py index c155aac503..4b2565e055 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -16,9 +16,7 @@ class JsonDictPreservingDuplicateKeys(OrderedDict): - """A specialized JSON dict preserving duplicate keys. - - """ + """A specialized JSON dict preserving duplicate keys.""" # Python versions prior to 3.8 suffer from an issue with multiple keys with the same name. # `json.dumps(obj, indent=N, sort_keys=True)` will output sorted keys when they are unique, and From 738840113465d9eb481eb14a99a30f56cf9329a7 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 2 Oct 2021 16:50:39 +0200 Subject: [PATCH 0837/1182] Update setup.py --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index ef2d5e8660..fccac462bb 100644 --- a/setup.py +++ b/setup.py @@ -6,6 +6,7 @@ import httpie + # Note: keep requirements here to ease distributions packaging tests_require = [ 'pytest', From a6c70334cff98727adef1edff82e39410fa71c4d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 3 Oct 2021 03:05:37 +0200 Subject: [PATCH 0838/1182] Expand HTTP method docs * mention `POST` without a body * mention `GET` with a body * mention custom method names * include examples for default `GET`/`POST` --- docs/README.md | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index ed3153705b..532cdd2dcf 100644 --- a/docs/README.md +++ b/docs/README.md @@ -256,7 +256,53 @@ Which looks similar to the actual `Request-Line` that is sent: DELETE /delete HTTP/1.1 ``` -When the `METHOD` argument is omitted from the command, HTTPie defaults to either `GET` (with no request data) or `POST` (with request data). +In addition to the standard methods (`GET`, `POST`, `HEAD`, `PUT`, `PATCH`, `DELETE`, etc.), you can use custom method names, for example: + + +```bash +$ http AHOY pie.dev/post +``` + +There are no restrictions regarding which request methods can include a body. You can send an empty `POST` request: + +```bash +$ http POST pie.dev/post +``` + +You can also make `GET` requests contaning a body: + +```bash +$ http GET pie.dev/get hello=world +``` + +### Optional `GET` and `POST` + +The `METHOD` argument is optional, and when you don’t specify it, HTTPie defaults to: + +* `GET` for requests without a body +* `POST` for requests with body + +Here we don’t specify any request data, so both commands will send the same `GET` request: + +```bash +$ http GET pie.dev/get +``` + +```bash +$ http pie.dev/get +``` + +Here, on the other hand, we do have some data, so both commands will make the same `POST` request: + +``` +$ http POST pie.dev/post hello=world +``` + +```bash +$ http pie.dev/post hello=world +``` + + ## Request URL From 6a4e985f717cf5376aaa81e9d7f446060696fb35 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 3 Oct 2021 03:08:05 +0200 Subject: [PATCH 0839/1182] Remove redundant/inconsistent article --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 532cdd2dcf..ba388c40ca 100644 --- a/docs/README.md +++ b/docs/README.md @@ -279,7 +279,7 @@ $ http GET pie.dev/get hello=world The `METHOD` argument is optional, and when you don’t specify it, HTTPie defaults to: -* `GET` for requests without a body +* `GET` for requests without body * `POST` for requests with body Here we don’t specify any request data, so both commands will send the same `GET` request: From 033798adc1a816d4ba0a83370c15d5abe5366081 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 3 Oct 2021 03:20:23 +0200 Subject: [PATCH 0840/1182] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 75b0576cdf..64ae4e0089 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ They use simple and natural syntax and provide formatted and colorized output. [![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions) [![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/httpie) [![Twitter](https://img.shields.io/twitter/follow/httpie?style=flat&color=%234B78E6&logoColor=%234B78E6)](https://twitter.com/httpie) -[![Chat](https://img.shields.io/badge/chat-Discord-brightgreen?style=flat&label=Chat%20on&color=%23FA9BFA)](https://httpie.io/chat) +[![Chat](https://img.shields.io/badge/chat-Discord-brightgreen?style=flat&label=Chat%20on&color=%23FA9BFA)](https://httpie.io/discord) HTTPie in action From e1c08a3de5597fef9d5af847209d5a919dee0419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 5 Oct 2021 15:45:34 +0200 Subject: [PATCH 0841/1182] Mention Snapcraft for unstable version installation --- docs/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index ba388c40ca..38846709e9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -146,13 +146,20 @@ You can install it on Linux, macOS, Windows, or FreeBSD with `pip`: $ python -m pip install --upgrade https://github.com/httpie/httpie/archive/master.tar.gz ``` -Or on macOS with Homebrew: +Or on macOS, and Linux, with Homebrew: ```bash $ brew uninstall --force httpie $ brew install --HEAD httpie ``` +And even on macOS, and Linux, with Snapcraft: + +```bash +$ snap remove httpie +$ snap install httpie --edge +``` + Verify that now you have the [current development version identifier](https://github.com/httpie/httpie/blob/master/httpie__init__.py#L6) with the `-dev` suffix, for example: ```bash From 031b4b89e3278b67badbe42d8fa46e8b4d3bf872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 5 Oct 2021 15:46:05 +0200 Subject: [PATCH 0842/1182] Fix docs formatting --- Makefile | 2 +- docs/README.md | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 9e46a5a250..95a590eac9 100644 --- a/Makefile +++ b/Makefile @@ -140,7 +140,7 @@ codecov-upload: doc-check: @echo $(H1)Running documentations checks$(H1END) - mdl --verbose --git-recurse --style docs/linter/mdl-styles.rb . + mdl --git-recurse --style docs/linter/mdl-styles.rb . ############################################################################### diff --git a/docs/README.md b/docs/README.md index 38846709e9..5d967fab1a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -265,7 +265,6 @@ DELETE /delete HTTP/1.1 In addition to the standard methods (`GET`, `POST`, `HEAD`, `PUT`, `PATCH`, `DELETE`, etc.), you can use custom method names, for example: - ```bash $ http AHOY pie.dev/post ``` @@ -286,8 +285,8 @@ $ http GET pie.dev/get hello=world The `METHOD` argument is optional, and when you don’t specify it, HTTPie defaults to: -* `GET` for requests without body -* `POST` for requests with body +- `GET` for requests without body +- `POST` for requests with body Here we don’t specify any request data, so both commands will send the same `GET` request: @@ -301,7 +300,7 @@ $ http pie.dev/get Here, on the other hand, we do have some data, so both commands will make the same `POST` request: -``` +```bash $ http POST pie.dev/post hello=world ``` @@ -309,8 +308,6 @@ $ http POST pie.dev/post hello=world $ http pie.dev/post hello=world ``` - - ## Request URL The only information HTTPie needs to perform a request is a URL. From e4e49275679cd3bc617e60968ae77f9f187c1f4c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 5 Oct 2021 21:25:10 +0200 Subject: [PATCH 0843/1182] Test on Python 3.10 --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ff164f9bc4..e61fde5b97 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: [3.6, 3.7, 3.8, 3.9, "3.10.0-rc.2"] + python-version: [3.6, 3.7, 3.8, 3.9, "3.10"] pyopenssl: [0, 1] runs-on: ${{ matrix.os }} steps: From 9c524493440a2643e2fea27bc1248c80e8191059 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 5 Oct 2021 21:28:39 +0200 Subject: [PATCH 0844/1182] Add self to paths; same paths for PR and push --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e61fde5b97..7db1bb6df6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,8 +5,10 @@ on: branches: - master paths: + - .github/workflows/tests.yml - httpie/**/*.py - setup.* + - tests/**/*.py pull_request: paths: - .github/workflows/tests.yml From a3fa016428cf8a890bbd9944d57789f7af4ee212 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 5 Oct 2021 21:30:28 +0200 Subject: [PATCH 0845/1182] Cover on Python 3.10 --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 8c0f94f07a..5edb47fa46 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: - python-version: 3.9 + python-version: "3.10" - run: make install - run: make test-cover - run: make codecov-upload From 0c9d7016181b3006b3b17c0bedc64e9e257b90bc Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 5 Oct 2021 21:37:40 +0200 Subject: [PATCH 0846/1182] Add `make install-reqs` to install packages without creating env --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 95a590eac9..ff07cfed11 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,10 @@ export PATH := $(VENV_BIN):$(PATH) all: uninstall-httpie install test -install: venv +install: venv install-reqs + + +install-reqs: @echo $(H1)Updating package tools$(H1END) $(VENV_PIP) install --upgrade pip wheel @@ -37,6 +40,7 @@ install: venv @echo + clean: @echo $(H1)Cleaning up$(H1END) rm -rf $(VENV_ROOT) From 08751d3672fac62f39d6b93afe52d2fd63aa93b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 6 Oct 2021 11:18:27 +0200 Subject: [PATCH 0847/1182] Add install/update instructions database (#1160) * Add install/update instructions database * Update the database * Revert README changes They will be overwritten later. * Revert * Tweak * Tweaks * Upgrade database * Complete commands Still not sure about Spack upgrades. * Sort * Doc generation script draft * Remove OS names from tool names * Fix Linuxbrew name * `wheel` already installs `setuptools` * Gen docs * Update * Tweak * Add a GitHub workflow to check for outdated installation instructions * Fix return value * Test * Delete test * Rename the script * Add `make doc-install-inst` * Add missing dev requirement * The first tool is the primary we want to display Then they are simply sorted by `tool.title`. * Sort OSes by name * Refactoring, jinja template, etc. * Add tool title uniqueness `assert`, fix platform list extra `\n` * Rebuild docs * Update generate.py * Update README.md * Update methods.yml * Update distros derived, more assertions * Tweaks * Add workflow to auto-update the docs * Do not hide the command * Tweaks Co-authored-by: Jakub Roztocil --- .github/workflows/code-style.yml | 2 - .github/workflows/coverage.yml | 2 - ...k-markdown.yml => docs-check-markdown.yml} | 2 - ...date-documentation.yml => docs-deploy.yml} | 2 - .github/workflows/docs-update-install.yml | 26 ++ .github/workflows/release.yml | 2 - ...x-snap.yml => test-package-linux-snap.yml} | 2 - ...mac-brew.yml => test-package-mac-brew.yml} | 0 .github/workflows/tests.yml | 2 - Makefile | 7 +- docs/README.md | 246 ++++++++++++++-- docs/installation/README.md | 5 + docs/installation/generate.py | 85 ++++++ docs/installation/installation.jinja2 | 37 +++ docs/installation/methods.yml | 269 ++++++++++++++++++ .../{linter/mdl-styles.rb => markdownlint.rb} | 2 + setup.py | 2 + 17 files changed, 647 insertions(+), 46 deletions(-) rename .github/workflows/{check-markdown.yml => docs-check-markdown.yml} (94%) rename .github/workflows/{update-documentation.yml => docs-deploy.yml} (93%) create mode 100644 .github/workflows/docs-update-install.yml rename .github/workflows/{packaging-linux-snap.yml => test-package-linux-snap.yml} (97%) rename .github/workflows/{packaging-mac-brew.yml => test-package-mac-brew.yml} (100%) create mode 100644 docs/installation/README.md create mode 100644 docs/installation/generate.py create mode 100644 docs/installation/installation.jinja2 create mode 100644 docs/installation/methods.yml rename docs/{linter/mdl-styles.rb => markdownlint.rb} (93%) diff --git a/.github/workflows/code-style.yml b/.github/workflows/code-style.yml index d006c85d3d..580bf467a1 100644 --- a/.github/workflows/code-style.yml +++ b/.github/workflows/code-style.yml @@ -1,5 +1,3 @@ -name: Code style - on: pull_request: paths: diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5edb47fa46..e178de17f9 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,5 +1,3 @@ -name: Coverage - on: pull_request: paths: diff --git a/.github/workflows/check-markdown.yml b/.github/workflows/docs-check-markdown.yml similarity index 94% rename from .github/workflows/check-markdown.yml rename to .github/workflows/docs-check-markdown.yml index 4e0b88ad16..a2cb9fbfd3 100644 --- a/.github/workflows/check-markdown.yml +++ b/.github/workflows/docs-check-markdown.yml @@ -1,5 +1,3 @@ -name: Check markdown - on: pull_request: paths: diff --git a/.github/workflows/update-documentation.yml b/.github/workflows/docs-deploy.yml similarity index 93% rename from .github/workflows/update-documentation.yml rename to .github/workflows/docs-deploy.yml index d9af12e38f..ff3217ac0b 100644 --- a/.github/workflows/update-documentation.yml +++ b/.github/workflows/docs-deploy.yml @@ -1,5 +1,3 @@ -name: Update documentation - on: push: branches: diff --git a/.github/workflows/docs-update-install.yml b/.github/workflows/docs-update-install.yml new file mode 100644 index 0000000000..d612e5ae34 --- /dev/null +++ b/.github/workflows/docs-update-install.yml @@ -0,0 +1,26 @@ +on: + push: + branches: + - master + paths: + - docs/installation/* + + # Allow to call the workflow manually + workflow_dispatch: + +jobs: + doc: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.9 + - run: make install + - run: make doc-update-install + - uses: Automattic/action-commit-to-branch@master + with: + branch: master + commit_message: Auto-update installation instructions in the docs + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 41ba517367..674bf04b02 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,3 @@ -name: Release - on: # Add a "Trigger" button to manually start the workflow. workflow_dispatch: diff --git a/.github/workflows/packaging-linux-snap.yml b/.github/workflows/test-package-linux-snap.yml similarity index 97% rename from .github/workflows/packaging-linux-snap.yml rename to .github/workflows/test-package-linux-snap.yml index 101964011c..6442378159 100644 --- a/.github/workflows/packaging-linux-snap.yml +++ b/.github/workflows/test-package-linux-snap.yml @@ -1,5 +1,3 @@ -name: Linux snap - on: pull_request: paths: diff --git a/.github/workflows/packaging-mac-brew.yml b/.github/workflows/test-package-mac-brew.yml similarity index 100% rename from .github/workflows/packaging-mac-brew.yml rename to .github/workflows/test-package-mac-brew.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7db1bb6df6..b8409f7c64 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,5 +1,3 @@ -name: Tests - on: push: branches: diff --git a/Makefile b/Makefile index ff07cfed11..1a0e96bdec 100644 --- a/Makefile +++ b/Makefile @@ -144,7 +144,12 @@ codecov-upload: doc-check: @echo $(H1)Running documentations checks$(H1END) - mdl --git-recurse --style docs/linter/mdl-styles.rb . + mdl --git-recurse --style docs/markdownlint.rb . + + +doc-update-install: + @echo $(H1)Updating installation instructions in the docs$(H1END) + $(VENV_PYTHON) docs/installation/generate.py ############################################################################### diff --git a/docs/README.md b/docs/README.md index 5d967fab1a..6bf35d6ab7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -41,99 +41,283 @@ You are invited to submit fixes and improvements to the docs by editing [this fi ## Installation +
      + + + +- [Universal](#universal) +- [macOS](#macos) +- [Windows](#windows) +- [Linux](#linux) +- [FreeBSD](#freebsd) + +### Universal + +#### PyPi + +Please make sure you have Python 3.6 or newer (`python --version`). + +```bash +# Install +$ python -m pip install --upgrade pip wheel +$ python -m pip install httpie +``` + +```bash +# Upgrade +$ python -m pip install --upgrade pip wheel +$ python -m pip install --upgrade httpie +``` + ### macOS -On macOS, HTTPie can also be installed via [Homebrew](https://brew.sh/): +#### Homebrew + +To install [Homebrew](https://brew.sh/) follow [installation instructions](https://docs.brew.sh/Installation). ```bash +# Install +$ brew update $ brew install httpie ``` -A MacPorts *port* is also available: +```bash +# Upgrade +$ brew update +$ brew upgrade httpie +``` + +#### MacPorts + +To install [MacPorts](https://www.macports.org/) follow [installation instructions](https://www.macports.org/install.php). ```bash +# Install +$ port selfupdate $ port install httpie ``` +```bash +# Upgrade +$ port selfupdate +$ port upgrade httpie +``` + +#### Snapcraft (macOS) + +To install [Snapcraft](https://snapcraft.io/) follow [installation instructions](https://snapcraft.io/docs/installing-snapd). + +```bash +# Install +$ snap install httpie +``` + +```bash +# Upgrade +$ snap refresh httpie +``` + +#### Spack (macOS) + +To install [Spack](https://spack.readthedocs.io/en/latest/index.html) follow [installation instructions](https://spack.readthedocs.io/en/latest/getting_started.html#installation). + +```bash +# Install +$ spack install httpie +``` + +```bash +# Upgrade +$ spack install httpie +``` + +### Windows + +#### Chocolatey + +To install [Chocolatey](https://chocolatey.org/) follow [installation instructions](https://chocolatey.org/install). + +```bash +# Install +$ choco install httpie +``` + +```bash +# Upgrade +$ choco upgrade httpie +``` + ### Linux -HTTPie is available on the [Snap Store](https://snapcraft.io/httpie): +#### Snapcraft (Linux) + +To install [Snapcraft](https://snapcraft.io/) follow [installation instructions](https://snapcraft.io/docs/installing-snapd). ```bash +# Install $ snap install httpie ``` -And most Linux distributions provide a package that can be installed using the -system package manager, for example: +```bash +# Upgrade +$ snap refresh httpie +``` + +#### Linuxbrew + +To install [Linuxbrew](https://docs.brew.sh/Homebrew-on-Linux) follow [installation instructions](https://docs.brew.sh/Homebrew-on-Linux#install). + +```bash +# Install +$ brew update +$ brew install httpie +``` + +```bash +# Upgrade +$ brew update +$ brew upgrade httpie +``` + +#### Debian and Ubuntu + +Also works for other Debian-derived distributions like MX Linux, Linux Mint, deepin, Pop!_OS, KDE neon, Zorin OS, elementary OS, Kubuntu, Devuan, Linux Lite, Peppermint OS, Lubuntu, antiX, Xubuntu, etc. ```bash -# Debian, Ubuntu, etc. +# Install +$ apt update $ apt install httpie ``` ```bash -# Fedora +# Upgrade +$ apt update +$ apt upgrade httpie +``` + +#### Fedora + +```bash +# Install +$ dnf update $ dnf install httpie ``` ```bash -# CentOS, RHEL, ... +# Upgrade +$ dnf update +$ dnf upgrade httpie +``` + +#### CentOS and RHEL + +Also works for other RHEL-derived distributions like ClearOS, Oracle Linux, etc. + +```bash +# Install +$ yum update $ yum install epel-release $ yum install httpie ``` ```bash -# Gentoo +# Upgrade +$ yum update +$ yum upgrade httpie +``` + +#### Alpine Linux + +```bash +# Install +$ apk update +$ apk add httpie +``` + +```bash +# Upgrade +$ apk update +$ apk add --upgrade httpie +``` + +#### Gentoo + +```bash +# Install +$ emerge --sync $ emerge httpie ``` ```bash -# Arch Linux -$ pacman -S httpie +# Upgrade +$ emerge --sync +$ emerge --update httpie ``` +#### Arch Linux + +Also works for other Arch-derived distributions like ArcoLinux, EndeavourOS, Artix Linux, etc. + ```bash -# Alpine Linux -$ apk add httpie +# Install +$ pacman -Sy httpie ``` ```bash -# Solus -$ eopkg install httpie +# Upgrade +$ pacman -Syu httpie ``` -### FreeBSD +#### Void Linux -On FreeBSD, HTTPie is available in the ports collection. A prebuilt package -can be installed via [pkg(8)](https://man.freebsd.org/pkg/8>): +```bash +# Install +$ xbps-install -Su +$ xbps-install -S httpie +``` ```bash -$ pkg install www/py-httpie +# Upgrade +$ xbps-install -Su +$ xbps-install -Su httpie ``` -### Windows, universal +#### Spack (Linux) -A universal installation method (that works on Linux, macOS, Windows, FreeBSD, and always provides the latest version) is to use [pip](https://pypi.org/project/pip/): +To install [Spack](https://spack.readthedocs.io/en/latest/index.html) follow [installation instructions](https://spack.readthedocs.io/en/latest/getting_started.html#installation). ```bash -# Make sure we have an up-to-date version of pip and setuptools: -$ python -m pip install --upgrade pip setuptools +# Install +$ spack install httpie +``` -$ python -m pip install --upgrade httpie +```bash +# Upgrade +$ spack install httpie ``` -(If `pip` installation fails for some reason, you can try -`easy_install httpie` as a fallback.) +### FreeBSD + +#### FreshPorts -Windows users can also install HTTPie with [Chocolatey](https://chocolatey.org): +```bash +# Install +$ pkg install www/py-httpie +``` ```bash -$ choco upgrade httpie +# Upgrade +$ pkg upgrade www/py-httpie ``` -### Python version + -Python version 3.6 or greater is required. +
      ### Unstable version @@ -160,7 +344,7 @@ $ snap remove httpie $ snap install httpie --edge ``` -Verify that now you have the [current development version identifier](https://github.com/httpie/httpie/blob/master/httpie__init__.py#L6) with the `-dev` suffix, for example: +Verify that now you have the [current development version identifier](https://github.com/httpie/httpie/blob/master/httpie/__init__.py#L6) with the `.dev0` suffix, for example: ```bash $ http --version diff --git a/docs/installation/README.md b/docs/installation/README.md new file mode 100644 index 0000000000..8337663be4 --- /dev/null +++ b/docs/installation/README.md @@ -0,0 +1,5 @@ +Here we maintain a database of installation methods, from which we generate +the installation section in docs. If you’d like add or update an installation method, +edit [methods.yml](./methods.yml), do not edit the main docs directly. + +For HTTPie installation instructions see: . diff --git a/docs/installation/generate.py b/docs/installation/generate.py new file mode 100644 index 0000000000..a67389ddd5 --- /dev/null +++ b/docs/installation/generate.py @@ -0,0 +1,85 @@ +import re +import sys +from pathlib import Path +from typing import Dict + +import yaml +from jinja2 import Template + +Database = Dict[str, dict] + +# Files +HERE = Path(__file__).parent +DB_FILE = HERE / 'methods.yml' +DOC_FILE = HERE.parent / 'README.md' +TPL_FILE = HERE / 'installation.jinja2' + +# Database keys +KEY_DOC_STRUCTURE = 'docs-structure' +KEY_TOOLS = 'tools' + +# Markers in-between content will be put. +MARKER_START = '
      ' +MARKER_END = '
      ' + + +def generate_documentation() -> str: + database = load_database() + structure = build_docs_structure(database) + template = Template(source=TPL_FILE.read_text(encoding='utf-8')) + output = template.render(structure=structure) + output = clean_template_output(output) + return output + + +def save_doc_file(content: str) -> None: + current_doc = load_doc_file() + marker_start = current_doc.find(MARKER_START) + len(MARKER_START) + assert marker_start > 0, 'cannot find the start marker' + marker_end = current_doc.find(MARKER_END, marker_start) + assert marker_start < marker_end, f'{marker_end=} < {marker_start=}' + updated_doc = ( + current_doc[:marker_start] + + '\n\n' + + content + + '\n\n' + + current_doc[marker_end:] + ) + if current_doc != updated_doc: + DOC_FILE.write_text(updated_doc, encoding='utf-8') + + +def build_docs_structure(database: Database): + tools = database[KEY_TOOLS] + assert len(tools) == len({tool['title'] for tool in tools.values()}), 'tool titles need to be unique' + tree = database[KEY_DOC_STRUCTURE] + structure = [] + for platform, tools_ids in tree.items(): + assert platform.isalnum(), f'{platform=} must be alpha-numeric for generated links to work' + platform_tools = [tools[tool_id] for tool_id in tools_ids] + structure.append((platform, platform_tools)) + return structure + + +def clean_template_output(output): + output = '\n'.join(line.strip() for line in output.strip().splitlines()) + output = re.sub('\n{3,}', '\n\n', output) + return output + + +def load_database() -> Database: + return yaml.safe_load(DB_FILE.read_text(encoding='utf-8')) + + +def load_doc_file() -> str: + return DOC_FILE.read_text(encoding='utf-8') + + +def main() -> int: + content = generate_documentation() + save_doc_file(content) + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/docs/installation/installation.jinja2 b/docs/installation/installation.jinja2 new file mode 100644 index 0000000000..5ecd816ea9 --- /dev/null +++ b/docs/installation/installation.jinja2 @@ -0,0 +1,37 @@ + +{% for platform, tools in structure %} + - [{{ platform }}](#{{ platform.lower() }}){% endfor %} {# <= keep `endfor` here to prevent unwanted `\n` #} + +{% for platform, tools in structure %} + + ### {{ platform }} + + {% for tool in tools %} + #### {{ tool.title }} + + {% if tool.note %} + {{ tool.note }} + {% endif %} + + {% if tool.links.setup %} + To install [{{ tool.name }}]({{ tool.links.homepage }}) follow [installation instructions]({{ tool.links.setup }}). + {% endif %} + + ```bash + # Install + $ {{ tool.commands.install|join('\n$ ') }} + ``` + + ```bash + # Upgrade + $ {{ tool.commands.upgrade|join('\n$ ') }} + ``` + {% endfor %} + +{% endfor %} + diff --git a/docs/installation/methods.yml b/docs/installation/methods.yml new file mode 100644 index 0000000000..f4990598c3 --- /dev/null +++ b/docs/installation/methods.yml @@ -0,0 +1,269 @@ +# Database of HTTPie installation methods. Used to build the docs. +# +# We currently only include here methods for popular systems where we take care of the package, +# or have a good relationship with the maintainers. +# +# Each tool name should be unique (it becomes a linkable header). +# If a tools have `links.setup`, it also needs `links.homepage`. +# Some tools are available on multiple platforms, take into account when editing. +# + +docs-structure: + Universal: + - pypi + macOS: + - brew-mac + - port + - snap-mac + - spack-mac + Windows: + - chocolatey + Linux: + - snap-linux + - brew-linux + - apt + - dnf + - yum + - apk + - emerge + - pacman + - xbps-install + - spack-linux + FreeBSD: + - pkg + +tools: + apk: + title: Alpine Linux + name: apk + links: + homepage: https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management + package: https://pkgs.alpinelinux.org/package/edge/community/x86/httpie + commands: + install: + - apk update + - apk add httpie + upgrade: + - apk update + - apk add --upgrade httpie + + apt: + title: Debian and Ubuntu + note: Also works for other Debian-derived distributions like MX Linux, Linux Mint, deepin, Pop!_OS, KDE neon, Zorin OS, elementary OS, Kubuntu, Devuan, Linux Lite, Peppermint OS, Lubuntu, antiX, Xubuntu, etc. + name: APT + links: + homepage: https://en.wikipedia.org/wiki/APT_(software) + package: https://packages.debian.org/sid/web/httpie + commands: + install: + - apt update + - apt install httpie + upgrade: + - apt update + - apt upgrade httpie + + brew-mac: + title: Homebrew + name: Homebrew + links: + homepage: https://brew.sh/ + setup: https://docs.brew.sh/Installation + package: https://formulae.brew.sh/formula/httpie + commands: + install: + - brew update + - brew install httpie + upgrade: + - brew update + - brew upgrade httpie + + brew-linux: + title: Linuxbrew + name: Linuxbrew + links: + homepage: https://docs.brew.sh/Homebrew-on-Linux + setup: https://docs.brew.sh/Homebrew-on-Linux#install + package: https://formulae.brew.sh/formula/httpie + commands: + install: + - brew update + - brew install httpie + upgrade: + - brew update + - brew upgrade httpie + + chocolatey: + title: Chocolatey + name: Chocolatey + links: + homepage: https://chocolatey.org/ + setup: https://chocolatey.org/install + package: https://community.chocolatey.org/packages/httpie/ + commands: + install: + - choco install httpie + upgrade: + - choco upgrade httpie + + dnf: + title: Fedora + name: DNF + links: + homepage: https://fedoraproject.org/wiki/DNF + package: https://src.fedoraproject.org/rpms/httpie + commands: + install: + - dnf update + - dnf install httpie + upgrade: + - dnf update + - dnf upgrade httpie + + emerge: + title: Gentoo + name: Portage + links: + homepage: https://wiki.gentoo.org/wiki/Portage + package: https://packages.gentoo.org/packages/net-misc/httpie + commands: + install: + - emerge --sync + - emerge httpie + upgrade: + - emerge --sync + - emerge --update httpie + + pacman: + title: Arch Linux + name: pacman + note: Also works for other Arch-derived distributions like ArcoLinux, EndeavourOS, Artix Linux, etc. + links: + homepage: https://archlinux.org/pacman/ + package: https://archlinux.org/packages/community/any/httpie/ + commands: + install: + - pacman -Sy httpie + upgrade: + - pacman -Syu httpie + + pkg: + title: FreshPorts + name: FreshPorts + links: + homepage: https://www.freebsd.org/cgi/man.cgi?query=pkg&sektion=8&n=1 + package: https://www.freshports.org/www/py-httpie/ + commands: + install: + - pkg install www/py-httpie + upgrade: + - pkg upgrade www/py-httpie + + port: + title: MacPorts + name: MacPorts + links: + homepage: https://www.macports.org/ + setup: https://www.macports.org/install.php + package: https://ports.macports.org/port/httpie/ + commands: + install: + - port selfupdate + - port install httpie + upgrade: + - port selfupdate + - port upgrade httpie + + pypi: + title: PyPi + name: pip + note: Please make sure you have Python 3.6 or newer (`python --version`). + links: + homepage: https://pypi.org/ + # setup: https://pip.pypa.io/en/stable/installation/ + package: https://pypi.org/project/httpie/ + commands: + install: + - python -m pip install --upgrade pip wheel + - python -m pip install httpie + upgrade: + - python -m pip install --upgrade pip wheel + - python -m pip install --upgrade httpie + + snap-linux: + title: Snapcraft (Linux) + name: Snapcraft + links: + homepage: https://snapcraft.io/ + setup: https://snapcraft.io/docs/installing-snapd + package: https://snapcraft.io/httpie + commands: + install: + - snap install httpie + upgrade: + - snap refresh httpie + + snap-mac: + title: Snapcraft (macOS) + name: Snapcraft + links: + homepage: https://snapcraft.io/ + setup: https://snapcraft.io/docs/installing-snapd + package: https://snapcraft.io/httpie + commands: + install: + - snap install httpie + upgrade: + - snap refresh httpie + + spack-linux: + title: Spack (Linux) + name: Spack + links: + homepage: https://spack.readthedocs.io/en/latest/index.html + setup: https://spack.readthedocs.io/en/latest/getting_started.html#installation + commands: + install: + - spack install httpie + upgrade: + - spack install httpie + + spack-mac: + title: Spack (macOS) + name: Spack + links: + homepage: https://spack.readthedocs.io/en/latest/index.html + setup: https://spack.readthedocs.io/en/latest/getting_started.html#installation + commands: + install: + - spack install httpie + upgrade: + - spack install httpie + + xbps-install: + title: Void Linux + name: XBPS + links: + homepage: https://docs.voidlinux.org/xbps/index.html + commands: + install: + - xbps-install -Su + - xbps-install -S httpie + upgrade: + - xbps-install -Su + - xbps-install -Su httpie + + yum: + title: CentOS and RHEL + name: Yum + note: Also works for other RHEL-derived distributions like ClearOS, Oracle Linux, etc. + links: + homepage: http://yum.baseurl.org/ + package: https://src.fedoraproject.org/rpms/httpie + commands: + install: + - yum update + - yum install epel-release + - yum install httpie + upgrade: + - yum update + - yum upgrade httpie diff --git a/docs/linter/mdl-styles.rb b/docs/markdownlint.rb similarity index 93% rename from docs/linter/mdl-styles.rb rename to docs/markdownlint.rb index a5938b7211..397f475755 100644 --- a/docs/linter/mdl-styles.rb +++ b/docs/markdownlint.rb @@ -1,3 +1,5 @@ +# Rules for + # Load all rules by default all diff --git a/setup.py b/setup.py index fccac462bb..45826d2d17 100644 --- a/setup.py +++ b/setup.py @@ -22,8 +22,10 @@ 'flake8-tuple', 'pyopenssl', 'pytest-cov', + 'pyyaml', 'twine', 'wheel', + 'Jinja2' ] install_requires = [ 'charset_normalizer>=2.0.0', From 93114072c85dbce8a49aab5afcc99b59020abcc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 6 Oct 2021 11:21:54 +0200 Subject: [PATCH 0848/1182] Fix looked path for workflow testing packages --- .github/workflows/test-package-linux-snap.yml | 2 +- .github/workflows/test-package-mac-brew.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-package-linux-snap.yml b/.github/workflows/test-package-linux-snap.yml index 6442378159..2f717e2a0c 100644 --- a/.github/workflows/test-package-linux-snap.yml +++ b/.github/workflows/test-package-linux-snap.yml @@ -1,7 +1,7 @@ on: pull_request: paths: - - .github/workflows/packaging-linux-snap.yml + - .github/workflows/test-package-linux-snap.yml - snapcraft.yaml jobs: diff --git a/.github/workflows/test-package-mac-brew.yml b/.github/workflows/test-package-mac-brew.yml index 0aeeec25b3..aa68b7ff74 100644 --- a/.github/workflows/test-package-mac-brew.yml +++ b/.github/workflows/test-package-mac-brew.yml @@ -3,7 +3,7 @@ name: Mac brew on: pull_request: paths: - - .github/workflows/packaging-mac-brew.yml + - .github/workflows/test-package-mac-brew.yml - extras/httpie.rb jobs: From 7989e438d2806e97f85f90c76a450bda1cf0fec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 6 Oct 2021 16:45:44 +0200 Subject: [PATCH 0849/1182] Add documentation about our release process (#1159) * Add documentation about our release process * Fixes * Add company-related tasks, enable back WIP pages * Fix WIP links * Add AOSC OS * Add WIP for AOSC OS * Tweak * Remove maintainers email IDs * Use GH nicknames * Remove useless WIP for brew * Tweaks --- .github/workflows/test-package-mac-brew.yml | 4 +- Makefile | 6 +- docs/packaging/README.md | 49 ++++++++++++ docs/packaging/brew/README.md | 33 ++++++++ {extras => docs/packaging/brew}/brew-deps.py | 0 {extras => docs/packaging/brew}/httpie.rb | 17 ++-- docs/packaging/linux-alpine/APKBUILD | 33 ++++++++ docs/packaging/linux-alpine/README.md | 67 ++++++++++++++++ docs/packaging/linux-aosc/README.md | 24 ++++++ docs/packaging/linux-aosc/spec | 5 ++ docs/packaging/linux-arch/PKGBUILD | 46 +++++++++++ docs/packaging/linux-arch/README.md | 22 ++++++ docs/packaging/linux-centos/README.md | 26 +++++++ docs/packaging/linux-debian/README.md | 29 +++++++ docs/packaging/linux-fedora/README.md | 48 ++++++++++++ docs/packaging/linux-gentoo/Manifest | 2 + docs/packaging/linux-gentoo/README.md | 78 +++++++++++++++++++ .../linux-gentoo/httpie-2.5.0.ebuild | 42 ++++++++++ docs/packaging/linux-gentoo/metadata.xml | 28 +++++++ docs/packaging/linux-void/README.md | 68 ++++++++++++++++ docs/packaging/linux-void/template | 28 +++++++ docs/packaging/mac-ports/Portfile | 49 ++++++++++++ docs/packaging/mac-ports/README.md | 40 ++++++++++ docs/packaging/snapcraft/README.md | 51 ++++++++++++ docs/packaging/spack/README.md | 54 +++++++++++++ docs/packaging/spack/package.py | 32 ++++++++ docs/packaging/windows-chocolatey/README.md | 20 +++++ 27 files changed, 883 insertions(+), 18 deletions(-) create mode 100644 docs/packaging/README.md create mode 100644 docs/packaging/brew/README.md rename {extras => docs/packaging/brew}/brew-deps.py (100%) rename {extras => docs/packaging/brew}/httpie.rb (74%) create mode 100644 docs/packaging/linux-alpine/APKBUILD create mode 100644 docs/packaging/linux-alpine/README.md create mode 100644 docs/packaging/linux-aosc/README.md create mode 100644 docs/packaging/linux-aosc/spec create mode 100644 docs/packaging/linux-arch/PKGBUILD create mode 100644 docs/packaging/linux-arch/README.md create mode 100644 docs/packaging/linux-centos/README.md create mode 100644 docs/packaging/linux-debian/README.md create mode 100644 docs/packaging/linux-fedora/README.md create mode 100644 docs/packaging/linux-gentoo/Manifest create mode 100644 docs/packaging/linux-gentoo/README.md create mode 100644 docs/packaging/linux-gentoo/httpie-2.5.0.ebuild create mode 100644 docs/packaging/linux-gentoo/metadata.xml create mode 100644 docs/packaging/linux-void/README.md create mode 100644 docs/packaging/linux-void/template create mode 100644 docs/packaging/mac-ports/Portfile create mode 100644 docs/packaging/mac-ports/README.md create mode 100644 docs/packaging/snapcraft/README.md create mode 100644 docs/packaging/spack/README.md create mode 100644 docs/packaging/spack/package.py create mode 100644 docs/packaging/windows-chocolatey/README.md diff --git a/.github/workflows/test-package-mac-brew.yml b/.github/workflows/test-package-mac-brew.yml index aa68b7ff74..fbaf52c1c3 100644 --- a/.github/workflows/test-package-mac-brew.yml +++ b/.github/workflows/test-package-mac-brew.yml @@ -1,10 +1,8 @@ -name: Mac brew - on: pull_request: paths: - .github/workflows/test-package-mac-brew.yml - - extras/httpie.rb + - docs/packaging/brew/httpie.rb jobs: brew: diff --git a/Makefile b/Makefile index 1a0e96bdec..2bcc269792 100644 --- a/Makefile +++ b/Makefile @@ -130,7 +130,7 @@ pycodestyle: codestyle codestyle: @echo $(H1)Running flake8$(H1END) @[ -f $(VENV_BIN)/flake8 ] || $(VENV_PIP) install --upgrade --editable '.[dev]' - $(VENV_BIN)/flake8 httpie/ tests/ extras/ *.py + $(VENV_BIN)/flake8 httpie/ tests/ docs/packaging/brew/ *.py @echo @@ -196,14 +196,14 @@ uninstall-httpie: ############################################################################### brew-deps: - extras/brew-deps.py + docs/packaging/brew/brew-deps.py brew-test: @echo $(H1)Uninstalling httpie$(H1END) - brew uninstall httpie @echo $(H1)Building from source…$(H1END) - - brew install --build-from-source ./extras/httpie.rb + - brew install --build-from-source ./docs/packaging/brew/httpie.rb @echo $(H1)Verifying…$(H1END) brew test httpie diff --git a/docs/packaging/README.md b/docs/packaging/README.md new file mode 100644 index 0000000000..0f329368c9 --- /dev/null +++ b/docs/packaging/README.md @@ -0,0 +1,49 @@ +# HTTPie release process + +Welcome on the documentation part of the **HTTPie release process**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions, then you can find all you need for your OS on [that page](https://httpie.io/docs#installation). In the case you do not find your OS, [let us know](https://github.com/httpie/httpie/issues/). +- If you are looking for technical information about the HTTPie packaging, then you are at the good place. + +## About + +You are looking at the HTTPie packaging documentation, where you will find valuable information about how we manage to release HTTPie to lots of OSes, including technical data that may be worth reading if you are a package maintainer. + +The overall release process starts simple: + +1. Do the [PyPi](https://pypi.org/project/httpie/) publication. +2. Then, handle company-related tasks. +3. Finally, follow OS-specific steps, described in documents below, to send patches downstream. + +## First, PyPi + +Let's do the release on [PyPi](https://pypi.org/project/httpie/). +That is done quite easily by manually triggering the [release workflow](https://github.com/httpie/httpie/actions/workflows/release.yml). + +## Then, company-specific tasks + +- Update the HTTPie version bundled into termible ([example](https://github.com/httpie/termible/pull/1)). + +## Finally, spread dowstream + +Find out how we do release new versions for each and every supported OS in the following table. +A more complete state of deployment can be found on [repology](https://repology.org/project/httpie/versions), including unofficial packages. + +| OS | Maintainer | +| ------------------------------------------------------------------: | -------------- | +| [Alpine](linux-alpine/README.md) | **HTTPie** | +| [Arch Linux, and derived](linux-arch/README.md) | trusted person | +| :construction: [AOSC OS](linux-aosc/README.md) | **HTTPie** | +| [CentOS, RHEL, and derived](linux-centos/README.md) | trusted person | +| [Debian, Ubuntu, and derived](linux-debian/README.md) | trusted person | +| [Fedora](linux-fedora/README.md) | trusted person | +| [Gentoo](linux-gentoo/README.md) | **HTTPie** | +| :construction: [Homebrew, Linuxbrew](brew/README.md) | **HTTPie** | +| :construction: [MacPorts](mac-ports/README.md) | **HTTPie** | +| [Snapcraft](snapcraft/README.md) | **HTTPie** | +| [Spack](spack/README.md) | **HTTPie** | +| [Void Linux](linux-void/README.md) | **HTTPie** | +| :construction: [Windows — Chocolatey](windows-chocolatey/README.md) | **HTTPie** | + +:new: You do not find your system or you would like to see HTTPie supported on another OS? Then [let us know](https://github.com/httpie/httpie/issues/). diff --git a/docs/packaging/brew/README.md b/docs/packaging/brew/README.md new file mode 100644 index 0000000000..ac5919ead6 --- /dev/null +++ b/docs/packaging/brew/README.md @@ -0,0 +1,33 @@ +# HTTPie on Homebrew, and Linuxbrew + +Welcome to the documentation about **packaging HTTPie for Homebrew**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on Homebrew, then you can find them on [that page](https://httpie.io/docs#homebrew) ([that one](https://httpie.io/docs#linuxbrew) for Linuxbrew). +- If you are looking for technical information about the HTTPie packaging on Homebrew, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Homebrew. They apply to Linuxbrew as well. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +## Overall process + +:construction: Work in progress. + +First, update the current Formula: + +```bash +make brew-deps +# Copy-paste content into downstream/mac/brew/httpie.rb +git add downstream/mac/brew/httpie.rb +git commit -s -m 'Update brew formula to XXX' +``` + +That [GitHub workflow](https://github.com/httpie/httpie/actions/workflows/test-package-mac-brew.yml) will test the formula when `downstream/mac/brew/httpie.rb` is changed in a pull request. + +Then, open a pull request with those changes to the [downstream file]([ file](https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb)). + +## Hacking + +:construction: Work in progress. diff --git a/extras/brew-deps.py b/docs/packaging/brew/brew-deps.py similarity index 100% rename from extras/brew-deps.py rename to docs/packaging/brew/brew-deps.py diff --git a/extras/httpie.rb b/docs/packaging/brew/httpie.rb similarity index 74% rename from extras/httpie.rb rename to docs/packaging/brew/httpie.rb index 25d45ce4cc..d10be2b97d 100644 --- a/extras/httpie.rb +++ b/docs/packaging/brew/httpie.rb @@ -1,9 +1,3 @@ -# The latest Homebrew formula as submitted to Homebrew/homebrew-core. -# Only useful for testing until it gets accepted by homebrew maintainers. -# (It will need to be updated from the repo version before next release.) -# -# https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb -# class Httpie < Formula include Language::Python::Virtualenv @@ -15,12 +9,11 @@ class Httpie < Formula head "https://github.com/httpie/httpie.git" bottle do - sha256 cellar: :any_skip_relocation, arm64_big_sur: "a0c123788163512698a0d284cfd6cb8125d8355aa59c3e4639df90b4388f94b5" - sha256 cellar: :any_skip_relocation, big_sur: "4e4bc9dd47e194bd45e9c0e36039942aed76a465871980924f0f27e83681d918" - sha256 cellar: :any_skip_relocation, catalina: "72dfebccff912bdb3913860983faf59c07c74db737ad4bf56143713236803821" - sha256 cellar: :any_skip_relocation, mojave: "4733686b9a1564835b6662e758dd39dd80fcb940b684af57485392bb9d6bf04e" - sha256 cellar: :any_skip_relocation, x86_64_linux: "914d67f6d9f732a7888ba2e35cf9c00525fb24917b6610544125b7bba545c7fc" - sha256 cellar: :any_skip_relocation, high_sierra: "87e7348b6fb40fd8e4f7597937952469601962189e62d321b8cb4fa421e035ef" + sha256 cellar: :any_skip_relocation, arm64_big_sur: "01115f69aff0399b3f73af09899a42a14343638a4624a35749059cc732c49cdc" + sha256 cellar: :any_skip_relocation, big_sur: "53f07157f00edf8193b7d4f74f247f53e1796fbc3e675cd2fbaa4b9dc2bad62c" + sha256 cellar: :any_skip_relocation, catalina: "7cf216fdee98208856d654060fdcad3968623d7ed27fcdeba27d3120354c9a9f" + sha256 cellar: :any_skip_relocation, mojave: "28adb5aed8c1c2b39c51789f242ff0dffde39073e161deb379c79184d787d063" + sha256 cellar: :any_skip_relocation, x86_64_linux: "91cb8c332c643bd8b1d0a8f3ec0acd4770b407991f6de1fd320d675f2b2e95ec" end depends_on "python@3.9" diff --git a/docs/packaging/linux-alpine/APKBUILD b/docs/packaging/linux-alpine/APKBUILD new file mode 100644 index 0000000000..9669e69b9c --- /dev/null +++ b/docs/packaging/linux-alpine/APKBUILD @@ -0,0 +1,33 @@ +# Contributor: Fabian Affolter +# Maintainer: Fabian Affolter +# Contributor: Daniel Isaksen +# Contributor: Mickaël Schoentgen +pkgname=httpie +pkgver=2.5.0 +pkgrel=0 +pkgdesc="CLI, cURL-like tool" +url="https://httpie.org/" +arch="noarch" +license="BSD-3-Clause" +depends="python3 py3-setuptools py3-requests py3-pygments py3-requests-toolbelt py3-pysocks py3-defusedxml" +makedepends="py3-setuptools" +checkdepends="py3-pytest py3-pytest-httpbin py3-responses" +source="https://files.pythonhosted.org/packages/source/h/httpie/httpie-$pkgver.tar.gz" + +# secfixes: +# 1.0.3-r0: +# - CVE-2019-10751 + +build() { + python3 setup.py build +} + +check() { + python3 -m pytest ./httpie ./tests +} + +package() { + python3 setup.py install --prefix=/usr --root="$pkgdir" +} + +sha512sums="3bfe572b03bfde87d5a02f9ba238f9493b32e587c33fd30600a4dd6a45082eedcb2b507c7f1e3e75a423cbdcc1ff0556138897dffb7888d191834994eae9a2aa httpie-2.5.0.tar.gz" diff --git a/docs/packaging/linux-alpine/README.md b/docs/packaging/linux-alpine/README.md new file mode 100644 index 0000000000..225bd74f18 --- /dev/null +++ b/docs/packaging/linux-alpine/README.md @@ -0,0 +1,67 @@ +# HTTPie on Alpine Linux + +Welcome to the documentation about **packaging HTTPie for Alpine Linux**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on Alpine Linux, then you can find them on [that page](https://httpie.io/docs#alpine-linux). +- If you are looking for technical information about the HTTPie packaging on Alpine Linux, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Alpine Linux. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +## Overall process + +Open a pull request to update the [downstream file](https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/httpie/APKBUILD) ([example](https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/25075)). + +Notes: + +- The `pkgrel` value must be set to `0`. +- The commit message must be `community/httpie: upgrade to XXX`. +- The commit must be signed-off (`git commit -s`). + +## Hacking + +Launch the docker image: + +```bash +docker pull alpine +docker run -it --rm alpine +``` + +From inside the container: + +```bash +# Install tools +apk add alpine-sdk sudo + +# Add a user (password required) +adduser me +addgroup me abuild +echo "me ALL=(ALL) ALL" >> /etc/sudoers + +# Switch user +su - me + +# Create a private key (not used but required) +abuild-keygen -a -i + +# Clone +git clone --depth=1 https://gitlab.alpinelinux.org/alpine/aports.git +cd aports/community/httpie + +# Retrieve the patch of the latest HTTPie version +curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-alpine/APKBUILD \ + -o APKBUILD + +# Build the package +abuild -r + +# Install the package +sudo apk add --repository ~/packages/community httpie + +# And test it! +http --version +https --version +``` diff --git a/docs/packaging/linux-aosc/README.md b/docs/packaging/linux-aosc/README.md new file mode 100644 index 0000000000..72cc67439c --- /dev/null +++ b/docs/packaging/linux-aosc/README.md @@ -0,0 +1,24 @@ +# HTTPie on AOSC OS + +Welcome to the documentation about **packaging HTTPie for AOSC OS**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for technical information about the HTTPie packaging on AOSC OS, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for AOSC OS. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +## Overall process + +Open a pull request to update the [downstream file](https://github.com/AOSC-Dev/aosc-os-abbs/blob/stable/extra-web/httpie/spec) ([example](https://github.com/AOSC-Dev/aosc-os-abbs/commit/d0d3ba0bcea347387bb582a1b0b1b4e518720c80)). + +Notes: + +- The commit message must be `httpie: update to XXX`. +- The commit must be signed-off (`git commit -s`). + +## Hacking + +:construction: Work in progress. diff --git a/docs/packaging/linux-aosc/spec b/docs/packaging/linux-aosc/spec new file mode 100644 index 0000000000..ee235501fd --- /dev/null +++ b/docs/packaging/linux-aosc/spec @@ -0,0 +1,5 @@ +VER=2.5.0 +SRCS="tbl::https://github.com/httpie/httpie/archive/$VER.tar.gz" +CHKSUMS="sha256::66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea" +REL=1 +CHKUPDATE="anitya::id=1337" diff --git a/docs/packaging/linux-arch/PKGBUILD b/docs/packaging/linux-arch/PKGBUILD new file mode 100644 index 0000000000..7b0b313073 --- /dev/null +++ b/docs/packaging/linux-arch/PKGBUILD @@ -0,0 +1,46 @@ +# Maintainer: Jelle van der Waa +# Maintainer: daurnimator +# Contributor: Daniel Micay +# Contributor: Thomas Weißschuh + +pkgname=httpie +pkgver=2.5.0 +pkgrel=1 +pkgdesc="human-friendly CLI HTTP client for the API era" +url="https://github.com/httpie/httpie" +depends=('python-defusedxml' + 'python-pygments' + 'python-pysocks' + 'python-requests' + 'python-requests-toolbelt') +makedepends=('python-setuptools') +checkdepends=('python-pytest' + 'python-pytest-httpbin' + 'python-responses') +conflicts=(python-httpie) +replaces=(python-httpie python2-httpie) +license=('BSD') +arch=('any') +source=($pkgname-$pkgver.tar.gz::"https://github.com/httpie/httpie/archive/$pkgver.tar.gz") +sha256sums=('66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea') + +build() { + cd $pkgname-$pkgver + python3 setup.py build +} + +package() { + cd $pkgname-$pkgver + install -Dm644 LICENSE "$pkgdir/usr/share/licenses/httpie/LICENSE" + python3 setup.py install --root="$pkgdir" --optimize=1 + + # Fix upstream, include them in MANIFEST.in and use data_files in setup.py to install them automatically + # TODO: add zsh support + install -Dm644 extras/httpie-completion.bash "$pkgdir"/usr/share/bash-completion/completions/http + install -Dm644 extras/httpie-completion.fish "$pkgdir"/usr/share/fish/vendor_completions.d/http.fish +} + +check() { + cd $pkgname-$pkgver + PYTHONDONTWRITEBYTECODE=1 python3 setup.py test +} diff --git a/docs/packaging/linux-arch/README.md b/docs/packaging/linux-arch/README.md new file mode 100644 index 0000000000..36c985350b --- /dev/null +++ b/docs/packaging/linux-arch/README.md @@ -0,0 +1,22 @@ +# HTTPie on Arch Linux, and derived + +Welcome to the documentation about **packaging HTTPie for Arch Linux**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on Arch Linux, then you can find them on [that page](https://httpie.io/docs#arch-linux). +- If you are looking for technical information about the HTTPie packaging on Arch Linux, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Arch Linux. They apply to Arch-derived distributions as well, like ArcoLinux, EndeavourOS, Artix Linux, etc. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +## Overall process + +Note: Sending patches downstream does not seem easy. We failed to find where is located the package file on . So we are relying on the last maintainer, daurnimator, and it works pretty well so far. + +Check and if the version is outdated, simply [report it](https://archlinux.org/packages/community/any/httpie/flag/). + +## Hacking + +Left blank on purpose, we will fill that section when we will have access to the downstream repository. diff --git a/docs/packaging/linux-centos/README.md b/docs/packaging/linux-centos/README.md new file mode 100644 index 0000000000..be809ea2a3 --- /dev/null +++ b/docs/packaging/linux-centos/README.md @@ -0,0 +1,26 @@ +# HTTPie on CentOS, RHEL, and derived + +Welcome to the documentation about **packaging HTTPie for CentOS and RHEL**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on CentOS, then you can find them on [that page](https://httpie.io/docs#centos-and-rhel). +- If you are looking for technical information about the HTTPie packaging on CentOS, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for CentOS. They apply to RHEL as well, and any RHEL-derived distributions like ClearOS, Oracle Linux, etc. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +The current maintainer is [Mikel Olasagasti](https://github.com/kaxero). + +## Overall process + +Same as [Fedora](../linux-fedora/README.md#overall-process). + +## Q/A with Mikel + +Q: What should we do to help seeing a new version on CentOS? + +A: When a new release is published Miro and I get notified by [release-monitoring](https://release-monitoring.org/project/1337/), that fills a BugZilla ticket reporting a new version being available. + +The system also tries to create a simple patch to update the spec file, but in the case of CentOS it needs some manual revision. For example for 2.5.0 `defuxedxml` dep is required. Maybe with CentOS-9 and some new macros that are available now in Fedora it can be automated same way. But even the bump can be automated, maintainers should check for license changes, new binaries/docs/ and so on. diff --git a/docs/packaging/linux-debian/README.md b/docs/packaging/linux-debian/README.md new file mode 100644 index 0000000000..dfea5a8af1 --- /dev/null +++ b/docs/packaging/linux-debian/README.md @@ -0,0 +1,29 @@ +# HTTPie on Debian, Ubuntu, and derived + +Welcome to the documentation about **packaging HTTPie for Debian GNU/Linux**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on Debian GNU/Linux, then you can find them on [that page](https://httpie.io/docs#debian-and-ubuntu). +- If you are looking for technical information about the HTTPie packaging on Debian GNU/Linux, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Debian GNU/Linux. They apply to Ubuntu as well, and any Debian-derived distributions like MX Linux, Linux Mint, deepin, Pop!_OS, KDE neon, Zorin OS, elementary OS, Kubuntu, Devuan, Linux Lite, Peppermint OS, Lubuntu, antiX, Xubuntu, etc. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +The current maintainer is Bartosz Fenski. + +## Overall process + +Open a new bug on the Debian Bug Tracking System by sending an email: + +- To: `Debian Bug Tracking System ` +- Subject: `httpie: Version XXX available` +- Message template ([example](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=993937)): + + ```email + Package: httpie + Severity: wishlist + + + ``` diff --git a/docs/packaging/linux-fedora/README.md b/docs/packaging/linux-fedora/README.md new file mode 100644 index 0000000000..ae1d035211 --- /dev/null +++ b/docs/packaging/linux-fedora/README.md @@ -0,0 +1,48 @@ +# HTTPie on Fedora + +Welcome to the documentation about **packaging HTTPie for Fedora**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on Fedora, then you can find them on [that page](https://httpie.io/docs#fedora). +- If you are looking for technical information about the HTTPie packaging on Fedora, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Fedora. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +The current maintainer is [Miro Hrončok](https://github.com/hroncok). + +## Overall process + +We added the [.packit.yaml](https://github.com/httpie/httpie/blob/master/.packit.yaml) local file. +It unlocks real-time Fedora checks on pull requests and new releases. + +So there is nothing to do on our side: `Packit` will see the new release and open a pull request [there](https://src.fedoraproject.org/rpms/httpie). Then, the Fedora maintainer will review and merge. + +It is also possible to follow [user feedbacks](https://bodhi.fedoraproject.org/updates/?packages=httpie) for all builds. + +## Q/A with Miro + +Q: What would the command to install the latest stable version look like? + +A: Assuming the latest stable version is already propagated to Fedora: + +```bash +# Note that yum is an alias to dnf. +$ sudo dnf install httpie +``` + +Q: Will dnf/yum upgrade then update to the latest? + +A: Yes, assuming the same as above. + +Q: Are new versions backported automatically? + +A: No. The process is: + +1. A new HTTPie release is created on Github. +2. A pull request for Fedora `rawhide` (the development version of Fedora, currently Fedora 35) is created. +3. A Fedora packager (usually Miro) sanity checks the pull request and merges, builds. HTTPie is updated in `rawhide` within 24 hours (sometimes more, for unrelated issues). +4. A Fedora packager decides whether the upgrade is suitable for stable Fedora releases (currently 34, 33), if so, merges the changes there. +5. (if the above is yes) The new version of HTTPie lands in `updates-testing` repo where it waits for user feedback and lands within ~1 week for broad availability. diff --git a/docs/packaging/linux-gentoo/Manifest b/docs/packaging/linux-gentoo/Manifest new file mode 100644 index 0000000000..3779e5c114 --- /dev/null +++ b/docs/packaging/linux-gentoo/Manifest @@ -0,0 +1,2 @@ +DIST httpie-2.4.0.tar.gz 1772537 BLAKE2B 111451cc7dc353d5b586554f98ac715a3198f03e74d261944a5f021d2dcc948455500800222b323d182a2a067d0549bda7c318ab3a6c934b9a9beec64aff2db2 SHA512 44cc7ff4fe0f3d8c53a7dd750465f6b56c36f5bbac06d22b760579bd60949039e82313845699669a659ec91adc69dbeac22c06ddd63af64e6f2e0edecf3e732a +DIST httpie-2.5.0.tar.gz 1105177 BLAKE2B 6e16868c81522d4e6d2fc0a4e093c190f18ced720b35217930865ae3f8e168193cc33dfecc13c5d310f52647d6e79d17b247f56e56e8586d633a2d9502be66a7 SHA512 f14aa23fea7578181b9bd6ededea04de9ddf0b2f697b23f76d2d96e2c17b95617318c711750bad6af550400dbc03732ab17fdf84e59d577f33f073e600a55330 diff --git a/docs/packaging/linux-gentoo/README.md b/docs/packaging/linux-gentoo/README.md new file mode 100644 index 0000000000..35fbce7cb7 --- /dev/null +++ b/docs/packaging/linux-gentoo/README.md @@ -0,0 +1,78 @@ +# HTTPie on Gentoo + +Welcome to the documentation about **packaging HTTPie for Gentoo**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on Gentoo, then you can find them on [that page](https://httpie.io/docs#gentoo). +- If you are looking for technical information about the HTTPie packaging on Gentoo, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Gentoo. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +## Overall process + +Open a pull request to create `httpie-XXX.ebuild` and update `Manifest`. + +- Here is how to calculate the size and checksum (replace `2.5.0` with the correct version): + + ```bash + # Download + $ wget https://github.com/httpie/httpie/archive/2.5.0.tar.gz + + # Size + $ stat --printf="%s\n" 2.5.0.tar.gz + 1105177 + + # Checksum + $ openssl dgst -blake2b512 2.5.0.tar.gz + BLAKE2b512(2.5.0.tar.gz)= 6e16868c81522d4e6d2fc0a4e093c190f18ced720b35217930865ae3f8e168193cc33dfecc13c5d310f52647d6e79d17b247f56e56e8586d633a2d9502be66a7 + ``` + +- The commit message must be `net-misc/httpie: version bump to XXX`. +- The commit must be signed-off (`git commit -s`). + +## Hacking + +Launch the docker image: + +```bash +docker pull gentoo/stage3 +docker run -it --rm gentoo/stage3 +``` + +From inside the container: + +```bash +# Install tools +emerge --sync +emerge pkgcheck repoman + +# Go to the package location +cd /var/db/repos/gentoo/net-misc/httpie + +# Retrieve the patch of the latest HTTPie version +# (only files that were modified since the previous release) +curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-gentoo/httpie-XXX.ebuild \ + -o httpie-XXX.ebuild +curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-gentoo/Manifest \ + -o Manifest +curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-gentoo/metadata.xml \ + -o metadata.xml + +# Basic checks +repoman manifest +repoman full -d -x +pkgcheck scan + +# Build and install the package +emerge --with-test-deps httpie-XXX.ebuild + +# Run the tests suite +ebuild httpie-XXX.ebuild clean test + +# And test it! +http --version +https --version +``` diff --git a/docs/packaging/linux-gentoo/httpie-2.5.0.ebuild b/docs/packaging/linux-gentoo/httpie-2.5.0.ebuild new file mode 100644 index 0000000000..00420956f6 --- /dev/null +++ b/docs/packaging/linux-gentoo/httpie-2.5.0.ebuild @@ -0,0 +1,42 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=7 + +DISTUTILS_USE_SETUPTOOLS=rdepend +PYTHON_COMPAT=( python3_{8,9,10} ) +PYTHON_REQ_USE="ssl(+)" + +inherit bash-completion-r1 distutils-r1 + +DESCRIPTION="Modern command line HTTP client" +HOMEPAGE="https://httpie.io/ https://pypi.org/project/httpie/" +SRC_URI="https://github.com/httpie/httpie/archive/${PV}.tar.gz -> ${P}.tar.gz" + +LICENSE="BSD" +SLOT="0" +KEYWORDS="~amd64 ~x86" + +RDEPEND=" + dev-python/defusedxml[${PYTHON_USEDEP}] + dev-python/pygments[${PYTHON_USEDEP}] + >=dev-python/requests-2.22.0[${PYTHON_USEDEP}] + >=dev-python/requests-toolbelt-0.9.1[${PYTHON_USEDEP}] +" +BDEPEND=" + test? ( + ${RDEPEND} + dev-python/pyopenssl[${PYTHON_USEDEP}] + dev-python/pytest-httpbin[${PYTHON_USEDEP}] + dev-python/responses[${PYTHON_USEDEP}] + ) +" + +distutils_enable_tests pytest + +python_install_all() { + newbashcomp extras/httpie-completion.bash http + insinto /usr/share/fish/vendor_completions.d + newins extras/httpie-completion.fish http.fish + distutils-r1_python_install_all +} diff --git a/docs/packaging/linux-gentoo/metadata.xml b/docs/packaging/linux-gentoo/metadata.xml new file mode 100644 index 0000000000..4bfbb6afe5 --- /dev/null +++ b/docs/packaging/linux-gentoo/metadata.xml @@ -0,0 +1,28 @@ + + + + + mickael@apible.io + Mickaël Schoentgen + + + proxy-maint@gentoo.org + Proxy Maintainers + + + HTTPie (pronounced aitch-tee-tee-pie) is a command line HTTP + client. Its goal is to make CLI interaction with web services as + human-friendly as possible. It provides a simple http command + that allows for sending arbitrary HTTP requests using a simple + and natural syntax, and displays colorized output. HTTPie can be + used for testing, debugging, and generally interacting with HTTP + servers. + + + https://github.com/httpie/httpie/issues + https://raw.githubusercontent.com/httpie/httpie/master/CHANGELOG.md + https://httpie.io/docs + httpie/httpie + httpie + + diff --git a/docs/packaging/linux-void/README.md b/docs/packaging/linux-void/README.md new file mode 100644 index 0000000000..3b6c9143e1 --- /dev/null +++ b/docs/packaging/linux-void/README.md @@ -0,0 +1,68 @@ +# HTTPie on Void Linux + +Welcome to the documentation about **packaging HTTPie for Void Linux**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on Void Linux, then you can find them on [that page](https://httpie.io/docs#void-linux). +- If you are looking for technical information about the HTTPie packaging on Void Linux, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Void Linux. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +## Overall process + +Open a pull request to update the [downstream file](https://github.com/void-linux/void-packages/blob/master/srcpkgs/httpie/template) ([example](https://github.com/void-linux/void-packages/pull/32905)). + +- The commit message must be `httpie: update to XXX.`. +- The commit must be signed-off (`git commit -s`). + +## Hacking + +Launch the docker image: + +```bash +docker pull voidlinux/voidlinux +docker run -it --rm voidlinux/voidlinux +``` + +From inside the container: + +```bash +# Sync and upgrade once, assume error comes from xbps update +xbps-install -Syu +# Install tools +xbps-install -y git xtools file util-linux binutils bsdtar coreutils + +# Clone +git clone --depth=1 git://github.com/void-linux/void-packages.git void-packages-src +cd void-packages-src + +# Retrieve the patch of the latest HTTPie version +curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-void/template \ + -o srcpkgs/httpie/template + +# Check the package +xlint srcpkgs/httpie/template + +# Link / to /masterdir +ln -s / masterdir + +# Enable ethereal chroot-style +export XBPS_ALLOW_CHROOT_BREAKOUT=yes +./xbps-src binary-bootstrap +./xbps-src chroot + +# Build the package +cd void-packages +export SOURCE_DATE_EPOCH=0 +./xbps-src pkg httpie + +# Install the package +xbps-install --repository=hostdir/binpkgs httpie + +# And finally test it! +http --version +https --version +``` diff --git a/docs/packaging/linux-void/template b/docs/packaging/linux-void/template new file mode 100644 index 0000000000..1a9a418a42 --- /dev/null +++ b/docs/packaging/linux-void/template @@ -0,0 +1,28 @@ +# Template file for 'httpie' +pkgname=httpie +version=2.5.0 +revision=1 +build_style=python3-module +hostmakedepends="python3-setuptools" +depends="python3-setuptools python3-requests python3-requests-toolbelt + python3-Pygments python3-pysocks python3-defusedxml" +short_desc="Human-friendly command line HTTP client" +maintainer="Mickaël Schoentgen " +license="BSD-3-Clause" +homepage="https://httpie.io/" +changelog="https://raw.githubusercontent.com/httpie/httpie/${version}/CHANGELOG.md" +distfiles="https://github.com/httpie/httpie/archive/${version}.tar.gz" +checksum=66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea +make_check=no # needs pytest_httpbin which is not packaged + +post_install() { + vcompletion extras/httpie-completion.bash bash http + vcompletion extras/httpie-completion.fish fish http + vlicense LICENSE +} + +python3-httpie_package() { + build_style=meta + short_desc+=" (transitional dummy package)" + depends="httpie>=${version}_${revision}" +} diff --git a/docs/packaging/mac-ports/Portfile b/docs/packaging/mac-ports/Portfile new file mode 100644 index 0000000000..3f6218e963 --- /dev/null +++ b/docs/packaging/mac-ports/Portfile @@ -0,0 +1,49 @@ +# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8::et:sw=4:ts=4:sts=4 + +PortSystem 1.0 +PortGroup github 1.0 +PortGroup python 1.0 + +github.setup httpie httpie 2.5.0 + +maintainers {g5pw @g5pw} openmaintainer +categories net +description HTTPie is a command line HTTP client, a user-friendly cURL replacement. +long_description HTTPie (pronounced aych-tee-tee-pie) is a command line HTTP \ + client. Its goal is to make CLI interaction with web \ + services as human-friendly as possible. It provides a simple \ + http command that allows for sending arbitrary HTTP requests \ + using a simple and natural syntax, and displays colorized \ + responses. HTTPie can be used for testing, debugging, and \ + generally interacting with HTTP servers. +platforms darwin +license BSD +homepage https://httpie.io/ + +variant python36 conflicts python37 python38 python39 description "Use Python 3.6" {} +variant python37 conflicts python36 python38 python39 description "Use Python 3.7" {} +variant python38 conflicts python36 python37 python39 description "Use Python 3.8" {} +variant python39 conflicts python36 python37 python38 description "Use Python 3.9" {} + +if {[variant_isset python36]} { + python.default_version 36 +} elseif {[variant_isset python37]} { + python.default_version 37 +} elseif {[variant_isset python39]} { + python.default_version 39 +} else { + default_variants +python38 + python.default_version 38 +} + +depends_lib-append port:py${python.version}-requests \ + port:py${python.version}-requests-toolbelt \ + port:py${python.version}-pygments \ + port:py${python.version}-socks \ + port:py${python.version}-defusedxml + +checksums rmd160 88d227d52199c232c0ddf704a219d1781b1e77ee \ + sha256 00c4b7bbe7f65abe1473f37b39d9d9f8f53f44069a430ad143a404c01c2179fc \ + size 1105185 + +python.link_binaries_suffix diff --git a/docs/packaging/mac-ports/README.md b/docs/packaging/mac-ports/README.md new file mode 100644 index 0000000000..aa7ce3b2c2 --- /dev/null +++ b/docs/packaging/mac-ports/README.md @@ -0,0 +1,40 @@ +# HTTPie on MacPorts + +Welcome to the documentation about **packaging HTTPie for MacPorts**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on MacPorts, then you can find them on [that page](https://httpie.io/docs#macports). +- If you are looking for technical information about the HTTPie packaging on MacPorts, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for MacPorts. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +## Overall process + +Open a pull request to update the [downstream file](https://github.com/macports/macports-ports/blob/master/net/httpie/Portfile) ([example](https://github.com/macports/macports-ports/pull/12167)). + +- Here is how to calculate the size and checksums (replace `2.5.0` with the correct version): + + ```bash + # Download the archive + $ wget https://api.github.com/repos/httpie/httpie/tarball/2.5.0 + + # Size + $ stat --printf="%s\n" 2.5.0 + 1105185 + + # Checksums + $ openssl dgst -rmd160 2.5.0 + RIPEMD160(2.5.0)= 88d227d52199c232c0ddf704a219d1781b1e77ee + $ openssl dgst -sha256 2.5.0 + SHA256(2.5.0)= 00c4b7bbe7f65abe1473f37b39d9d9f8f53f44069a430ad143a404c01c2179fc + ``` + +- The commit message must be `httpie: update to XXX`. +- The commit must be signed-off (`git commit -s`). + +## Hacking + +:construction: Work in progress. diff --git a/docs/packaging/snapcraft/README.md b/docs/packaging/snapcraft/README.md new file mode 100644 index 0000000000..3a1f71d817 --- /dev/null +++ b/docs/packaging/snapcraft/README.md @@ -0,0 +1,51 @@ +# HTTPie on Snapcraft + +Welcome to the documentation about **packaging HTTPie for Snapcraft**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on Snapcraft, then you can find them on [that page](https://httpie.io/docs#snap-linux) ([that one](https://httpie.io/docs#snap-mac) for macOS). +- If you are looking for technical information about the HTTPie packaging on Snapcraft, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Snapcraft. They apply to Snapcraft on Linux, macOS, and Windows. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +## Overall process + +Trigger a new [build](https://snapcraft.io/httpie/builds), then [promote it](https://snapcraft.io/httpie/releases). If more management is needed: [revisions supervision](https://dashboard.snapcraft.io/snaps/httpie/revisions/). + +## Hacking + +Launch the docker image: + +```bash +docker pull ubuntu/latest +docker run -it --rm ubuntu/latest +``` + +From inside the container: + +```bash +# Clone +git clone --depth=1 https://github.com/httpie/httpie.git +cd httpie + +# Build +export SNAPCRAFT_BUILD_ENVIRONMENT_CPU=8 +export SNAPCRAFT_BUILD_ENVIRONMENT_MEMORY=16G +snapcraft --debug + +# Install +sudo snap install --dangerous httpie_XXX_amd64.snap + +# Test +httpie.http --version +httpie.https --version +# Auto-aliases cannot be tested when installing a snap outside the store. +# http --version +# https --version + +# Remove +sudo snap remove httpie +``` diff --git a/docs/packaging/spack/README.md b/docs/packaging/spack/README.md new file mode 100644 index 0000000000..50bb0bda83 --- /dev/null +++ b/docs/packaging/spack/README.md @@ -0,0 +1,54 @@ +# HTTPie on Spack + +Welcome to the documentation about **packaging HTTPie for Spack**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on Spack, then you can find them on [that page](https://httpie.io/docs#spack-linux) ([that one](https://httpie.io/docs#spack-mac) for macOS). +- If you are looking for technical information about the HTTPie packaging on Spack, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Spack. They apply to Spack on Linux, and macOS. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +## Overall process + +Open a pull request to update the [downstream file](https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/httpie/package.py) ([example](https://github.com/spack/spack/pull/25888)). + +- The commit message must be `httpie: add vXXX`. +- The commit must be signed-off (`git commit -s`). + +## Hacking + +Launch the docker image: + +```bash +docker pull spack/centos7 +docker run -it --rm spack/centos7 +``` + +From inside the container: + +```bash +# Clone +git clone --depth=1 https://github.com/spack/spack.git +cd spack + +# Retrieve the patch of the latest HTTPie version +curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/spack/package.py \ + -o var/spack/repos/builtin/packages/httpie/package.py + +# Check the package +spack spec httpie + +# Check available versions (it should show the new version) +spack versions httpie + +# Install the package +spack install httpie@XXX +spack load httpie + +# And test it! +http --version +https --version +``` diff --git a/docs/packaging/spack/package.py b/docs/packaging/spack/package.py new file mode 100644 index 0000000000..b94c0bd61a --- /dev/null +++ b/docs/packaging/spack/package.py @@ -0,0 +1,32 @@ +# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other +# Spack Project Developers. See the top-level COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + +from spack import * + + +class Httpie(PythonPackage): + """Modern command line HTTP client.""" + + homepage = "https://httpie.io/" + pypi = "httpie/httpie-2.5.0.tar.gz" + + version('2.5.0', sha256='fe6a8bc50fb0635a84ebe1296a732e39357c3e1354541bf51a7057b4877e47f9') + version('0.9.9', sha256='f1202e6fa60367e2265284a53f35bfa5917119592c2ab08277efc7fffd744fcb') + version('0.9.8', sha256='515870b15231530f56fe2164190581748e8799b66ef0fe36ec9da3396f0df6e1') + + variant('socks', default=True, + description='Enable SOCKS proxy support') + + depends_on('py-setuptools', type=('build', 'run')) + depends_on('py-defusedxml', type=('build', 'run')) + depends_on('py-pygments', type=('build', 'run')) + depends_on('py-requests', type=('build', 'run')) + depends_on('py-requests-toolbelt', type=('build', 'run')) + depends_on('py-pysocks', type=('build', 'run'), when="+socks") + # Concretization problem breaks this. Unconditional for now... + # https://github.com/spack/spack/issues/3628 + # depends_on('py-argparse@1.2.1:', type=('build', 'run'), + # when='^python@:2.6,3.0:3.1') + depends_on('py-argparse@1.2.1:', type=('build', 'run'), when='^python@:2.6') diff --git a/docs/packaging/windows-chocolatey/README.md b/docs/packaging/windows-chocolatey/README.md new file mode 100644 index 0000000000..1102834191 --- /dev/null +++ b/docs/packaging/windows-chocolatey/README.md @@ -0,0 +1,20 @@ +# HTTPie on Chocolatey + +Welcome to the documentation about **packaging HTTPie for Chocolatey**. + +- If you do not know HTTPie, have a look [here](https://httpie.io/cli). +- If you are looking for HTTPie installation or upgrade instructions on Chocolatey, then you can find them on [that page](https://httpie.io/docs#chocolatey). +- If you are looking for technical information about the HTTPie packaging on Chocolatey, then you are in a good place. + +## About + +This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Chocolatey. +We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. + +## Overall process + +:construction: Work in progress. + +## Hacking + +:construction: Work in progress. From 4f1c9441c5b98bb36b542023555457ccfe479448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 6 Oct 2021 17:27:07 +0200 Subject: [PATCH 0850/1182] Fix encoding error with non-prettified encoded responses (#1168) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix encoding error with non-prettified encoded responses Removed `--format-option response.as` an promote `--response-as`: using the format option would be misleading as it is now also used by non-prettified responses. * Encoding refactoring * split --response-as into --response-mime and --response-charset * add support for Content-Type charset for requests printed to terminal * add support charset detection for requests printed to terminal without a Content-Type charset * etc. * `test_unicode.py` → `test_encoding.py` * Drop sequence length check * Clean-up tests * [skip ci] Tweaks * Use the compatible release clause for `charset_normalizer` requirement Cf. https://www.python.org/dev/peps/pep-0440/#version-specifiers * Clean-up * Partially revert d52a4833e461e1b16b7961a112ea5c53e93cd643 * Changelog * Tweak tests * [skip ci] Better test name * Cleanup tests and add request body charset detection * More test suite cleanups * Cleanup * Fix code style in test * Improve detect_encoding() docstring * Uniformize pytest.mark.parametrize() calls * [skip ci] Comment out TODOs (will be tackled in a specific PR) Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 6 +- docs/README.md | 83 +++++++----- httpie/cli/argparser.py | 2 - httpie/cli/argtypes.py | 16 +++ httpie/cli/constants.py | 2 - httpie/cli/definition.py | 29 +++-- httpie/client.py | 2 +- httpie/codec.py | 37 ------ httpie/compat.py | 50 +++++++ httpie/config.py | 2 +- httpie/constants.py | 2 - httpie/context.py | 2 +- httpie/encoding.py | 50 +++++++ httpie/models.py | 31 ++--- httpie/output/formatters/xml.py | 2 +- httpie/output/processing.py | 1 - httpie/output/streams.py | 47 +++---- httpie/output/utils.py | 54 -------- httpie/output/writer.py | 48 ++++--- httpie/utils.py | 18 +++ tests/fixtures/__init__.py | 5 +- tests/test_auth.py | 6 +- tests/test_cli.py | 2 +- tests/test_config.py | 2 +- tests/test_encoding.py | 222 ++++++++++++++++++++++++++++++++ tests/test_errors.py | 21 ++- tests/test_httpie.py | 2 +- tests/test_json.py | 62 ++++++--- tests/test_output.py | 77 ++++++----- tests/test_sessions.py | 22 ++-- tests/test_stream.py | 6 +- tests/test_unicode.py | 211 ------------------------------ tests/test_xml.py | 103 +++++---------- tests/utils/__init__.py | 2 +- 34 files changed, 652 insertions(+), 575 deletions(-) delete mode 100644 httpie/codec.py delete mode 100644 httpie/constants.py create mode 100644 httpie/encoding.py create mode 100644 tests/test_encoding.py delete mode 100644 tests/test_unicode.py diff --git a/CHANGELOG.md b/CHANGELOG.md index df49ee28a5..7e0f5ef063 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.6.0.dev0](https://github.com/httpie/httpie/compare/2.5.0...master) (unreleased) - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) -- Added `--format-options=response.as:CONTENT_TYPE` to allow overriding the response `Content-Type`. ([#1134](https://github.com/httpie/httpie/issues/1134)) -- Added `--response-as` shortcut for setting the response `Content-Type`-related `--format-options`. ([#1134](https://github.com/httpie/httpie/issues/1134)) -- Improved handling of prettified responses without correct `Content-Type` encoding. ([#1110](https://github.com/httpie/httpie/issues/1110)) +- Added `--response-encoding` to allow overriding the response encoding for terminal display purposes. ([#1168](https://github.com/httpie/httpie/issues/1168)) +- Added `--response-mime` to allow overriding the response mime type for coloring and formatting for the terminal. ([#1168](https://github.com/httpie/httpie/issues/1168)) +- Improved handling of responses with incorrect `Content-Type`. ([#1110](https://github.com/httpie/httpie/issues/1110), [#1168](https://github.com/httpie/httpie/issues/1168)) - Installed plugins are now listed in `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165)) - Fixed duplicate keys preservation of JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163)) diff --git a/docs/README.md b/docs/README.md index 6bf35d6ab7..388b98e227 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1413,6 +1413,8 @@ HTTPie does several things by default in order to make its terminal output easy ### Colors and formatting + + Syntax highlighting is applied to HTTP headers and bodies (where it makes sense). You can choose your preferred color scheme via the `--style` option if you don’t like the default one. There are dozens of styles available, here are just a few notable ones: @@ -1448,15 +1450,14 @@ You can further control the applied formatting via the more granular [format opt The `--format-options=opt1:value,opt2:value` option allows you to control how the output should be formatted when formatting is applied. The following options are available: -| Option | Default value | Shortcuts | -| ---------------: | :-----------: | ----------------------------------------- | -| `headers.sort` | `true` | `--sorted`, `--unsorted` | -| `json.format` | `true` | N/A | -| `json.indent` | `4` | N/A | -| `json.sort_keys` | `true` | `--sorted`, `--unsorted` | -| `response.as` | `''` | [`--response-as`](#response-content-type) | -| `xml.format` | `true` | N/A | -| `xml.indent` | `2` | N/A | +| Option | Default value | Shortcuts | +| ---------------: | :-----------: | ------------------------ | +| `headers.sort` | `true` | `--sorted`, `--unsorted` | +| `json.format` | `true` | N/A | +| `json.indent` | `4` | N/A | +| `json.sort_keys` | `true` | `--sorted`, `--unsorted` | +| `xml.format` | `true` | N/A | +| `xml.indent` | `2` | N/A | For example, this is how you would disable the default header and JSON key sorting, and specify a custom JSON indent size: @@ -1471,11 +1472,10 @@ sorting-related format options (currently it means JSON keys and headers): This is something you will typically store as one of the default options in your [config](#config) file. -#### Response `Content-Type` +### Response `Content-Type` -The `--response-as=value` option is a shortcut for `--format-options response.as:value`, -and it allows you to override the response `Content-Type` sent by the server. -That makes it possible for HTTPie to pretty-print the response even when the server specifies the type incorrectly. +The `--response-as=value` option allows you to override the response `Content-Type` sent by the server. +That makes it possible for HTTPie to print the response even when the server specifies the type incorrectly. For example, the following request will force the response to be treated as XML: @@ -1495,27 +1495,6 @@ $ http --response-as='text/plain; charset=big5' pie.dev/get Given the encoding is not sent by the server, HTTPie will auto-detect it. -### Binary data - -Binary data is suppressed for terminal output, which makes it safe to perform requests to URLs that send back binary data. -Binary data is also suppressed in redirected but prettified output. -The connection is closed as soon as we know that the response body is binary, - -```bash -$ http pie.dev/bytes/2000 -``` - -You will nearly instantly see something like this: - -```http -HTTP/1.1 200 OK -Content-Type: application/octet-stream - -+-----------------------------------------+ -| NOTE: binary data not shown in terminal | -+-----------------------------------------+ -``` - ### Redirected output HTTPie uses a different set of defaults for redirected output than for [terminal output](#terminal-output). @@ -1557,6 +1536,42 @@ function httpless { } ``` +### Binary data + +Binary data is suppressed for terminal output, which makes it safe to perform requests to URLs that send back binary data. +Binary data is also suppressed in redirected but prettified output. +The connection is closed as soon as we know that the response body is binary, + +```bash +$ http pie.dev/bytes/2000 +``` + +You will nearly instantly see something like this: + +```http +HTTP/1.1 200 OK +Content-Type: application/octet-stream + ++-----------------------------------------+ +| NOTE: binary data not shown in terminal | ++-----------------------------------------+ +``` + + + ## Download mode HTTPie features a download mode in which it acts similarly to `wget`. diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 5739e9d357..0b68941092 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -458,8 +458,6 @@ def _process_download_options(self): def _process_format_options(self): format_options = self.args.format_options or [] - if self.args.response_as is not None: - format_options.append('response.as:' + self.args.response_as) parsed_options = PARSED_DEFAULT_FORMAT_OPTIONS for options_group in format_options: parsed_options = parse_format_options(options_group, defaults=parsed_options) diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index f77d5e0af1..b5069b036b 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -242,3 +242,19 @@ def parse_format_options(s: str, defaults: Optional[dict]) -> dict: s=','.join(DEFAULT_FORMAT_OPTIONS), defaults=None, ) + + +def response_charset_type(encoding: str) -> str: + try: + ''.encode(encoding) + except LookupError: + raise argparse.ArgumentTypeError( + f'{encoding!r} is not a supported encoding') + return encoding + + +def response_mime_type(mime_type: str) -> str: + if mime_type.count('/') != 1: + raise argparse.ArgumentTypeError( + f'{mime_type!r} doesn’t look like a mime type; use type/subtype') + return mime_type diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index 969a2d6079..a1b78d33b2 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -85,13 +85,11 @@ PRETTY_STDOUT_TTY_ONLY = object() -EMPTY_FORMAT_OPTION = "''" DEFAULT_FORMAT_OPTIONS = [ 'headers.sort:true', 'json.format:true', 'json.indent:4', 'json.sort_keys:true', - 'response.as:' + EMPTY_FORMAT_OPTION, 'xml.format:true', 'xml.indent:2', ] diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 77be93a9dd..ff3b31b06d 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -9,7 +9,7 @@ from .argparser import HTTPieArgumentParser from .argtypes import ( KeyValueArgType, SessionNameValidator, - readable_file_arg, + readable_file_arg, response_charset_type, response_mime_type, ) from .constants import ( DEFAULT_FORMAT_OPTIONS, OUTPUT_OPTIONS, @@ -310,21 +310,30 @@ ) output_processing.add_argument( - '--response-as', - metavar='CONTENT_TYPE', + '--response-charset', + metavar='ENCODING', + type=response_charset_type, help=''' - Override the response Content-Type for formatting purposes, e.g.: + Override the response encoding for terminal display purposes, e.g.: - --response-as=application/xml - --response-as=charset=utf-8 - --response-as='application/xml; charset=utf-8' + --response-charset=utf8 + --response-charset=big5 - It is a shortcut for: - - --format-options=response.as:CONTENT_TYPE ''' ) +output_processing.add_argument( + '--response-mime', + metavar='MIME_TYPE', + type=response_mime_type, + help=''' + Override the response mime type for coloring and formatting for the terminal, e.g.: + + --response-mime=application/json + --response-mime=text/xml + + ''' +) output_processing.add_argument( '--format-options', diff --git a/httpie/client.py b/httpie/client.py index 788a56c270..5feaf48301 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -12,7 +12,7 @@ import urllib3 from . import __version__ from .cli.dicts import RequestHeadersDict -from .constants import UTF8 +from .encoding import UTF8 from .plugins.registry import plugin_manager from .sessions import get_httpie_session from .ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter diff --git a/httpie/codec.py b/httpie/codec.py deleted file mode 100644 index 61057166c2..0000000000 --- a/httpie/codec.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import Union - -from charset_normalizer import from_bytes - -from .constants import UTF8 - -Bytes = Union[bytearray, bytes] - - -def detect_encoding(content: Bytes) -> str: - """Detect the `content` encoding. - Fallback to UTF-8 when no suitable encoding found. - - """ - match = from_bytes(bytes(content)).best() - return match.encoding if match else UTF8 - - -def decode(content: Bytes, encoding: str) -> str: - """Decode `content` using the given `encoding`. - If no `encoding` is provided, the best effort is to guess it from `content`. - - Unicode errors are replaced. - - """ - if not encoding: - encoding = detect_encoding(content) - return content.decode(encoding, 'replace') - - -def encode(content: str, encoding: str) -> bytes: - """Encode `content` using the given `encoding`. - - Unicode errors are replaced. - - """ - return content.encode(encoding, 'replace') diff --git a/httpie/compat.py b/httpie/compat.py index f508bbb360..43333571d4 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -2,3 +2,53 @@ is_windows = 'win32' in str(sys.platform).lower() + + +try: + from functools import cached_property +except ImportError: + # Can be removed once we drop Python <3.8 support. + # Taken from `django.utils.functional.cached_property`. + class cached_property: + """ + Decorator that converts a method with a single self argument into a + property cached on the instance. + + A cached property can be made out of an existing method: + (e.g. ``url = cached_property(get_absolute_url)``). + The optional ``name`` argument is obsolete as of Python 3.6 and will be + deprecated in Django 4.0 (#30127). + """ + name = None + + @staticmethod + def func(instance): + raise TypeError( + 'Cannot use cached_property instance without calling ' + '__set_name__() on it.' + ) + + def __init__(self, func, name=None): + self.real_func = func + self.__doc__ = getattr(func, '__doc__') + + def __set_name__(self, owner, name): + if self.name is None: + self.name = name + self.func = self.real_func + elif name != self.name: + raise TypeError( + "Cannot assign the same cached_property to two different names " + "(%r and %r)." % (self.name, name) + ) + + def __get__(self, instance, cls=None): + """ + Call the function and put the return value in instance.__dict__ so that + subsequent attribute access on the instance returns the cached value + instead of calling cached_property.__get__(). + """ + if instance is None: + return self + res = instance.__dict__[self.name] = self.func(instance) + return res diff --git a/httpie/config.py b/httpie/config.py index 61f1accc1f..e2cc5e0ec3 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -5,7 +5,7 @@ from . import __version__ from .compat import is_windows -from .constants import UTF8 +from .encoding import UTF8 ENV_XDG_CONFIG_HOME = 'XDG_CONFIG_HOME' diff --git a/httpie/constants.py b/httpie/constants.py deleted file mode 100644 index 8b13f5dc4e..0000000000 --- a/httpie/constants.py +++ /dev/null @@ -1,2 +0,0 @@ -# UTF-8 encoding name -UTF8 = 'utf-8' diff --git a/httpie/context.py b/httpie/context.py index a0b87b8ede..be2e0565b2 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -11,7 +11,7 @@ from .compat import is_windows from .config import DEFAULT_CONFIG_DIR, Config, ConfigFileError -from .constants import UTF8 +from .encoding import UTF8 from .utils import repr_dict diff --git a/httpie/encoding.py b/httpie/encoding.py new file mode 100644 index 0000000000..8888743a36 --- /dev/null +++ b/httpie/encoding.py @@ -0,0 +1,50 @@ +from typing import Union + +from charset_normalizer import from_bytes +from charset_normalizer.constant import TOO_SMALL_SEQUENCE + +UTF8 = 'utf-8' + +ContentBytes = Union[bytearray, bytes] + + +def detect_encoding(content: ContentBytes) -> str: + """ + We default to UTF-8 if text too short, because the detection + can return a random encoding leading to confusing results + given the `charset_normalizer` version (< 2.0.5). + + >>> too_short = ']"foo"' + >>> detected = from_bytes(too_short.encode()).best().encoding + >>> detected + 'ascii' + >>> too_short.encode().decode(detected) + ']"foo"' + """ + encoding = UTF8 + if len(content) > TOO_SMALL_SEQUENCE: + match = from_bytes(bytes(content)).best() + if match: + encoding = match.encoding + return encoding + + +def smart_decode(content: ContentBytes, encoding: str) -> str: + """Decode `content` using the given `encoding`. + If no `encoding` is provided, the best effort is to guess it from `content`. + + Unicode errors are replaced. + + """ + if not encoding: + encoding = detect_encoding(content) + return content.decode(encoding, 'replace') + + +def smart_encode(content: str, encoding: str) -> bytes: + """Encode `content` using the given `encoding`. + + Unicode errors are replaced. + + """ + return content.encode(encoding, 'replace') diff --git a/httpie/models.py b/httpie/models.py index 21034a04d0..c554dca97b 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -1,34 +1,33 @@ -from abc import ABCMeta, abstractmethod -from typing import Iterable, Optional +from typing import Iterable from urllib.parse import urlsplit -from .constants import UTF8 -from .utils import split_cookies +from .utils import split_cookies, parse_content_type_header +from .compat import cached_property -class HTTPMessage(metaclass=ABCMeta): +class HTTPMessage: """Abstract class for HTTP messages.""" def __init__(self, orig): self._orig = orig - @abstractmethod def iter_body(self, chunk_size: int) -> Iterable[bytes]: """Return an iterator over the body.""" + raise NotImplementedError - @abstractmethod def iter_lines(self, chunk_size: int) -> Iterable[bytes]: """Return an iterator over the body yielding (`line`, `line_feed`).""" + raise NotImplementedError @property - @abstractmethod def headers(self) -> str: """Return a `str` with the message's headers.""" + raise NotImplementedError - @property - @abstractmethod - def encoding(self) -> Optional[str]: - """Return a `str` with the message's encoding, if known.""" + @cached_property + def encoding(self) -> str: + ct, params = parse_content_type_header(self.content_type) + return params.get('charset', '') @property def content_type(self) -> str: @@ -77,10 +76,6 @@ def headers(self): ) return '\r\n'.join(headers) - @property - def encoding(self): - return self._orig.encoding or UTF8 - class HTTPRequest(HTTPMessage): """A :class:`requests.models.Request` wrapper.""" @@ -114,10 +109,6 @@ def headers(self): headers = '\r\n'.join(headers).strip() return headers - @property - def encoding(self): - return UTF8 - @property def body(self): body = self._orig.body diff --git a/httpie/output/formatters/xml.py b/httpie/output/formatters/xml.py index 2909f7c0e7..3d63fbd574 100644 --- a/httpie/output/formatters/xml.py +++ b/httpie/output/formatters/xml.py @@ -1,7 +1,7 @@ import sys from typing import TYPE_CHECKING, Optional -from ...constants import UTF8 +from ...encoding import UTF8 from ...plugins import FormatterPlugin if TYPE_CHECKING: diff --git a/httpie/output/processing.py b/httpie/output/processing.py index 25d9c45ab1..ddee9ca9c3 100644 --- a/httpie/output/processing.py +++ b/httpie/output/processing.py @@ -33,7 +33,6 @@ def __init__(self, groups: List[str], env=Environment(), **kwargs): :param kwargs: additional keyword arguments for processors """ - self.options = kwargs['format_options'] available_plugins = plugin_manager.get_formatters_grouped() self.enabled_plugins = [] for group in groups: diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 1c6afaa821..24a1ba23c9 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -1,14 +1,12 @@ from abc import ABCMeta, abstractmethod from itertools import chain -from typing import Any, Callable, Dict, Iterable, Tuple, Union +from typing import Callable, Iterable, Union -from .. import codec -from ..cli.constants import EMPTY_FORMAT_OPTION -from ..context import Environment -from ..constants import UTF8 -from ..models import HTTPMessage, HTTPResponse from .processing import Conversion, Formatting -from .utils import parse_header_content_type +from ..context import Environment +from ..encoding import smart_decode, smart_encode, UTF8 +from ..models import HTTPMessage + BINARY_SUPPRESSED_NOTICE = ( b'\n' @@ -100,8 +98,16 @@ class EncodedStream(BaseStream): """ CHUNK_SIZE = 1 - def __init__(self, env=Environment(), **kwargs): + def __init__( + self, + env=Environment(), + mime_overwrite: str = None, + encoding_overwrite: str = None, + **kwargs + ): super().__init__(**kwargs) + self.mime = mime_overwrite or self.msg.content_type + self.encoding = encoding_overwrite or self.msg.encoding if env.stdout_isatty: # Use the encoding supported by the terminal. output_encoding = env.stdout_encoding @@ -115,8 +121,8 @@ def iter_body(self) -> Iterable[bytes]: for line, lf in self.msg.iter_lines(self.CHUNK_SIZE): if b'\0' in line: raise BinarySuppressedError() - line = codec.decode(line, self.msg.encoding) - yield codec.encode(line, self.output_encoding) + lf + line = smart_decode(line, self.encoding) + yield smart_encode(line, self.output_encoding) + lf class PrettyStream(EncodedStream): @@ -138,23 +144,6 @@ def __init__( super().__init__(**kwargs) self.formatting = formatting self.conversion = conversion - self.mime, mime_options = self._get_mime_and_options() - self.encoding = mime_options.get('charset') or '' - - def _get_mime_and_options(self) -> Tuple[str, Dict[str, Any]]: - # Defaults from the `Content-Type` header. - mime, options = parse_header_content_type(self.msg.content_type) - - if not isinstance(self.msg, HTTPResponse): - return mime, options - - # Override from the `--response-as` option. - forced_content_type = self.formatting.options['response']['as'] - if forced_content_type == EMPTY_FORMAT_OPTION: - return mime, options - - forced_mime, forced_options = parse_header_content_type(forced_content_type) - return (forced_mime or mime, forced_options or options) def get_headers(self) -> bytes: return self.formatting.format_headers( @@ -185,9 +174,9 @@ def process_body(self, chunk: Union[str, bytes]) -> bytes: if not isinstance(chunk, str): # Text when a converter has been used, # otherwise it will always be bytes. - chunk = codec.decode(chunk, self.encoding) + chunk = smart_decode(chunk, self.encoding) chunk = self.formatting.format_body(content=chunk, mime=self.mime) - return codec.encode(chunk, self.output_encoding) + return smart_encode(chunk, self.output_encoding) class BufferedPrettyStream(PrettyStream): diff --git a/httpie/output/utils.py b/httpie/output/utils.py index f53aab215b..875e885586 100644 --- a/httpie/output/utils.py +++ b/httpie/output/utils.py @@ -35,57 +35,3 @@ def parse_prefixed_json(data: str) -> Tuple[str, str]: data_prefix = matches[0] if matches else '' body = data[len(data_prefix):] return data_prefix, body - - -def parse_header_content_type(line): - """Parse a Content-Type like header. - Return the main Content-Type and a dictionary of options. - >>> parse_header_content_type('application/xml; charset=utf-8') - ('application/xml', {'charset': 'utf-8'}) - >>> parse_header_content_type('application/xml; charset = utf-8') - ('application/xml', {'charset': 'utf-8'}) - >>> parse_header_content_type('application/html+xml;ChArSeT="UTF-8"') - ('application/html+xml', {'charset': 'UTF-8'}) - >>> parse_header_content_type('application/xml') - ('application/xml', {}) - >>> parse_header_content_type(';charset=utf-8') - ('', {'charset': 'utf-8'}) - >>> parse_header_content_type('charset=utf-8') - ('', {'charset': 'utf-8'}) - >>> parse_header_content_type('multipart/mixed; boundary="gc0pJq0M:08jU534c0p"') - ('multipart/mixed', {'boundary': 'gc0pJq0M:08jU534c0p'}) - >>> parse_header_content_type('Message/Partial; number=3; total=3; id="oc=jpbe0M2Yt4s@foo.com"') - ('Message/Partial', {'number': '3', 'total': '3', 'id': 'oc=jpbe0M2Yt4s@foo.com'}) - """ - # Source: https://github.com/python/cpython/blob/bb3e0c2/Lib/cgi.py#L230 - - def _parseparam(s: str): - # Source: https://github.com/python/cpython/blob/bb3e0c2/Lib/cgi.py#L218 - while s[:1] == ';': - s = s[1:] - end = s.find(';') - while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2: - end = s.find(';', end + 1) - if end < 0: - end = len(s) - f = s[:end] - yield f.strip() - s = s[end:] - - # Special case: 'key=value' only (without starting with ';'). - if ';' not in line and '=' in line: - line = ';' + line - - parts = _parseparam(';' + line) - key = parts.__next__() - pdict = {} - for p in parts: - i = p.find('=') - if i >= 0: - name = p[:i].strip().lower() - value = p[i + 1:].strip() - if len(value) >= 2 and value[0] == value[-1] == '"': - value = value[1:-1] - value = value.replace('\\\\', '\\').replace('\\"', '"') - pdict[name] = value - return key, pdict diff --git a/httpie/output/writer.py b/httpie/output/writer.py index d239e50374..6f251f7cea 100644 --- a/httpie/output/writer.py +++ b/httpie/output/writer.py @@ -5,7 +5,7 @@ import requests from ..context import Environment -from ..models import HTTPRequest, HTTPResponse +from ..models import HTTPRequest, HTTPResponse, HTTPMessage from .processing import Conversion, Formatting from .streams import ( BaseStream, BufferedPrettyStream, EncodedStream, PrettyStream, RawStream, @@ -97,16 +97,17 @@ def build_output_stream_for_message( with_headers: bool, with_body: bool, ): + message_type = { + requests.PreparedRequest: HTTPRequest, + requests.Response: HTTPResponse, + }[type(requests_message)] stream_class, stream_kwargs = get_stream_type_and_kwargs( env=env, args=args, + message_type=message_type, ) - message_class = { - requests.PreparedRequest: HTTPRequest, - requests.Response: HTTPResponse, - }[type(requests_message)] yield from stream_class( - msg=message_class(requests_message), + msg=message_type(requests_message), with_headers=with_headers, with_body=with_body, **stream_kwargs, @@ -120,7 +121,8 @@ def build_output_stream_for_message( def get_stream_type_and_kwargs( env: Environment, - args: argparse.Namespace + args: argparse.Namespace, + message_type: Type[HTTPMessage], ) -> Tuple[Type['BaseStream'], dict]: """Pick the right stream type and kwargs for it based on `env` and `args`. @@ -134,23 +136,27 @@ def get_stream_type_and_kwargs( else RawStream.CHUNK_SIZE ) } - elif args.prettify: - stream_class = PrettyStream if args.stream else BufferedPrettyStream - stream_kwargs = { - 'env': env, - 'conversion': Conversion(), - 'formatting': Formatting( - env=env, - groups=args.prettify, - color_scheme=args.style, - explicit_json=args.json, - format_options=args.format_options, - ) - } else: stream_class = EncodedStream stream_kwargs = { - 'env': env + 'env': env, } + if message_type is HTTPResponse: + stream_kwargs.update({ + 'mime_overwrite': args.response_mime, + 'encoding_overwrite': args.response_charset, + }) + if args.prettify: + stream_class = PrettyStream if args.stream else BufferedPrettyStream + stream_kwargs.update({ + 'conversion': Conversion(), + 'formatting': Formatting( + env=env, + groups=args.prettify, + color_scheme=args.style, + explicit_json=args.json, + format_options=args.format_options, + ) + }) return stream_class, stream_kwargs diff --git a/httpie/utils.py b/httpie/utils.py index 4b2565e055..f40625ad94 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -189,3 +189,21 @@ def _max_age_to_expires(cookies, now): max_age = cookie.get('max-age') if max_age and max_age.isdigit(): cookie['expires'] = now + float(max_age) + + +def parse_content_type_header(header): + """Borrowed from requests.""" + tokens = header.split(';') + content_type, params = tokens[0].strip(), tokens[1:] + params_dict = {} + items_to_strip = "\"' " + for param in params: + param = param.strip() + if param: + key, value = param, True + index_of_equals = param.find("=") + if index_of_equals != -1: + key = param[:index_of_equals].strip(items_to_strip) + value = param[index_of_equals + 1:].strip(items_to_strip) + params_dict[key.lower()] = value + return content_type, params_dict diff --git a/tests/fixtures/__init__.py b/tests/fixtures/__init__.py index cf979e5f11..ade4492975 100644 --- a/tests/fixtures/__init__.py +++ b/tests/fixtures/__init__.py @@ -1,7 +1,8 @@ """Test data""" from pathlib import Path -from httpie.constants import UTF8 +from httpie.encoding import UTF8 +from httpie.output.formatters.xml import pretty_xml, parse_xml def patharg(path): @@ -35,3 +36,5 @@ def patharg(path): JSON_FILE_CONTENT = JSON_FILE_PATH.read_text(encoding=UTF8) BIN_FILE_CONTENT = BIN_FILE_PATH.read_bytes() UNICODE = FILE_CONTENT +XML_DATA_RAW = 'text' +XML_DATA_FORMATTED = pretty_xml(parse_xml(XML_DATA_RAW)) diff --git a/tests/test_auth.py b/tests/test_auth.py index e96b9f4fe5..d3581a5f8b 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -119,11 +119,11 @@ def test_ignore_netrc_with_auth_type_resulting_in_missing_auth(httpbin): @pytest.mark.parametrize( - argnames=['auth_type', 'endpoint'], - argvalues=[ + 'auth_type, endpoint', + [ ('basic', '/basic-auth/httpie/password'), ('digest', '/digest-auth/auth/httpie/password'), - ], + ] ) def test_auth_plugin_netrc_parse(auth_type, endpoint, httpbin): # Test diff --git a/tests/test_cli.py b/tests/test_cli.py index f2a7260ffa..4562deb6ca 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -51,7 +51,7 @@ def test_escape_separator(self): } 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'), diff --git a/tests/test_config.py b/tests/test_config.py index 680b16b982..be19d572e4 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -4,7 +4,7 @@ from _pytest.monkeypatch import MonkeyPatch from httpie.compat import is_windows -from httpie.constants import UTF8 +from httpie.encoding import UTF8 from httpie.config import ( Config, DEFAULT_CONFIG_DIRNAME, DEFAULT_RELATIVE_LEGACY_CONFIG_DIR, DEFAULT_RELATIVE_XDG_CONFIG_HOME, DEFAULT_WINDOWS_CONFIG_DIR, diff --git a/tests/test_encoding.py b/tests/test_encoding.py new file mode 100644 index 0000000000..e9f50dc9bb --- /dev/null +++ b/tests/test_encoding.py @@ -0,0 +1,222 @@ +""" +Various encoding handling related tests. + +""" +import pytest +import responses +from charset_normalizer.constant import TOO_SMALL_SEQUENCE + +from httpie.cli.constants import PRETTY_MAP +from httpie.encoding import UTF8 + +from .utils import http, HTTP_OK, DUMMY_URL, MockEnvironment +from .fixtures import UNICODE + + +CHARSET_TEXT_PAIRS = [ + ('big5', '卷首卷首卷首卷首卷卷首卷首卷首卷首卷首卷首卷首卷首卷首卷首卷首卷首卷首'), + ('windows-1250', 'Všichni lidé jsou si rovni. Všichni lidé jsou si rovni.'), + (UTF8, 'Všichni lidé jsou si rovni. Všichni lidé jsou si rovni.'), +] + + +def test_charset_text_pairs(): + # Verify our test data is legit. + for charset, text in CHARSET_TEXT_PAIRS: + assert len(text) > TOO_SMALL_SEQUENCE + if charset != UTF8: + with pytest.raises(UnicodeDecodeError): + assert text != text.encode(charset).decode(UTF8) + + +def test_unicode_headers(httpbin): + # httpbin doesn't interpret UFT-8 headers + r = http(httpbin.url + '/headers', f'Test:{UNICODE}') + assert HTTP_OK in r + + +def test_unicode_headers_verbose(httpbin): + # httpbin doesn't interpret UTF-8 headers + r = http('--verbose', httpbin.url + '/headers', f'Test:{UNICODE}') + assert HTTP_OK in r + assert UNICODE in r + + +def test_unicode_raw(httpbin): + r = http('--raw', f'test {UNICODE}', 'POST', httpbin.url + '/post') + assert HTTP_OK in r + assert r.json['data'] == f'test {UNICODE}' + + +def test_unicode_raw_verbose(httpbin): + r = http('--verbose', '--raw', f'test {UNICODE}', + 'POST', httpbin.url + '/post') + assert HTTP_OK in r + assert UNICODE in r + + +def test_unicode_form_item(httpbin): + r = http('--form', 'POST', httpbin.url + '/post', f'test={UNICODE}') + assert HTTP_OK in r + assert r.json['form'] == {'test': UNICODE} + + +def test_unicode_form_item_verbose(httpbin): + r = http('--verbose', '--form', + 'POST', httpbin.url + '/post', f'test={UNICODE}') + assert HTTP_OK in r + assert UNICODE in r + + +def test_unicode_json_item(httpbin): + r = http('--json', 'POST', httpbin.url + '/post', f'test={UNICODE}') + assert HTTP_OK in r + assert r.json['json'] == {'test': UNICODE} + + +def test_unicode_json_item_verbose(httpbin): + r = http('--verbose', '--json', + 'POST', httpbin.url + '/post', f'test={UNICODE}') + assert HTTP_OK in r + assert UNICODE in r + + +def test_unicode_raw_json_item(httpbin): + r = http('--json', 'POST', httpbin.url + '/post', + f'test:={{ "{UNICODE}" : [ "{UNICODE}" ] }}') + assert HTTP_OK in r + assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} + + +def test_unicode_raw_json_item_verbose(httpbin): + r = http('--json', 'POST', httpbin.url + '/post', + f'test:={{ "{UNICODE}" : [ "{UNICODE}" ] }}') + assert HTTP_OK in r + assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} + + +def test_unicode_url_query_arg_item(httpbin): + r = http(httpbin.url + '/get', f'test=={UNICODE}') + assert HTTP_OK in r + assert r.json['args'] == {'test': UNICODE}, r + + +def test_unicode_url_query_arg_item_verbose(httpbin): + r = http('--verbose', httpbin.url + '/get', f'test=={UNICODE}') + assert HTTP_OK in r + assert UNICODE in r + + +def test_unicode_url(httpbin): + r = http(f'{httpbin.url}/get?test={UNICODE}') + assert HTTP_OK in r + assert r.json['args'] == {'test': UNICODE} + + +def test_unicode_url_verbose(httpbin): + r = http('--verbose', f'{httpbin.url}/get?test={UNICODE}') + assert HTTP_OK in r + assert r.json['args'] == {'test': UNICODE} + + +def test_unicode_basic_auth(httpbin): + # it doesn't really authenticate us because httpbin + # doesn't interpret the UTF-8-encoded auth + http('--verbose', '--auth', f'test:{UNICODE}', + f'{httpbin.url}/basic-auth/test/{UNICODE}') + + +def test_unicode_digest_auth(httpbin): + # it doesn't really authenticate us because httpbin + # doesn't interpret the UTF-8-encoded auth + http('--auth-type=digest', + '--auth', f'test:{UNICODE}', + f'{httpbin.url}/digest-auth/auth/test/{UNICODE}') + + +@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@responses.activate +def test_terminal_output_response_charset_detection(text, charset): + responses.add( + method=responses.POST, + url=DUMMY_URL, + body=text.encode(charset), + content_type='text/plain', + ) + r = http('--form', 'POST', DUMMY_URL) + assert text in r + + +@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@responses.activate +def test_terminal_output_response_content_type_charset(charset, text): + responses.add( + method=responses.POST, + url=DUMMY_URL, + body=text.encode(charset), + content_type=f'text/plain; charset={charset}', + ) + r = http('--form', 'POST', DUMMY_URL) + assert text in r + + +@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('pretty', PRETTY_MAP.keys()) +@responses.activate +def test_terminal_output_response_content_type_charset_with_stream(charset, text, pretty): + responses.add( + method=responses.GET, + url=DUMMY_URL, + body=f'\n{text}'.encode(charset), + stream=True, + content_type=f'text/xml; charset={charset.upper()}', + ) + r = http('--pretty', pretty, '--stream', DUMMY_URL) + assert text in r + + +@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('pretty', PRETTY_MAP.keys()) +@responses.activate +def test_terminal_output_response_charset_override(charset, text, pretty): + responses.add( + responses.GET, + DUMMY_URL, + body=text.encode(charset), + content_type='text/plain; charset=utf-8', + ) + args = ['--pretty', pretty, DUMMY_URL] + if charset != UTF8: + # Content-Type charset wrong -> garbled text expected. + r = http(*args) + assert text not in r + r = http('--response-charset', charset, *args) + assert text in r + + +@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +def test_terminal_output_request_content_type_charset(charset, text): + r = http( + '--offline', + DUMMY_URL, + f'Content-Type: text/plain; charset={charset.upper()}', + env=MockEnvironment( + stdin=text.encode(charset), + stdin_isatty=False, + ), + ) + assert text in r + + +@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +def test_terminal_output_request_charset_detection(charset, text): + r = http( + '--offline', + DUMMY_URL, + 'Content-Type: text/plain', + env=MockEnvironment( + stdin=text.encode(charset), + stdin_isatty=False, + ), + ) + assert text in r diff --git a/tests/test_errors.py b/tests/test_errors.py index abbf7235a4..5a1a0f2476 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -41,8 +41,19 @@ def test_max_headers_no_limit(httpbin_both): assert HTTP_OK in http('--max-headers=0', httpbin_both + '/get') -def test_charset_argument_unknown_encoding(httpbin_both): - with raises(LookupError) as e: - http('--response-as', 'charset=foobar', - 'GET', httpbin_both + '/get') - assert 'unknown encoding: foobar' in str(e.value) +def test_response_charset_option_unknown_encoding(httpbin_both): + r = http( + '--response-charset=foobar', + httpbin_both + '/get', + tolerate_error_exit_status=True, + ) + assert "'foobar' is not a supported encoding" in r.stderr + + +def test_response_mime_option_invalid_mime_type(httpbin_both): + r = http( + '--response-mime=foobar', + httpbin_both + '/get', + tolerate_error_exit_status=True, + ) + assert "'foobar' doesn’t look like a mime type" in r.stderr diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 3ed1bb2c26..a6cda1c393 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -9,7 +9,7 @@ from .fixtures import FILE_CONTENT, FILE_PATH from httpie.cli.exceptions import ParseError from httpie.context import Environment -from httpie.constants import UTF8 +from httpie.encoding import UTF8 from httpie.status import ExitStatus from .utils import HTTP_OK, MockEnvironment, StdinBytesIO, http diff --git a/tests/test_json.py b/tests/test_json.py index 8d73c77965..9b0f17ce68 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -9,10 +9,28 @@ from httpie.utils import JsonDictPreservingDuplicateKeys from .fixtures import JSON_WITH_DUPE_KEYS_FILE_PATH -from .utils import MockEnvironment, http, URL_EXAMPLE - -TEST_JSON_XXSI_PREFIXES = (r")]}',\n", ")]}',", 'while(1);', 'for(;;)', ')', ']', '}') -TEST_JSON_VALUES = ({}, {'a': 0, 'b': 0}, [], ['a', 'b'], 'foo', True, False, None) # FIX: missing int & float +from .utils import MockEnvironment, http, DUMMY_URL + +TEST_JSON_XXSI_PREFIXES = [ + r")]}',\n", + ")]}',", + 'while(1);', + 'for(;;)', + ')', + ']', + '}', +] +TEST_JSON_VALUES = [ + # FIXME: missing int & float + {}, + {'a': 0, 'b': 0}, + [], + ['a', 'b'], + 'foo', + True, + False, + None, +] TEST_PREFIX_TOKEN_COLOR = '\x1b[38;5;15m' if is_windows else '\x1b[04m\x1b[91m' JSON_WITH_DUPES_RAW = '{"key": 15, "key": 15, "key": 3, "key": 7}' @@ -37,15 +55,19 @@ def test_json_formatter_with_body_preceded_by_non_json_data(data_prefix, json_data, pretty): """Test JSON bodies preceded by non-JSON data.""" body = data_prefix + json.dumps(json_data) - content_type = 'application/json' - responses.add(responses.GET, URL_EXAMPLE, body=body, - content_type=content_type) - - colored_output = pretty in ('all', 'colors') + content_type = 'application/json;charset=utf8' + responses.add( + responses.GET, + DUMMY_URL, + body=body, + content_type=content_type, + ) + + colored_output = pretty in {'all', 'colors'} env = MockEnvironment(colors=256) if colored_output else None - r = http('--pretty=' + pretty, URL_EXAMPLE, env=env) + r = http('--pretty', pretty, DUMMY_URL, env=env) - indent = None if pretty in ('none', 'colors') else 4 + indent = None if pretty in {'none', 'colors'} else 4 expected_body = data_prefix + json.dumps(json_data, indent=indent) if colored_output: fmt = ColorFormatter(env, format_options={'json': {'format': True, 'indent': 4}}) @@ -59,9 +81,13 @@ def test_json_formatter_with_body_preceded_by_non_json_data(data_prefix, json_da @responses.activate def test_duplicate_keys_support_from_response(): """JSON with duplicate keys should be handled correctly.""" - responses.add(responses.GET, URL_EXAMPLE, body=JSON_WITH_DUPES_RAW, - content_type='application/json') - args = ('--pretty', 'format', URL_EXAMPLE) + responses.add( + responses.GET, + DUMMY_URL, + body=JSON_WITH_DUPES_RAW, + content_type='application/json', + ) + args = ('--pretty', 'format', DUMMY_URL) # Check implicit --sorted if JsonDictPreservingDuplicateKeys.SUPPORTS_SORTING: @@ -75,8 +101,12 @@ def test_duplicate_keys_support_from_response(): def test_duplicate_keys_support_from_input_file(): """JSON file with duplicate keys should be handled correctly.""" - args = ('--verbose', '--offline', URL_EXAMPLE, - f'@{JSON_WITH_DUPE_KEYS_FILE_PATH}') + args = ( + '--verbose', + '--offline', + DUMMY_URL, + f'@{JSON_WITH_DUPE_KEYS_FILE_PATH}', + ) # Check implicit --sorted if JsonDictPreservingDuplicateKeys.SUPPORTS_SORTING: diff --git a/tests/test_output.py b/tests/test_output.py index dfa202285a..de0e76f618 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -9,16 +9,18 @@ import pytest import requests +import responses from httpie.cli.argtypes import ( PARSED_DEFAULT_FORMAT_OPTIONS, parse_format_options, ) from httpie.cli.definition import parser -from httpie.constants import UTF8 +from httpie.encoding import UTF8 from httpie.output.formatters.colors import get_lexer from httpie.status import ExitStatus -from .utils import COLOR, CRLF, HTTP_OK, MockEnvironment, http +from .fixtures import XML_DATA_RAW, XML_DATA_FORMATTED +from .utils import COLOR, CRLF, HTTP_OK, MockEnvironment, http, DUMMY_URL @pytest.mark.parametrize('stdout_isatty', [True, False]) @@ -168,8 +170,8 @@ def test_verbose_implies_all(self, httpbin): class TestColors: @pytest.mark.parametrize( - argnames=['mime', 'explicit_json', 'body', 'expected_lexer_name'], - argvalues=[ + 'mime, explicit_json, body, expected_lexer_name', + [ ('application/json', False, None, 'JSON'), ('application/json+foo', False, None, 'JSON'), ('application/foo+json', False, None, 'JSON'), @@ -302,8 +304,8 @@ def get_headers(sort): assert f'ZZZ: foo{CRLF}XXX: foo' in r_unsorted @pytest.mark.parametrize( - argnames=['options', 'expected_json'], - argvalues=[ + 'options, expected_json', + [ # @formatter:off ( 'json.sort_keys:true,json.indent:4', @@ -329,8 +331,8 @@ def test_json_formatting_options(self, options: str, expected_json: str): assert expected_json in r @pytest.mark.parametrize( - argnames=['defaults', 'options_string', 'expected'], - argvalues=[ + 'defaults, options_string, expected', + [ # @formatter:off ({'foo': {'bar': 1}}, 'foo.bar:2', {'foo': {'bar': 2}}), ({'foo': {'bar': True}}, 'foo.bar:false', {'foo': {'bar': False}}), @@ -343,8 +345,8 @@ def test_parse_format_options(self, defaults, options_string, expected): assert expected == actual @pytest.mark.parametrize( - argnames=['options_string', 'expected_error'], - argvalues=[ + 'options_string, expected_error', + [ ('foo:2', 'invalid option'), ('foo.baz:2', 'invalid key'), ('foo.bar:false', 'expected int got bool'), @@ -360,8 +362,8 @@ def test_parse_format_options_errors(self, options_string, expected_error): parse_format_options(s=options_string, defaults=defaults) @pytest.mark.parametrize( - argnames=['args', 'expected_format_options'], - argvalues=[ + 'args, expected_format_options', + [ ( [ '--format-options', @@ -377,9 +379,6 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 10, 'format': True }, - 'response': { - 'as': "''", - }, 'xml': { 'format': True, 'indent': 2, @@ -399,9 +398,6 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 4, 'format': True }, - 'response': { - 'as': "''", - }, 'xml': { 'format': True, 'indent': 2, @@ -423,9 +419,6 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 4, 'format': True }, - 'response': { - 'as': "''", - }, 'xml': { 'format': True, 'indent': 2, @@ -444,7 +437,6 @@ def test_parse_format_options_errors(self, options_string, expected_error): ( [ '--format-options=json.indent:2', - '--format-options=response.as:application/xml; charset=utf-8', '--format-options=xml.format:false', '--format-options=xml.indent:4', '--unsorted', @@ -459,9 +451,6 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 2, 'format': True }, - 'response': { - 'as': 'application/xml; charset=utf-8', - }, 'xml': { 'format': False, 'indent': 4, @@ -483,9 +472,6 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 2, 'format': True }, - 'response': { - 'as': "''", - }, 'xml': { 'format': True, 'indent': 2, @@ -508,9 +494,6 @@ def test_parse_format_options_errors(self, options_string, expected_error): 'indent': 2, 'format': True }, - 'response': { - 'as': "''", - }, 'xml': { 'format': True, 'indent': 2, @@ -525,3 +508,35 @@ def test_format_options_accumulation(self, args, expected_format_options): env=MockEnvironment(), ) assert parsed_args.format_options == expected_format_options + + +@responses.activate +def test_response_mime_overwrite(): + responses.add( + method=responses.GET, + url=DUMMY_URL, + body=XML_DATA_RAW, + content_type='text/plain', + ) + r = http( + '--offline', + '--raw', XML_DATA_RAW, + '--response-mime=application/xml', DUMMY_URL + ) + assert XML_DATA_RAW in r # not affecting request bodies + + r = http('--response-mime=application/xml', DUMMY_URL) + assert XML_DATA_FORMATTED in r + + +@responses.activate +def test_response_mime_overwrite_incorrect(): + responses.add( + method=responses.GET, + url=DUMMY_URL, + body=XML_DATA_RAW, + content_type='text/xml', + ) + # The provided Content-Type is simply ignored, and so no formatting is done. + r = http('--response-mime=incorrect/type', DUMMY_URL) + assert XML_DATA_RAW in r diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 3568382d74..7f6af2eaf1 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -7,7 +7,7 @@ import pytest from .fixtures import FILE_PATH_ARG, UNICODE -from httpie.constants import UTF8 +from httpie.encoding import UTF8 from httpie.plugins import AuthPlugin from httpie.plugins.builtin import HTTPBasicAuth from httpie.plugins.registry import plugin_manager @@ -239,8 +239,8 @@ def test_download_in_session(self, tmp_path, httpbin): os.chdir(cwd) @pytest.mark.parametrize( - argnames=['auth_require_param', 'auth_parse_param'], - argvalues=[ + 'auth_require_param, auth_parse_param', + [ (False, False), (False, True), (True, False) @@ -337,8 +337,8 @@ def get_auth(self, username=None, password=None): class TestExpiredCookies(CookieTestBase): @pytest.mark.parametrize( - argnames=['initial_cookie', 'expired_cookie'], - argvalues=[ + 'initial_cookie, expired_cookie', + [ ({'id': {'value': 123}}, 'id'), ({'id': {'value': 123}}, 'token') ] @@ -369,8 +369,8 @@ def test_get_expired_cookies_using_max_age(self): assert get_expired_cookies(cookies, now=None) == expected_expired @pytest.mark.parametrize( - argnames=['cookies', 'now', 'expected_expired'], - argvalues=[ + 'cookies, now, expected_expired', + [ ( 'hello=world; Path=/; Expires=Thu, 01-Jan-1970 00:00:00 GMT; HttpOnly', None, @@ -413,8 +413,8 @@ def test_get_expired_cookies_manages_multiple_cookie_headers(self, cookies, now, class TestCookieStorage(CookieTestBase): @pytest.mark.parametrize( - argnames=['new_cookies', 'new_cookies_dict', 'expected'], - argvalues=[( + 'new_cookies, new_cookies_dict, expected', + [( 'new=bar', {'new': 'bar'}, 'cookie1=foo; cookie2=foo; new=bar' @@ -457,8 +457,8 @@ def test_existing_and_new_cookies_sent_in_request(self, new_cookies, new_cookies assert 'Cookie' not in updated_session['headers'] @pytest.mark.parametrize( - argnames=['cli_cookie', 'set_cookie', 'expected'], - argvalues=[( + 'cli_cookie, set_cookie, expected', + [( '', '/cookies/set/cookie1/bar', 'bar' diff --git a/tests/test_stream.py b/tests/test_stream.py index b0b1f93e31..002b245af0 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -9,7 +9,7 @@ from httpie.plugins import ConverterPlugin from httpie.plugins.registry import plugin_manager -from .utils import StdinBytesIO, http, MockEnvironment, URL_EXAMPLE +from .utils import StdinBytesIO, http, MockEnvironment, DUMMY_URL from .fixtures import BIN_FILE_CONTENT, BIN_FILE_PATH PRETTY_OPTIONS = list(PRETTY_MAP.keys()) @@ -65,10 +65,10 @@ def test_pretty_options_with_and_without_stream_with_converter(pretty, stream): assert 'SortJSONConverterPlugin' in str(plugin_manager) body = b'\x00{"foo":42,\n"bar":"baz"}' - responses.add(responses.GET, URL_EXAMPLE, body=body, + responses.add(responses.GET, DUMMY_URL, body=body, stream=True, content_type='json/bytes') - args = ['--pretty=' + pretty, 'GET', URL_EXAMPLE] + args = ['--pretty=' + pretty, 'GET', DUMMY_URL] if stream: args.insert(0, '--stream') r = http(*args) diff --git a/tests/test_unicode.py b/tests/test_unicode.py deleted file mode 100644 index 2a12180e41..0000000000 --- a/tests/test_unicode.py +++ /dev/null @@ -1,211 +0,0 @@ -""" -Various unicode handling related tests. - -""" -import pytest -import responses - -from httpie.cli.constants import PRETTY_MAP -from httpie.constants import UTF8 - -from .utils import http, HTTP_OK, URL_EXAMPLE -from .fixtures import UNICODE - -ENCODINGS = [UTF8, 'windows-1250'] - - -def test_unicode_headers(httpbin): - # httpbin doesn't interpret UFT-8 headers - r = http(httpbin.url + '/headers', f'Test:{UNICODE}') - assert HTTP_OK in r - - -def test_unicode_headers_verbose(httpbin): - # httpbin doesn't interpret UTF-8 headers - r = http('--verbose', httpbin.url + '/headers', f'Test:{UNICODE}') - assert HTTP_OK in r - assert UNICODE in r - - -def test_unicode_raw(httpbin): - r = http('--raw', f'test {UNICODE}', 'POST', httpbin.url + '/post') - assert HTTP_OK in r - assert r.json['data'] == f'test {UNICODE}' - - -def test_unicode_raw_verbose(httpbin): - r = http('--verbose', '--raw', f'test {UNICODE}', - 'POST', httpbin.url + '/post') - assert HTTP_OK in r - assert UNICODE in r - - -def test_unicode_form_item(httpbin): - r = http('--form', 'POST', httpbin.url + '/post', f'test={UNICODE}') - assert HTTP_OK in r - assert r.json['form'] == {'test': UNICODE} - - -def test_unicode_form_item_verbose(httpbin): - r = http('--verbose', '--form', - 'POST', httpbin.url + '/post', f'test={UNICODE}') - assert HTTP_OK in r - assert UNICODE in r - - -def test_unicode_json_item(httpbin): - r = http('--json', 'POST', httpbin.url + '/post', f'test={UNICODE}') - assert HTTP_OK in r - assert r.json['json'] == {'test': UNICODE} - - -def test_unicode_json_item_verbose(httpbin): - r = http('--verbose', '--json', - 'POST', httpbin.url + '/post', f'test={UNICODE}') - assert HTTP_OK in r - assert UNICODE in r - - -def test_unicode_raw_json_item(httpbin): - r = http('--json', 'POST', httpbin.url + '/post', - f'test:={{ "{UNICODE}" : [ "{UNICODE}" ] }}') - assert HTTP_OK in r - assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} - - -def test_unicode_raw_json_item_verbose(httpbin): - r = http('--json', 'POST', httpbin.url + '/post', - f'test:={{ "{UNICODE}" : [ "{UNICODE}" ] }}') - assert HTTP_OK in r - assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} - - -def test_unicode_url_query_arg_item(httpbin): - r = http(httpbin.url + '/get', f'test=={UNICODE}') - assert HTTP_OK in r - assert r.json['args'] == {'test': UNICODE}, r - - -def test_unicode_url_query_arg_item_verbose(httpbin): - r = http('--verbose', httpbin.url + '/get', f'test=={UNICODE}') - assert HTTP_OK in r - assert UNICODE in r - - -def test_unicode_url(httpbin): - r = http(f'{httpbin.url}/get?test={UNICODE}') - assert HTTP_OK in r - assert r.json['args'] == {'test': UNICODE} - - -def test_unicode_url_verbose(httpbin): - r = http('--verbose', f'{httpbin.url}/get?test={UNICODE}') - assert HTTP_OK in r - assert r.json['args'] == {'test': UNICODE} - - -def test_unicode_basic_auth(httpbin): - # it doesn't really authenticate us because httpbin - # doesn't interpret the UTF-8-encoded auth - http('--verbose', '--auth', f'test:{UNICODE}', - f'{httpbin.url}/basic-auth/test/{UNICODE}') - - -def test_unicode_digest_auth(httpbin): - # it doesn't really authenticate us because httpbin - # doesn't interpret the UTF-8-encoded auth - http('--auth-type=digest', - '--auth', f'test:{UNICODE}', - f'{httpbin.url}/digest-auth/auth/test/{UNICODE}') - - -@pytest.mark.parametrize('encoding', ENCODINGS) -@responses.activate -def test_GET_encoding_detection_from_content_type_header(encoding): - responses.add(responses.GET, - URL_EXAMPLE, - body='\nFinanciën'.encode(encoding), - content_type=f'text/xml; charset={encoding.upper()}') - r = http('GET', URL_EXAMPLE) - assert 'Financiën' in r - - -@pytest.mark.parametrize('encoding', ENCODINGS) -@responses.activate -def test_GET_encoding_detection_from_content(encoding): - body = f'\nFinanciën' - responses.add(responses.GET, - URL_EXAMPLE, - body=body.encode(encoding), - content_type='text/xml') - r = http('GET', URL_EXAMPLE) - assert 'Financiën' in r - - -@responses.activate -def test_GET_encoding_provided_by_format_options(): - responses.add(responses.GET, - URL_EXAMPLE, - body='▒▒▒'.encode('johab'), - content_type='text/plain') - r = http('--format-options', 'response.as:text/plain; charset=johab', - 'GET', URL_EXAMPLE) - assert '▒▒▒' in r - - -@responses.activate -def test_GET_encoding_provided_by_shortcut_option(): - responses.add(responses.GET, - URL_EXAMPLE, - body='▒▒▒'.encode('johab'), - content_type='text/plain') - r = http('--response-as', 'text/plain; charset=johab', - 'GET', URL_EXAMPLE) - assert '▒▒▒' in r - - -@pytest.mark.parametrize('encoding', ENCODINGS) -@responses.activate -def test_GET_encoding_provided_by_empty_shortcut_option_should_use_content_detection(encoding): - body = f'\nFinanciën' - responses.add(responses.GET, - URL_EXAMPLE, - body=body.encode(encoding), - content_type='text/xml') - r = http('--response-as', '', 'GET', URL_EXAMPLE) - assert 'Financiën' in r - - -@pytest.mark.parametrize('encoding', ENCODINGS) -@responses.activate -def test_POST_encoding_detection_from_content_type_header(encoding): - responses.add(responses.POST, - URL_EXAMPLE, - body='Všichni lidé jsou si rovni.'.encode(encoding), - content_type=f'text/plain; charset={encoding.upper()}') - r = http('--form', 'POST', URL_EXAMPLE) - assert 'Všichni lidé jsou si rovni.' in r - - -@pytest.mark.parametrize('encoding', ENCODINGS) -@responses.activate -def test_POST_encoding_detection_from_content(encoding): - responses.add(responses.POST, - URL_EXAMPLE, - body='Všichni lidé jsou si rovni.'.encode(encoding), - content_type='text/plain') - r = http('--form', 'POST', URL_EXAMPLE) - assert 'Všichni lidé jsou si rovni.' in r - - -@pytest.mark.parametrize('encoding', ENCODINGS) -@pytest.mark.parametrize('pretty', PRETTY_MAP.keys()) -@responses.activate -def test_stream_encoding_detection_from_content_type_header(encoding, pretty): - responses.add(responses.GET, - URL_EXAMPLE, - body='\nFinanciën'.encode(encoding), - stream=True, - content_type=f'text/xml; charset={encoding.upper()}') - r = http('--pretty=' + pretty, '--stream', 'GET', URL_EXAMPLE) - assert 'Financiën' in r diff --git a/tests/test_xml.py b/tests/test_xml.py index 43a6d8fb76..a427b266e5 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -3,14 +3,11 @@ import pytest import responses -from httpie.constants import UTF8 +from httpie.encoding import UTF8 from httpie.output.formatters.xml import parse_xml, pretty_xml -from .fixtures import XML_FILES_PATH, XML_FILES_VALID, XML_FILES_INVALID -from .utils import http, URL_EXAMPLE - -XML_DATA_RAW = 'text' -XML_DATA_FORMATTED = pretty_xml(parse_xml(XML_DATA_RAW)) +from .fixtures import XML_FILES_PATH, XML_FILES_VALID, XML_FILES_INVALID, XML_DATA_RAW, XML_DATA_FORMATTED +from .utils import http, DUMMY_URL @pytest.mark.parametrize( @@ -23,10 +20,14 @@ ) @responses.activate def test_xml_format_options(options, expected_xml): - responses.add(responses.GET, URL_EXAMPLE, body=XML_DATA_RAW, - content_type='application/xml') + responses.add( + responses.GET, + DUMMY_URL, + body=XML_DATA_RAW, + content_type='application/xml', + ) - r = http('--format-options', options, URL_EXAMPLE) + r = http('--format-options', options, DUMMY_URL) assert expected_xml in r @@ -42,10 +43,14 @@ def test_valid_xml(file): xml_data = file.read_text(encoding=UTF8) expected_xml_file = file.with_name(file.name.replace('_raw', '_formatted')) expected_xml_output = expected_xml_file.read_text(encoding=UTF8) - responses.add(responses.GET, URL_EXAMPLE, body=xml_data, - content_type='application/xml') + responses.add( + responses.GET, + DUMMY_URL, + body=xml_data, + content_type='application/xml', + ) - r = http(URL_EXAMPLE) + r = http(DUMMY_URL) assert expected_xml_output in r @@ -64,10 +69,14 @@ def test_xml_xhtml(): ) expected_xml_file = file.with_name(expected_file_name) expected_xml_output = expected_xml_file.read_text(encoding=UTF8) - responses.add(responses.GET, URL_EXAMPLE, body=xml_data, - content_type='application/xhtml+xml') + responses.add( + responses.GET, + DUMMY_URL, + body=xml_data, + content_type='application/xhtml+xml', + ) - r = http(URL_EXAMPLE) + r = http(DUMMY_URL) assert expected_xml_output in r @@ -78,61 +87,13 @@ def test_invalid_xml(file): and none should make HTTPie to crash. """ xml_data = file.read_text(encoding=UTF8) - responses.add(responses.GET, URL_EXAMPLE, body=xml_data, - content_type='application/xml') + responses.add( + responses.GET, + DUMMY_URL, + body=xml_data, + content_type='application/xml', + ) - # No formatting done, data is simply printed as-is - r = http(URL_EXAMPLE) + # No formatting done, data is simply printed as-is. + r = http(DUMMY_URL) assert xml_data in r - - -@responses.activate -def test_content_type_from_format_options_argument(): - """Test XML response with a incorrect Content-Type header. - Using the --format-options to force the good one. - """ - responses.add(responses.GET, URL_EXAMPLE, body=XML_DATA_RAW, - content_type='plain/text') - args = ('--format-options', 'response.as:application/xml', - URL_EXAMPLE) - - # Ensure the option is taken into account only for responses. - # Request - r = http('--offline', '--raw', XML_DATA_RAW, *args) - assert XML_DATA_RAW in r - - # Response - r = http(*args) - assert XML_DATA_FORMATTED in r - - -@responses.activate -def test_content_type_from_shortcut_argument(): - """Test XML response with a incorrect Content-Type header. - Using the --format-options shortcut to force the good one. - """ - responses.add(responses.GET, URL_EXAMPLE, body=XML_DATA_RAW, - content_type='text/plain') - args = ('--response-as', 'application/xml', URL_EXAMPLE) - - # Ensure the option is taken into account only for responses. - # Request - r = http('--offline', '--raw', XML_DATA_RAW, *args) - assert XML_DATA_RAW in r - - # Response - r = http(*args) - assert XML_DATA_FORMATTED in r - - -@responses.activate -def test_content_type_from_incomplete_format_options_argument(): - """Test XML response with a incorrect Content-Type header. - Using the --format-options to use a partial Content-Type without mime type. - """ - responses.add(responses.GET, URL_EXAMPLE, body=XML_DATA_RAW, - content_type='text/plain') - - # The provided Content-Type is simply ignored, and so no formatting is done. - r = http('--response-as', 'charset=utf-8', URL_EXAMPLE) - assert XML_DATA_RAW in r diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index 193d2e2fbb..0877b9cad7 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -33,7 +33,7 @@ '\x1b[39m\x1b[38;5;245m \x1b[39m\x1b[38;5;136mOK' ) -URL_EXAMPLE = 'http://example.org' # Note: URL never fetched +DUMMY_URL = 'http://this-should.never-resolve' # Note: URL never fetched def mk_config_dir() -> Path: From 80e83f04632e31f269bf65b59c9f3f39a0cd9591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 6 Oct 2021 17:29:03 +0200 Subject: [PATCH 0851/1182] Ignore more venv folders and VS Code folder --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index b52aa4763c..83aed325d2 100644 --- a/.gitignore +++ b/.gitignore @@ -118,6 +118,7 @@ celerybeat.pid .venv env/ venv/ +venv*/ ENV/ env.bak/ venv.bak/ @@ -144,3 +145,6 @@ dmypy.json /httpie.spec /httpie-*.rpm /httpie-*.tar.gz + +# VS Code +.vscode/ From f954c9e2b74f9c7b985c80268f88a6d5bcbbc110 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 6 Oct 2021 17:35:07 +0200 Subject: [PATCH 0852/1182] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e0f5ef063..7f4dd7546f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.6.0.dev0](https://github.com/httpie/httpie/compare/2.5.0...master) (unreleased) - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) -- Added `--response-encoding` to allow overriding the response encoding for terminal display purposes. ([#1168](https://github.com/httpie/httpie/issues/1168)) +- Added `--response-charset` to allow overriding the response encoding for terminal display purposes. ([#1168](https://github.com/httpie/httpie/issues/1168)) - Added `--response-mime` to allow overriding the response mime type for coloring and formatting for the terminal. ([#1168](https://github.com/httpie/httpie/issues/1168)) - Improved handling of responses with incorrect `Content-Type`. ([#1110](https://github.com/httpie/httpie/issues/1110), [#1168](https://github.com/httpie/httpie/issues/1168)) - Installed plugins are now listed in `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165)) From e1627803fe88b3815c69438b2da89879fc004ee1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 6 Oct 2021 19:24:10 +0200 Subject: [PATCH 0853/1182] Add more types and docs for plugins API --- httpie/plugins/base.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index 5b1b4d8a09..1250d74405 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -1,5 +1,7 @@ -class BasePlugin: +from typing import Tuple, Union + +class BasePlugin: # The name of the plugin, eg. "My auth". name = None @@ -53,7 +55,7 @@ class AuthPlugin(BasePlugin): # then this is `None`. raw_auth = None - def get_auth(self, username=None, password=None): + def get_auth(self, username: str = None, password: str = None): """ If `auth_parse` is set to `True`, then `username` and `password` contain the parsed credentials. @@ -101,14 +103,19 @@ class ConverterPlugin(BasePlugin): """ - def __init__(self, mime): + def __init__(self, mime: str): self.mime = mime - def convert(self, content_bytes): + def convert(self, content_bytes: bytes) -> Tuple[str, Union[str, bytes]]: + """ + Convert content as needed and return a tuple containing the new Content-Type and content, e.g.: + ('application/json', '{}') + + """ raise NotImplementedError @classmethod - def supports(cls, mime): + def supports(cls, mime: str) -> bool: raise NotImplementedError From 7e0bed4e54c6c13f4ef8e0c8317163f0b124787a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 6 Oct 2021 19:28:21 +0200 Subject: [PATCH 0854/1182] Add more types and docs for plugins API II. --- httpie/plugins/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index 1250d74405..408566df9e 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -106,9 +106,9 @@ class ConverterPlugin(BasePlugin): def __init__(self, mime: str): self.mime = mime - def convert(self, content_bytes: bytes) -> Tuple[str, Union[str, bytes]]: + def convert(self, body: bytes) -> Tuple[str, str]: """ - Convert content as needed and return a tuple containing the new Content-Type and content, e.g.: + Convert content bytes to a string and return a tuple containing the new Content-Type and content, e.g.: ('application/json', '{}') """ From ef4fa20ceb0044aa7820bd9d3f222fefc9d8fca2 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 6 Oct 2021 19:31:43 +0200 Subject: [PATCH 0855/1182] Tweak --- httpie/plugins/base.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index 408566df9e..f446346cd2 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -95,7 +95,7 @@ def get_adapter(self): class ConverterPlugin(BasePlugin): """ - Possibly converts response data for prettified terminal display. + Possibly converts binary response data for prettified terminal display. See httpie-msgpack for an example converter plugin: @@ -108,7 +108,9 @@ def __init__(self, mime: str): def convert(self, body: bytes) -> Tuple[str, str]: """ - Convert content bytes to a string and return a tuple containing the new Content-Type and content, e.g.: + Convert a binary body to a textual representation for the terminal + and return a tuple containing the new Content-Type and content, e.g.: + ('application/json', '{}') """ From 9dda23a32215ce233f9a5384030ddc7eb9e231b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 7 Oct 2021 13:53:11 +0200 Subject: [PATCH 0856/1182] Add Chocolatey packaging information (#1172) * Add Chocolatey packaging information * Fix working directory * Fix Python dependency * Update icon URL * Fix local installation * Simplify links * Remove the workflow, it adds no real value and th etime to fix is is not worth --- .gitignore | 3 ++ docs/packaging/README.md | 30 ++++++------ docs/packaging/windows-chocolatey/README.md | 29 ++++++++++- .../windows-chocolatey/httpie.nuspec | 49 +++++++++++++++++++ .../tools/chocolateyinstall.ps1 | 6 +++ .../tools/chocolateyuninstall.ps1 | 2 + snapcraft.yaml | 2 +- 7 files changed, 103 insertions(+), 18 deletions(-) create mode 100644 docs/packaging/windows-chocolatey/httpie.nuspec create mode 100644 docs/packaging/windows-chocolatey/tools/chocolateyinstall.ps1 create mode 100644 docs/packaging/windows-chocolatey/tools/chocolateyuninstall.ps1 diff --git a/.gitignore b/.gitignore index 83aed325d2..4f4d94543e 100644 --- a/.gitignore +++ b/.gitignore @@ -148,3 +148,6 @@ dmypy.json # VS Code .vscode/ + +# Windows Chocolatey +*.nupkg diff --git a/docs/packaging/README.md b/docs/packaging/README.md index 0f329368c9..5cc107459e 100644 --- a/docs/packaging/README.md +++ b/docs/packaging/README.md @@ -30,20 +30,20 @@ That is done quite easily by manually triggering the [release workflow](https:// Find out how we do release new versions for each and every supported OS in the following table. A more complete state of deployment can be found on [repology](https://repology.org/project/httpie/versions), including unofficial packages. -| OS | Maintainer | -| ------------------------------------------------------------------: | -------------- | -| [Alpine](linux-alpine/README.md) | **HTTPie** | -| [Arch Linux, and derived](linux-arch/README.md) | trusted person | -| :construction: [AOSC OS](linux-aosc/README.md) | **HTTPie** | -| [CentOS, RHEL, and derived](linux-centos/README.md) | trusted person | -| [Debian, Ubuntu, and derived](linux-debian/README.md) | trusted person | -| [Fedora](linux-fedora/README.md) | trusted person | -| [Gentoo](linux-gentoo/README.md) | **HTTPie** | -| :construction: [Homebrew, Linuxbrew](brew/README.md) | **HTTPie** | -| :construction: [MacPorts](mac-ports/README.md) | **HTTPie** | -| [Snapcraft](snapcraft/README.md) | **HTTPie** | -| [Spack](spack/README.md) | **HTTPie** | -| [Void Linux](linux-void/README.md) | **HTTPie** | -| :construction: [Windows — Chocolatey](windows-chocolatey/README.md) | **HTTPie** | +| OS | Maintainer | +| -------------------------------------------: | -------------- | +| [Alpine](linux-alpine/) | **HTTPie** | +| [Arch Linux, and derived](linux-arch/) | trusted person | +| :construction: [AOSC OS](linux-aosc/) | **HTTPie** | +| [CentOS, RHEL, and derived](linux-centos/) | trusted person | +| [Debian, Ubuntu, and derived](linux-debian/) | trusted person | +| [Fedora](linux-fedora/) | trusted person | +| [Gentoo](linux-gentoo/) | **HTTPie** | +| :construction: [Homebrew, Linuxbrew](brew/) | **HTTPie** | +| :construction: [MacPorts](mac-ports/) | **HTTPie** | +| [Snapcraft](snapcraft/) | **HTTPie** | +| [Spack](spack/) | **HTTPie** | +| [Void Linux](linux-void/) | **HTTPie** | +| [Windows — Chocolatey](windows-chocolatey/) | **HTTPie** | :new: You do not find your system or you would like to see HTTPie supported on another OS? Then [let us know](https://github.com/httpie/httpie/issues/). diff --git a/docs/packaging/windows-chocolatey/README.md b/docs/packaging/windows-chocolatey/README.md index 1102834191..ff18b536c3 100644 --- a/docs/packaging/windows-chocolatey/README.md +++ b/docs/packaging/windows-chocolatey/README.md @@ -13,8 +13,33 @@ We will discuss setting up the environment, installing development tools, instal ## Overall process -:construction: Work in progress. +After having successfully [built and tested](#hacking) the package, push it: + +```bash +# Replace 2.5.0 with the correct version +choco push httpie.2.5.0.nupkg -s https://push.chocolatey.org/ +``` ## Hacking -:construction: Work in progress. +```bash +# Clone +git clone --depth=1 https://github.com/httpie/httpie.git +cd httpie/docs/packaging/windows-chocolatey + +# Build +choco pack + +# Check metadata +choco info httpie -s . + +# Install +choco install httpie -y -dv -s "'.;https://community.chocolatey.org/api/v2/'" + +# Test +http --version +https --version + +# Remove +choco uninstall -y httpie +``` diff --git a/docs/packaging/windows-chocolatey/httpie.nuspec b/docs/packaging/windows-chocolatey/httpie.nuspec new file mode 100644 index 0000000000..c630276508 --- /dev/null +++ b/docs/packaging/windows-chocolatey/httpie.nuspec @@ -0,0 +1,49 @@ + + + + httpie + 2.5.0 + +HTTPie *aitch-tee-tee-pie* is a user-friendly command-line HTTP client for the API era. +It comes with JSON support, syntax highlighting, persistent sessions, wget-like downloads, plugins, and more. + +The project's goal is to make CLI interaction with web services as human-friendly as possible. HTTPie is designed for testing, debugging, and generally interacting with APIs and HTTP servers. +The `http` and `https` commands allow for creating and sending arbitrary HTTP requests. They use simple and natural syntax and provide formatted and colorized output. + +Main features: + +- Built-in JSON support +- Colorized and formatted terminal output +- Sensible defaults for the API era +- Persistent sessions +- Forms and file uploads +- HTTPS, proxies, and authentication support +- Support for arbitrary request data and headers +- Wget-like downloads +- Extensions API +- Expressive and intuitive syntax +- Linux, macOS, Windows, and FreeBSD support +- All that and more in 2 simple commands: `http` + `https` + + HTTPie + HTTPie + Tiger-222 + 2012-2021 Jakub Roztocil + https://raw.githubusercontent.com/httpie/httpie/master/LICENSE + https://pie-assets.s3.eu-central-1.amazonaws.com/LogoIcons/GB.png + false + See the [changelog](https://github.com/httpie/httpie/blob/2.5.0/CHANGELOG.md). + httpie http https rest api client curl python ssl cli foss oss url + https://httpie.io + https://github.com/httpie/httpie + https://github.com/httpie/httpie + https://httpie.io/docs + https://github.com/httpie/httpie/issues + + + + + + + + diff --git a/docs/packaging/windows-chocolatey/tools/chocolateyinstall.ps1 b/docs/packaging/windows-chocolatey/tools/chocolateyinstall.ps1 new file mode 100644 index 0000000000..36f3b195c5 --- /dev/null +++ b/docs/packaging/windows-chocolatey/tools/chocolateyinstall.ps1 @@ -0,0 +1,6 @@ +$ErrorActionPreference = 'Stop'; +$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" +$nuspecPath = "$(Join-Path (Split-Path -parent $toolsDir) ($env:ChocolateyPackageName + ".nuspec"))" +[XML]$nuspec = Get-Content $nuspecPath +$pipVersion = $nuspec.package.metadata.version +py -m pip install "$($env:ChocolateyPackageName)==$($pipVersion)" --disable-pip-version-check diff --git a/docs/packaging/windows-chocolatey/tools/chocolateyuninstall.ps1 b/docs/packaging/windows-chocolatey/tools/chocolateyuninstall.ps1 new file mode 100644 index 0000000000..59c660b513 --- /dev/null +++ b/docs/packaging/windows-chocolatey/tools/chocolateyuninstall.ps1 @@ -0,0 +1,2 @@ +$ErrorActionPreference = 'Stop'; +py -m pip uninstall -y $env:ChocolateyPackageName --disable-pip-version-check diff --git a/snapcraft.yaml b/snapcraft.yaml index ef72a810c8..0b9b07d85a 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -25,7 +25,7 @@ description: | - Wget-like downloads - Extensions API - Expressive and intuitive syntax - - Linux, macOS, and Windows support + - Linux, macOS, Windows, and FreeBSD support - All that & more in 2 simple commands: http + https Links From bd227c03645d5486f22bdc531da06d84fdd6d0c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 7 Oct 2021 13:57:46 +0200 Subject: [PATCH 0857/1182] Specify the API key to submit Chocolatey packages --- docs/packaging/windows-chocolatey/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/packaging/windows-chocolatey/README.md b/docs/packaging/windows-chocolatey/README.md index ff18b536c3..588fd7e7d7 100644 --- a/docs/packaging/windows-chocolatey/README.md +++ b/docs/packaging/windows-chocolatey/README.md @@ -17,7 +17,7 @@ After having successfully [built and tested](#hacking) the package, push it: ```bash # Replace 2.5.0 with the correct version -choco push httpie.2.5.0.nupkg -s https://push.chocolatey.org/ +choco push httpie.2.5.0.nupkg -s https://push.chocolatey.org/ --api-key=API_KEY ``` ## Hacking From 1e094d0a794b4f40f2fc4f35e2d2edf1cefbdcb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 7 Oct 2021 14:06:06 +0200 Subject: [PATCH 0858/1182] Fix Snapcraft and Spack anchors --- docs/packaging/snapcraft/README.md | 2 +- docs/packaging/spack/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/packaging/snapcraft/README.md b/docs/packaging/snapcraft/README.md index 3a1f71d817..b22a00ef80 100644 --- a/docs/packaging/snapcraft/README.md +++ b/docs/packaging/snapcraft/README.md @@ -3,7 +3,7 @@ Welcome to the documentation about **packaging HTTPie for Snapcraft**. - If you do not know HTTPie, have a look [here](https://httpie.io/cli). -- If you are looking for HTTPie installation or upgrade instructions on Snapcraft, then you can find them on [that page](https://httpie.io/docs#snap-linux) ([that one](https://httpie.io/docs#snap-mac) for macOS). +- If you are looking for HTTPie installation or upgrade instructions on Snapcraft, then you can find them on [that page](https://httpie.io/docs#snapcraft-linux) ([that one](https://httpie.io/docs#snapcraft-macos) for macOS). - If you are looking for technical information about the HTTPie packaging on Snapcraft, then you are in a good place. ## About diff --git a/docs/packaging/spack/README.md b/docs/packaging/spack/README.md index 50bb0bda83..dc20604a8a 100644 --- a/docs/packaging/spack/README.md +++ b/docs/packaging/spack/README.md @@ -3,7 +3,7 @@ Welcome to the documentation about **packaging HTTPie for Spack**. - If you do not know HTTPie, have a look [here](https://httpie.io/cli). -- If you are looking for HTTPie installation or upgrade instructions on Spack, then you can find them on [that page](https://httpie.io/docs#spack-linux) ([that one](https://httpie.io/docs#spack-mac) for macOS). +- If you are looking for HTTPie installation or upgrade instructions on Spack, then you can find them on [that page](https://httpie.io/docs#spack-linux) ([that one](https://httpie.io/docs#spack-macos) for macOS). - If you are looking for technical information about the HTTPie packaging on Spack, then you are in a good place. ## About From 17f74f10f36822a821a43d81344e2214c0371c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 7 Oct 2021 14:34:33 +0200 Subject: [PATCH 0859/1182] Add summary to Chocolatey metadata It is strongly recommended to add a summary. It will be effective for the next release though. --- docs/packaging/windows-chocolatey/httpie.nuspec | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/packaging/windows-chocolatey/httpie.nuspec b/docs/packaging/windows-chocolatey/httpie.nuspec index c630276508..39e4810d76 100644 --- a/docs/packaging/windows-chocolatey/httpie.nuspec +++ b/docs/packaging/windows-chocolatey/httpie.nuspec @@ -3,6 +3,7 @@ httpie 2.5.0 + Modern, user-friendly command-line HTTP client for the API era. HTTPie *aitch-tee-tee-pie* is a user-friendly command-line HTTP client for the API era. It comes with JSON support, syntax highlighting, persistent sessions, wget-like downloads, plugins, and more. From 3869c3ce992413aa2e3478e9506f47bd8674b5a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 7 Oct 2021 14:41:03 +0200 Subject: [PATCH 0860/1182] Remove unused import --- httpie/plugins/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index f446346cd2..f933342e51 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -1,4 +1,4 @@ -from typing import Tuple, Union +from typing import Tuple class BasePlugin: From 476eb4f0d91b53fbe2fae394f13083e9f4813531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 7 Oct 2021 16:15:52 +0200 Subject: [PATCH 0861/1182] Use HTTPie repository everywhere --- docs/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 388b98e227..38761344e7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1928,8 +1928,8 @@ All changes are recorded in the [change log](#change-log). HTTPie has the following community channels: -- [GitHub Issues](https://github.com/jkbr/httpie/issues) for bug reports and feature requests -- [Discord server](https://httpie.io/chat) to ask questions, discuss features, and for general API development discussion +- [GitHub Issues](https://github.com/httpie/httpie/issues) for bug reports and feature requests +- [Discord server](https://httpie.io/discord) to ask questions, discuss features, and for general API development discussion - [StackOverflow](https://stackoverflow.com) to ask questions (make sure to use the [httpie](https://stackoverflow.com/questions/tagged/httpie) tag) - Twitter; where you can tweet directly to (and follow!) [@httpie](https://twitter.com/httpie) @@ -1955,7 +1955,7 @@ Helpers to convert from other client tools: #### Alternatives -- [httpcat](https://github.com/jakubroztocil/httpcat) — a lower-level sister utility of HTTPie for constructing raw HTTP requests on the command line +- [httpcat](https://github.com/httpie/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 From 555afef486b02beb09cbd5c267dd716c1ae7b8d1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 7 Oct 2021 16:21:36 +0200 Subject: [PATCH 0862/1182] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 64ae4e0089..9b8d0b58eb 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ $ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/com ## Community & support - Visit the [HTTPie website](https://httpie.io) for full documentation and useful links. -- Join our [Discord server](https://httpie.io/chat) is to ask questions, discuss features, and for general API chat. +- Join our [Discord server](https://httpie.io/discord) is to ask questions, discuss features, and for general API chat. - Tweet at [@httpie](https://twitter.com/httpie) on Twitter. - Use [StackOverflow](https://stackoverflow.com/questions/tagged/httpie) to ask questions and include a `httpie` tag. - Create [GitHub Issues](https://github.com/httpie/httpie/issues) for bug reports and feature requests. From 50f57f8c82bb80b9f9dab56f503165536ecceebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 7 Oct 2021 17:37:06 +0200 Subject: [PATCH 0863/1182] Add help output for --chunked (#1174) --- httpie/cli/definition.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index ff3b31b06d..f6a8c0e63f 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -711,9 +711,11 @@ def __iter__(self): '--chunked', default=False, action='store_true', - help=""" + help=''' + Enable streaming via chunked transfer encoding. + The Transfer-Encoding header is set to chunked. - """ + ''' ) ####################################################################### From 1b7f74c2b2f2a0ba75f5e48cf3240eb1f053b2ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Fri, 8 Oct 2021 11:24:24 +0200 Subject: [PATCH 0864/1182] Add a workflow to control Snap publications (#1176) --- .github/workflows/release-snap.yml | 22 ++++++++++++++++++++++ .github/workflows/release.yml | 2 ++ 2 files changed, 24 insertions(+) create mode 100644 .github/workflows/release-snap.yml diff --git a/.github/workflows/release-snap.yml b/.github/workflows/release-snap.yml new file mode 100644 index 0000000000..9c6b009452 --- /dev/null +++ b/.github/workflows/release-snap.yml @@ -0,0 +1,22 @@ +on: + workflow_dispatch: + inputs: + branch: + description: "The branch, tag or SHA to release from" + required: true + default: "master" + +jobs: + snap: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.branch }} + - uses: snapcore/action-build@v1 + id: build + - uses: snapcore/action-publish@v1 + with: + store_login: ${{ secrets.SNAP_STORE_LOGIN }} + snap: ${{ steps.build.outputs.snap }} + release: edge diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 674bf04b02..9e1c1f53ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,6 +17,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.branch }} - uses: actions/setup-python@v2 with: python-version: 3.9 From 6befaf9067c5286d302ecd3b8e76053ae81a441a Mon Sep 17 00:00:00 2001 From: dkreeft <37153972+dkreeft@users.noreply.github.com> Date: Fri, 8 Oct 2021 14:18:11 +0200 Subject: [PATCH 0865/1182] Added the ability to silence warnings via double `-q` or `--quiet` (#1175) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * change behavior of '--quiet' to silence errors and warnings when passed twice together with '--check-status' * Apply suggestions from code review Co-authored-by: Jakub Roztocil * remove header, trailing comma, rename constant and variable * fix flags for tests * [skip ci] Update ticket number Co-authored-by: Dave Co-authored-by: Jakub Roztocil Co-authored-by: Mickaël Schoentgen --- CHANGELOG.md | 1 + docs/README.md | 7 +++++++ httpie/cli/definition.py | 8 +++++--- httpie/core.py | 2 +- tests/test_output.py | 41 +++++++++++++++++++++++++++++----------- 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f4dd7546f..d926e0b1bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.6.0.dev0](https://github.com/httpie/httpie/compare/2.5.0...master) (unreleased) +- Added the ability to silence warnings through using `-q` or `--quiet` twice (e.g. `-qq`) ([#1175](https://github.com/httpie/httpie/issues/1175)) - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) - Added `--response-charset` to allow overriding the response encoding for terminal display purposes. ([#1168](https://github.com/httpie/httpie/issues/1168)) - Added `--response-mime` to allow overriding the response mime type for coloring and formatting for the terminal. ([#1168](https://github.com/httpie/httpie/issues/1168)) diff --git a/docs/README.md b/docs/README.md index 38761344e7..e25ad930a2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1247,6 +1247,13 @@ This doesn’t affect output to a file via `--output` or `--download`. $ http --quiet pie.dev/post enjoy='the silence' ``` +If you’d like to silence warnings as well, use `-q` or `--quiet` twice: + +```bash +# There will be no output, even in case of an unexpected response status code: +$ http -qq --check-status pie.dev/post enjoy='the silence without warnings' +``` + ### Viewing intermediary requests/responses To see all the HTTP communication, i.e. the final request/response as well as any possible intermediary requests/responses, use the `--all` option. diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index f6a8c0e63f..6ebb50c50e 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -497,12 +497,14 @@ output_options.add_argument( '--quiet', '-q', - action='store_true', - default=False, + action='count', + default=0, help=''' - Do not print to stdout or stderr. + Do not print to stdout or stderr, except for errors and warnings when provided once. + Provide twice to suppress warnings as well. stdout is still redirected if --output is specified. Flag doesn't affect behaviour of download beyond not printing to terminal. + ''' ) diff --git a/httpie/core.py b/httpie/core.py index c3567219be..44b3f5c5f2 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -185,7 +185,7 @@ def request_body_read_callback(chunk: bytes): final_response = message if args.check_status or downloader: exit_status = http_status_to_exit_status(http_status=message.status_code, follow=args.follow) - if exit_status != ExitStatus.SUCCESS and (not env.stdout_isatty or args.quiet): + if exit_status != ExitStatus.SUCCESS and (not env.stdout_isatty or args.quiet == 1): env.log_error(f'HTTP {message.raw.status} {message.raw.reason}', level='warning') write_message(requests_message=message, env=env, args=args, with_headers=with_headers, with_body=do_write_body) diff --git a/tests/test_output.py b/tests/test_output.py index de0e76f618..36072b6fcb 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -39,15 +39,16 @@ def test_output_option(tmp_path, httpbin, stdout_isatty): class TestQuietFlag: + QUIET_SCENARIOS = [('--quiet',), ('-q',), ('--quiet', '--quiet'), ('-qq',)] - @pytest.mark.parametrize('argument_name', ['--quiet', '-q']) - def test_quiet(self, httpbin, argument_name): + @pytest.mark.parametrize('quiet_flags', QUIET_SCENARIOS) + def test_quiet(self, httpbin, quiet_flags): env = MockEnvironment( stdin_isatty=True, stdout_isatty=True, devnull=io.BytesIO() ) - r = http(argument_name, 'GET', httpbin.url + '/get', env=env) + r = http(*quiet_flags, 'GET', httpbin.url + '/get', env=env) assert env.stdout is env.devnull assert env.stderr is env.devnull assert HTTP_OK in r.devnull @@ -69,9 +70,25 @@ def test_quiet_with_check_status_non_zero_pipe(self, httpbin): ) assert 'http: warning: HTTP 500' in r.stderr + def test_quiet_quiet_with_check_status_non_zero(self, httpbin): + r = http( + '--quiet', '--quiet', '--check-status', httpbin + '/status/500', + tolerate_error_exit_status=True, + ) + assert not r.stderr + + def test_quiet_quiet_with_check_status_non_zero_pipe(self, httpbin): + r = http( + '--quiet', '--quiet', '--check-status', httpbin + '/status/500', + tolerate_error_exit_status=True, + env=MockEnvironment(stdout_isatty=False) + ) + assert 'http: warning: HTTP 500' in r.stderr + + @pytest.mark.parametrize('quiet_flags', QUIET_SCENARIOS) @mock.patch('httpie.cli.argtypes.AuthCredentials._getpass', new=lambda self, prompt: 'password') - def test_quiet_with_password_prompt(self, httpbin): + def test_quiet_with_password_prompt(self, httpbin, quiet_flags): """ Tests whether httpie still prompts for a password when request requires authentication and only username is provided @@ -83,7 +100,7 @@ def test_quiet_with_password_prompt(self, httpbin): devnull=io.BytesIO() ) r = http( - '--quiet', '--auth', 'user', 'GET', + *quiet_flags, '--auth', 'user', 'GET', httpbin.url + '/basic-auth/user/password', env=env ) @@ -93,17 +110,19 @@ def test_quiet_with_password_prompt(self, httpbin): assert r == '' assert r.stderr == '' - @pytest.mark.parametrize('argument_name', ['-h', '-b', '-v', '-p=hH']) - def test_quiet_with_explicit_output_options(self, httpbin, argument_name): + @pytest.mark.parametrize('quiet_flags', QUIET_SCENARIOS) + @pytest.mark.parametrize('output_options', ['-h', '-b', '-v', '-p=hH']) + def test_quiet_with_explicit_output_options(self, httpbin, quiet_flags, output_options): env = MockEnvironment(stdin_isatty=True, stdout_isatty=True) - r = http('--quiet', argument_name, httpbin.url + '/get', env=env) + r = http(*quiet_flags, output_options, httpbin.url + '/get', env=env) assert env.stdout is env.devnull assert env.stderr is env.devnull assert r == '' assert r.stderr == '' + @pytest.mark.parametrize('quiet_flags', QUIET_SCENARIOS) @pytest.mark.parametrize('with_download', [True, False]) - def test_quiet_with_output_redirection(self, tmp_path, httpbin, with_download): + def test_quiet_with_output_redirection(self, tmp_path, httpbin, quiet_flags, with_download): url = httpbin + '/robots.txt' output_path = Path('output.txt') env = MockEnvironment() @@ -114,7 +133,7 @@ def test_quiet_with_output_redirection(self, tmp_path, httpbin, with_download): try: assert os.listdir('.') == [] r = http( - '--quiet', + *quiet_flags, '--output', str(output_path), *extra_args, url, @@ -142,7 +161,7 @@ def test_verbose(self, httpbin): def test_verbose_raw(self, httpbin): r = http('--verbose', '--raw', 'foo bar', - 'POST', httpbin.url + '/post',) + 'POST', httpbin.url + '/post') assert HTTP_OK in r assert 'foo bar' in r From ab8512f96cb551e9d2fa6468d1f1e0630dc23afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Fri, 8 Oct 2021 18:38:40 +0200 Subject: [PATCH 0866/1182] Add --compress documentation (#1173) * Add --compress documentation * Apply suggestions from code review Co-authored-by: Jakub Roztocil * Update docs/README.md * Update docs/README.md Co-authored-by: Jakub Roztocil --- docs/README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index e25ad930a2..9387c2c269 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1304,7 +1304,8 @@ The universal method for passing request data is through redirected `stdin` By default, `stdin` data is buffered and then with no further processing used as the request body. If you provide `Content-Length`, then the request body is streamed without buffering. -You may also use `--chunked` to enable streaming via [chunked transfer encoding](#chunked-transfer-encoding). +You may also use `--chunked` to enable streaming via [chunked transfer encoding](#chunked-transfer-encoding) +or `--compress, -x` to [compress the request body](#compressed-request-body). There are multiple useful ways to use piping: @@ -1414,6 +1415,24 @@ $ http --chunked pie.dev/post @files/data.xml $ cat files/data.xml | http --chunked pie.dev/post ``` +## Compressed request body + +You can use the `--compress, -x` flag to instruct HTTPie to use `Content-Encoding: deflate` and compress the request data: + +```bash +$ http --compress pie.dev/post @files/data.xml +``` + +```bash +$ cat files/data.xml | http --compress pie.dev/post +``` + +If compressing the data does not save size, HTTPie sends it untouched. To always compress the data, specify `--compress, -x` twice: + +```bash +$ http -xx PUT pie.dev/put hello=world +``` + ## Terminal output HTTPie does several things by default in order to make its terminal output easy to read. From 459cdfcf538b7724b5fd1a2833dacebcc815630a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 10 Oct 2021 20:17:49 +0200 Subject: [PATCH 0867/1182] Tweak install docs template Shorten setup, add missing comma --- .github/workflows/docs-update-install.yml | 1 + docs/installation/installation.jinja2 | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docs-update-install.yml b/.github/workflows/docs-update-install.yml index d612e5ae34..99d4d1e1eb 100644 --- a/.github/workflows/docs-update-install.yml +++ b/.github/workflows/docs-update-install.yml @@ -3,6 +3,7 @@ on: branches: - master paths: + - .github/workflows/docs-update-install.yml - docs/installation/* # Allow to call the workflow manually diff --git a/docs/installation/installation.jinja2 b/docs/installation/installation.jinja2 index 5ecd816ea9..28671a7ed2 100644 --- a/docs/installation/installation.jinja2 +++ b/docs/installation/installation.jinja2 @@ -19,16 +19,16 @@ Do not edit here, but in docs/installation/. {% endif %} {% if tool.links.setup %} - To install [{{ tool.name }}]({{ tool.links.homepage }}) follow [installation instructions]({{ tool.links.setup }}). + To install [{{ tool.name }}]({{ tool.links.homepage }}), see [its installation]({{ tool.links.setup }}). {% endif %} ```bash - # Install + # Install httpie $ {{ tool.commands.install|join('\n$ ') }} ``` ```bash - # Upgrade + # Upgrade httpie $ {{ tool.commands.upgrade|join('\n$ ') }} ``` {% endfor %} From 7d418aecd0330202a10eba96ca68c1dc32821f1b Mon Sep 17 00:00:00 2001 From: jakubroztocil Date: Sun, 10 Oct 2021 18:18:39 +0000 Subject: [PATCH 0868/1182] Auto-update installation instructions in the docs --- docs/README.md | 84 +++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/docs/README.md b/docs/README.md index 9387c2c269..bac9ee9009 100644 --- a/docs/README.md +++ b/docs/README.md @@ -63,13 +63,13 @@ Do not edit here, but in docs/installation/. Please make sure you have Python 3.6 or newer (`python --version`). ```bash -# Install +# Install httpie $ python -m pip install --upgrade pip wheel $ python -m pip install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ python -m pip install --upgrade pip wheel $ python -m pip install --upgrade httpie ``` @@ -78,61 +78,61 @@ $ python -m pip install --upgrade httpie #### Homebrew -To install [Homebrew](https://brew.sh/) follow [installation instructions](https://docs.brew.sh/Installation). +To install [Homebrew](https://brew.sh/), see [its installation](https://docs.brew.sh/Installation). ```bash -# Install +# Install httpie $ brew update $ brew install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ brew update $ brew upgrade httpie ``` #### MacPorts -To install [MacPorts](https://www.macports.org/) follow [installation instructions](https://www.macports.org/install.php). +To install [MacPorts](https://www.macports.org/), see [its installation](https://www.macports.org/install.php). ```bash -# Install +# Install httpie $ port selfupdate $ port install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ port selfupdate $ port upgrade httpie ``` #### Snapcraft (macOS) -To install [Snapcraft](https://snapcraft.io/) follow [installation instructions](https://snapcraft.io/docs/installing-snapd). +To install [Snapcraft](https://snapcraft.io/), see [its installation](https://snapcraft.io/docs/installing-snapd). ```bash -# Install +# Install httpie $ snap install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ snap refresh httpie ``` #### Spack (macOS) -To install [Spack](https://spack.readthedocs.io/en/latest/index.html) follow [installation instructions](https://spack.readthedocs.io/en/latest/getting_started.html#installation). +To install [Spack](https://spack.readthedocs.io/en/latest/index.html), see [its installation](https://spack.readthedocs.io/en/latest/getting_started.html#installation). ```bash -# Install +# Install httpie $ spack install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ spack install httpie ``` @@ -140,15 +140,15 @@ $ spack install httpie #### Chocolatey -To install [Chocolatey](https://chocolatey.org/) follow [installation instructions](https://chocolatey.org/install). +To install [Chocolatey](https://chocolatey.org/), see [its installation](https://chocolatey.org/install). ```bash -# Install +# Install httpie $ choco install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ choco upgrade httpie ``` @@ -156,30 +156,30 @@ $ choco upgrade httpie #### Snapcraft (Linux) -To install [Snapcraft](https://snapcraft.io/) follow [installation instructions](https://snapcraft.io/docs/installing-snapd). +To install [Snapcraft](https://snapcraft.io/), see [its installation](https://snapcraft.io/docs/installing-snapd). ```bash -# Install +# Install httpie $ snap install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ snap refresh httpie ``` #### Linuxbrew -To install [Linuxbrew](https://docs.brew.sh/Homebrew-on-Linux) follow [installation instructions](https://docs.brew.sh/Homebrew-on-Linux#install). +To install [Linuxbrew](https://docs.brew.sh/Homebrew-on-Linux), see [its installation](https://docs.brew.sh/Homebrew-on-Linux#install). ```bash -# Install +# Install httpie $ brew update $ brew install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ brew update $ brew upgrade httpie ``` @@ -189,13 +189,13 @@ $ brew upgrade httpie Also works for other Debian-derived distributions like MX Linux, Linux Mint, deepin, Pop!_OS, KDE neon, Zorin OS, elementary OS, Kubuntu, Devuan, Linux Lite, Peppermint OS, Lubuntu, antiX, Xubuntu, etc. ```bash -# Install +# Install httpie $ apt update $ apt install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ apt update $ apt upgrade httpie ``` @@ -203,13 +203,13 @@ $ apt upgrade httpie #### Fedora ```bash -# Install +# Install httpie $ dnf update $ dnf install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ dnf update $ dnf upgrade httpie ``` @@ -219,14 +219,14 @@ $ dnf upgrade httpie Also works for other RHEL-derived distributions like ClearOS, Oracle Linux, etc. ```bash -# Install +# Install httpie $ yum update $ yum install epel-release $ yum install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ yum update $ yum upgrade httpie ``` @@ -234,13 +234,13 @@ $ yum upgrade httpie #### Alpine Linux ```bash -# Install +# Install httpie $ apk update $ apk add httpie ``` ```bash -# Upgrade +# Upgrade httpie $ apk update $ apk add --upgrade httpie ``` @@ -248,13 +248,13 @@ $ apk add --upgrade httpie #### Gentoo ```bash -# Install +# Install httpie $ emerge --sync $ emerge httpie ``` ```bash -# Upgrade +# Upgrade httpie $ emerge --sync $ emerge --update httpie ``` @@ -264,40 +264,40 @@ $ emerge --update httpie Also works for other Arch-derived distributions like ArcoLinux, EndeavourOS, Artix Linux, etc. ```bash -# Install +# Install httpie $ pacman -Sy httpie ``` ```bash -# Upgrade +# Upgrade httpie $ pacman -Syu httpie ``` #### Void Linux ```bash -# Install +# Install httpie $ xbps-install -Su $ xbps-install -S httpie ``` ```bash -# Upgrade +# Upgrade httpie $ xbps-install -Su $ xbps-install -Su httpie ``` #### Spack (Linux) -To install [Spack](https://spack.readthedocs.io/en/latest/index.html) follow [installation instructions](https://spack.readthedocs.io/en/latest/getting_started.html#installation). +To install [Spack](https://spack.readthedocs.io/en/latest/index.html), see [its installation](https://spack.readthedocs.io/en/latest/getting_started.html#installation). ```bash -# Install +# Install httpie $ spack install httpie ``` ```bash -# Upgrade +# Upgrade httpie $ spack install httpie ``` @@ -306,12 +306,12 @@ $ spack install httpie #### FreshPorts ```bash -# Install +# Install httpie $ pkg install www/py-httpie ``` ```bash -# Upgrade +# Upgrade httpie $ pkg upgrade www/py-httpie ``` From 6b99e1c932b5b9f0569b73ad87bb8d85299b4e2b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 10 Oct 2021 20:25:03 +0200 Subject: [PATCH 0869/1182] Link GitHub action file in generated commit --- .github/workflows/docs-update-install.yml | 6 +++++- docs/README.md | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docs-update-install.yml b/.github/workflows/docs-update-install.yml index 99d4d1e1eb..c7d13e0ba0 100644 --- a/.github/workflows/docs-update-install.yml +++ b/.github/workflows/docs-update-install.yml @@ -22,6 +22,10 @@ jobs: - uses: Automattic/action-commit-to-branch@master with: branch: master - commit_message: Auto-update installation instructions in the docs + commit_message: | + Auto-update install docs + + Via .github/workflows/docs-update-install.yml + env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/docs/README.md b/docs/README.md index bac9ee9009..d44d35bf19 100644 --- a/docs/README.md +++ b/docs/README.md @@ -47,7 +47,7 @@ You are invited to submit fixes and improvements to the docs by editing [this fi THE INSTALLATION SECTION IS GENERATED Do not edit here, but in docs/installation/. - +TEST --> - [Universal](#universal) From ce9746b1f8b4a79bf6bb6e5b9851539fc8ffb118 Mon Sep 17 00:00:00 2001 From: jakubroztocil Date: Sun, 10 Oct 2021 18:25:59 +0000 Subject: [PATCH 0870/1182] Auto-update install docs Via .github/workflows/docs-update-install.yml --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index d44d35bf19..bac9ee9009 100644 --- a/docs/README.md +++ b/docs/README.md @@ -47,7 +47,7 @@ You are invited to submit fixes and improvements to the docs by editing [this fi THE INSTALLATION SECTION IS GENERATED Do not edit here, but in docs/installation/. -TEST + --> - [Universal](#universal) From 1171984ec2eb1690058dfd2f714ad82159d23130 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 10 Oct 2021 20:45:41 +0200 Subject: [PATCH 0871/1182] Better links for snap on macos --- docs/installation/methods.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/methods.yml b/docs/installation/methods.yml index f4990598c3..fbcc8e5ea2 100644 --- a/docs/installation/methods.yml +++ b/docs/installation/methods.yml @@ -207,7 +207,7 @@ tools: name: Snapcraft links: homepage: https://snapcraft.io/ - setup: https://snapcraft.io/docs/installing-snapd + setup: https://snapcraft.io/docs/installing-snapcraft package: https://snapcraft.io/httpie commands: install: From ef92e2a74a576b01fb7269ff2bd93eaa00c6de07 Mon Sep 17 00:00:00 2001 From: jakubroztocil Date: Sun, 10 Oct 2021 18:46:46 +0000 Subject: [PATCH 0872/1182] Auto-update install docs Via .github/workflows/docs-update-install.yml --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index bac9ee9009..6fb10a9761 100644 --- a/docs/README.md +++ b/docs/README.md @@ -110,7 +110,7 @@ $ port upgrade httpie #### Snapcraft (macOS) -To install [Snapcraft](https://snapcraft.io/), see [its installation](https://snapcraft.io/docs/installing-snapd). +To install [Snapcraft](https://snapcraft.io/), see [its installation](https://snapcraft.io/docs/installing-snapcraft). ```bash # Install httpie From 59f4ef03ccb95b2147d351d13487312f5e9bdf76 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 10 Oct 2021 20:57:58 +0200 Subject: [PATCH 0873/1182] Remove macOS/Snap snapd is not available on macOS yet --- docs/installation/methods.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/docs/installation/methods.yml b/docs/installation/methods.yml index fbcc8e5ea2..77ab986316 100644 --- a/docs/installation/methods.yml +++ b/docs/installation/methods.yml @@ -14,7 +14,6 @@ docs-structure: macOS: - brew-mac - port - - snap-mac - spack-mac Windows: - chocolatey @@ -202,19 +201,6 @@ tools: upgrade: - snap refresh httpie - snap-mac: - title: Snapcraft (macOS) - name: Snapcraft - links: - homepage: https://snapcraft.io/ - setup: https://snapcraft.io/docs/installing-snapcraft - package: https://snapcraft.io/httpie - commands: - install: - - snap install httpie - upgrade: - - snap refresh httpie - spack-linux: title: Spack (Linux) name: Spack From 9f6fa090df0bcec9f02734665834bf60fd204308 Mon Sep 17 00:00:00 2001 From: jakubroztocil Date: Sun, 10 Oct 2021 18:58:57 +0000 Subject: [PATCH 0874/1182] Auto-update install docs Via .github/workflows/docs-update-install.yml --- docs/README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/docs/README.md b/docs/README.md index 6fb10a9761..b33706bab8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -108,20 +108,6 @@ $ port selfupdate $ port upgrade httpie ``` -#### Snapcraft (macOS) - -To install [Snapcraft](https://snapcraft.io/), see [its installation](https://snapcraft.io/docs/installing-snapcraft). - -```bash -# Install httpie -$ snap install httpie -``` - -```bash -# Upgrade httpie -$ snap refresh httpie -``` - #### Spack (macOS) To install [Spack](https://spack.readthedocs.io/en/latest/index.html), see [its installation](https://spack.readthedocs.io/en/latest/getting_started.html#installation). From 344491ba8e3ca10c223e6daf5a601d5fc95cdf71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 11 Oct 2021 10:07:24 +0200 Subject: [PATCH 0875/1182] Tweak the Chocolatey package installation file --- .../windows-chocolatey/tools/chocolateyinstall.ps1 | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/packaging/windows-chocolatey/tools/chocolateyinstall.ps1 b/docs/packaging/windows-chocolatey/tools/chocolateyinstall.ps1 index 36f3b195c5..e27045f342 100644 --- a/docs/packaging/windows-chocolatey/tools/chocolateyinstall.ps1 +++ b/docs/packaging/windows-chocolatey/tools/chocolateyinstall.ps1 @@ -1,6 +1,2 @@ $ErrorActionPreference = 'Stop'; -$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" -$nuspecPath = "$(Join-Path (Split-Path -parent $toolsDir) ($env:ChocolateyPackageName + ".nuspec"))" -[XML]$nuspec = Get-Content $nuspecPath -$pipVersion = $nuspec.package.metadata.version -py -m pip install "$($env:ChocolateyPackageName)==$($pipVersion)" --disable-pip-version-check +py -m pip install $env:ChocolateyPackageName==$env:ChocolateyPackageVersion --disable-pip-version-check From 19691bba68eea8ca5f8b9b73ba22e5cd9883a00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 11 Oct 2021 17:42:29 +0200 Subject: [PATCH 0876/1182] Packaging documentation tweaks --- docs/packaging/README.md | 3 ++- httpie/output/lexers/json.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/packaging/README.md b/docs/packaging/README.md index 5cc107459e..40099faaae 100644 --- a/docs/packaging/README.md +++ b/docs/packaging/README.md @@ -23,7 +23,8 @@ That is done quite easily by manually triggering the [release workflow](https:// ## Then, company-specific tasks -- Update the HTTPie version bundled into termible ([example](https://github.com/httpie/termible/pull/1)). +- Blank the `master_and_released_docs_differ_after` value in [config.json](https://github.com/httpie/httpie/blob/master/docs/config.json). +- Update the HTTPie version bundled into [Termible](https://termible.io/) ([example](https://github.com/httpie/termible/pull/1)). ## Finally, spread dowstream diff --git a/httpie/output/lexers/json.py b/httpie/output/lexers/json.py index a235c4f3a3..d26e522f30 100644 --- a/httpie/output/lexers/json.py +++ b/httpie/output/lexers/json.py @@ -20,7 +20,7 @@ class EnhancedJsonLexer(RegexLexer): tokens = { 'root': [ # Eventual non-JSON data prefix followed by actual JSON body. - # FIX: data prefix + number (integer or float) are not correctly handled. + # FIX: data prefix + number (integer or float) is not correctly handled. ( fr'({PREFIX_REGEX})' + r'((?:[{\["]|true|false|null).+)', bygroups(PREFIX_TOKEN, using(JsonLexer)) From a15fd6f966a72c0d40e8a65f0d91779d6963a516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 13 Oct 2021 23:32:46 +0200 Subject: [PATCH 0877/1182] Add `--response=mime` and `--response=charset` docs (#1179) * Add the "display encoding" section in the docs * Remove repetition * `--response=mime` / `--response=charset` docs * Cleanup * Cleanup * Cleanup Co-authored-by: Jakub Roztocil --- docs/README.md | 48 +++++++++++------------------------------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/docs/README.md b/docs/README.md index b33706bab8..45384ed9b4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1425,10 +1425,8 @@ HTTPie does several things by default in order to make its terminal output easy ### Colors and formatting - - Syntax highlighting is applied to HTTP headers and bodies (where it makes sense). -You can choose your preferred color scheme via the `--style` option if you don’t like the default one. +You can choose your preferred color scheme via the --style option if you don’t like the default one. There are dozens of styles available, here are just a few notable ones: | Style | Description | @@ -1448,6 +1446,12 @@ Use one of these options to control output processing: | `--pretty=format` | Apply formatting | | `--pretty=none` | Disables output processing. Default for redirected output | +HTTPie looks at `Content-Type` to select the right syntax highlighter and formatter for each message body. If that fails (e.g., the server provides the wrong type), or you prefer a different treatment, you can manually overwrite the mime type for a response with `--response-mime`: + +```bash +$ http --response-mime=text/yaml pie.dev/get +``` + Formatting has the following effects: - HTTP headers are sorted by name. @@ -1484,29 +1488,6 @@ sorting-related format options (currently it means JSON keys and headers): This is something you will typically store as one of the default options in your [config](#config) file. -### Response `Content-Type` - -The `--response-as=value` option allows you to override the response `Content-Type` sent by the server. -That makes it possible for HTTPie to print the response even when the server specifies the type incorrectly. - -For example, the following request will force the response to be treated as XML: - -```bash -$ http --response-as=application/xml pie.dev/get -``` - -And the following requests will force the response to use the [big5](https://docs.python.org/3/library/codecs.html#standard-encodings) encoding: - -```bash -$ http --response-as='charset=big5' pie.dev/get -``` - -```bash -$ http --response-as='text/plain; charset=big5' pie.dev/get -``` - -Given the encoding is not sent by the server, HTTPie will auto-detect it. - ### Redirected output HTTPie uses a different set of defaults for redirected output than for [terminal output](#terminal-output). @@ -1569,20 +1550,13 @@ Content-Type: application/octet-stream +-----------------------------------------+ ``` - +```bash +$ http --response-charset=big5 pie.dev/get +``` ## Download mode From 7b683d4b57c41f9acd5a7cb443d6edc51c5e02c3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 13 Oct 2021 23:37:40 +0200 Subject: [PATCH 0878/1182] Update CHANGELOG.md --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d926e0b1bb..f1340e6d61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,13 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.6.0.dev0](https://github.com/httpie/httpie/compare/2.5.0...master) (unreleased) -- Added the ability to silence warnings through using `-q` or `--quiet` twice (e.g. `-qq`) ([#1175](https://github.com/httpie/httpie/issues/1175)) - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) +- Added charset auto-detection when `Content-Type` doesn’t include it. ([#1110](https://github.com/httpie/httpie/issues/1110), [#1168](https://github.com/httpie/httpie/issues/1168)) - Added `--response-charset` to allow overriding the response encoding for terminal display purposes. ([#1168](https://github.com/httpie/httpie/issues/1168)) - Added `--response-mime` to allow overriding the response mime type for coloring and formatting for the terminal. ([#1168](https://github.com/httpie/httpie/issues/1168)) -- Improved handling of responses with incorrect `Content-Type`. ([#1110](https://github.com/httpie/httpie/issues/1110), [#1168](https://github.com/httpie/httpie/issues/1168)) -- Installed plugins are now listed in `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165)) -- Fixed duplicate keys preservation of JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163)) +- Added the ability to silence warnings through using `-q` or `--quiet` twice (e.g. `-qq`) ([#1175](https://github.com/httpie/httpie/issues/1175)) +- Added installed plugin list to `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165)) +- Fixed duplicate keys preservation in JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163)) ## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06) From a65771e2718d9b5c0ebbb123cd6392d350ee6469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 14 Oct 2021 10:33:14 +0200 Subject: [PATCH 0879/1182] Add a script that lists all contributors to a release (#1181) * Add a script that lists all contributors to a release We will keep a contributors database (simple JSON file) where each entry is a contributor (either a committer, either an issue reporter, either both) with some nicknames (GitHub, and Twitter). The file will be used to craft credits on our release blog posts and to ping them on Twitter. * Add templates * Missing docstring * Clean-up * Tweak --- docs/contributors/README.md | 3 + docs/contributors/fetch.py | 280 +++++++++++++++++++++++++++++++ docs/contributors/generate.py | 41 +++++ docs/contributors/people.json | 240 ++++++++++++++++++++++++++ docs/contributors/snippet.jinja2 | 13 ++ 5 files changed, 577 insertions(+) create mode 100644 docs/contributors/README.md create mode 100644 docs/contributors/fetch.py create mode 100644 docs/contributors/generate.py create mode 100644 docs/contributors/people.json create mode 100644 docs/contributors/snippet.jinja2 diff --git a/docs/contributors/README.md b/docs/contributors/README.md new file mode 100644 index 0000000000..20b3c278fb --- /dev/null +++ b/docs/contributors/README.md @@ -0,0 +1,3 @@ +Here we maintain a database of contributors, from which we generate credits on release blog posts and social medias. + +For the HTTPie blog see: . diff --git a/docs/contributors/fetch.py b/docs/contributors/fetch.py new file mode 100644 index 0000000000..7924f46443 --- /dev/null +++ b/docs/contributors/fetch.py @@ -0,0 +1,280 @@ +""" +Generate the contributors database. + +FIXME: replace `requests` calls with the HTTPie API, when available. +""" +import json +import os +import re +import sys +from copy import deepcopy +from datetime import datetime +from pathlib import Path +from subprocess import check_output +from time import sleep +from typing import Any, Dict, Optional, Set + +import requests + +FullNames = Set[str] +GitHubLogins = Set[str] +Person = Dict[str, str] +People = Dict[str, Person] +UserInfo = Dict[str, Any] + +CO_AUTHORS = re.compile(r'Co-authored-by: ([^<]+) <').finditer +API_URL = 'https://api.github.com' +REPO = OWNER = 'httpie' +REPO_URL = f'{API_URL}/repos/{REPO}/{OWNER}' + +HERE = Path(__file__).parent +DB_FILE = HERE / 'people.json' + +DEFAULT_PERSON: Person = {'committed': [], 'reported': [], 'github': '', 'twitter': ''} +SKIPPED_LABELS = {'invalid'} + +GITHUB_TOKEN = os.getenv('GITHUB_TOKEN') +assert GITHUB_TOKEN, 'GITHUB_TOKEN envar is missing' + + +class FinishedForNow(Exception): + """Raised when remaining GitHub rate limit is zero.""" + + +def main(previous_release: str, current_release: str) -> int: + since = release_date(previous_release) + until = release_date(current_release) + + contributors = load_awesome_people() + try: + committers = find_committers(since, until) + reporters = find_reporters(since, until) + except Exception as exc: + # We want to save what we fetched so far. So pass. + print(' !! ', exc) + + try: + merge_all_the_people(current_release, contributors, committers, reporters) + fetch_missing_users_details(contributors) + except FinishedForNow: + # We want to save what we fetched so far. So pass. + print(' !! Committers:', committers) + print(' !! Reporters:', reporters) + exit_status = 1 + else: + exit_status = 0 + + save_awesome_people(contributors) + return exit_status + + +def find_committers(since: str, until: str) -> FullNames: + url = f'{REPO_URL}/commits' + page = 1 + per_page = 100 + params = { + 'since': since, + 'until': until, + 'per_page': per_page, + } + committers: FullNames = set() + + while 'there are commits': + params['page'] = page + data = fetch(url, params=params) + + for item in data: + commit = item['commit'] + committers.add(commit['author']['name']) + debug(' >>> Commit', item['html_url']) + for co_author in CO_AUTHORS(commit['message']): + name = co_author.group(1) + committers.add(name) + + if len(data) < per_page: + break + page += 1 + + return committers + + +def find_reporters(since: str, until: str) -> GitHubLogins: + url = f'{API_URL}/search/issues' + page = 1 + per_page = 100 + params = { + 'q': f'repo:{REPO}/{OWNER} is:issue closed:{since}..{until}', + 'per_page': per_page, + } + reporters: GitHubLogins = set() + + while 'there are issues': + params['page'] = page + data = fetch(url, params=params) + + for item in data['items']: + # Filter out unwanted labels. + if any(label['name'] in SKIPPED_LABELS for label in item['labels']): + continue + debug(' >>> Issue', item['html_url']) + reporters.add(item['user']['login']) + + if len(data['items']) < per_page: + break + page += 1 + + return reporters + + +def merge_all_the_people(release: str, contributors: People, committers: FullNames, reporters: GitHubLogins) -> None: + """ + >>> contributors = {'Alice': new_person(github='alice', twitter='alice')} + >>> merge_all_the_people('2.6.0', contributors, {}, {}) + >>> contributors + {'Alice': {'committed': [], 'reported': [], 'github': 'alice', 'twitter': 'alice'}} + + >>> contributors = {'Bob': new_person(github='bob', twitter='bob')} + >>> merge_all_the_people('2.6.0', contributors, {'Bob'}, {'bob'}) + >>> contributors + {'Bob': {'committed': ['2.6.0'], 'reported': ['2.6.0'], 'github': 'bob', 'twitter': 'bob'}} + + >>> contributors = {'Charlotte': new_person(github='charlotte', twitter='charlotte', committed=['2.5.0'], reported=['2.5.0'])} + >>> merge_all_the_people('2.6.0', contributors, {'Charlotte'}, {'charlotte'}) + >>> contributors + {'Charlotte': {'committed': ['2.5.0', '2.6.0'], 'reported': ['2.5.0', '2.6.0'], 'github': 'charlotte', 'twitter': 'charlotte'}} + + """ + # Update known contributors. + for name, details in contributors.items(): + if name in committers: + if release not in details['committed']: + details['committed'].append(release) + committers.remove(name) + if details['github'] in reporters: + if release not in details['reported']: + details['reported'].append(release) + reporters.remove(details['github']) + + # Add new committers. + for name in committers: + user_info = user(fullname=name) + contributors[name] = new_person( + github=user_info['login'], + twitter=user_info['twitter_username'], + committed=[release], + ) + if user_info['login'] in reporters: + contributors[name]['reported'].append(release) + reporters.remove(user_info['login']) + + # Add new reporters. + for github_username in reporters: + user_info = user(github_username=github_username) + contributors[user_info['name'] or user_info['login']] = new_person( + github=github_username, + twitter=user_info['twitter_username'], + reported=[release], + ) + + +def release_date(release: str) -> str: + date = check_output(['git', 'log', '-1', '--format=%ai', release], text=True).strip() + return datetime.strptime(date, '%Y-%m-%d %H:%M:%S %z').isoformat() + + +def load_awesome_people() -> People: + try: + with DB_FILE.open(encoding='utf-8') as fh: + return json.load(fh) + except (FileNotFoundError, ValueError): + return {} + + +def fetch(url: str, params: Optional[Dict[str, str]] = None) -> UserInfo: + headers = { + 'Accept': 'application/vnd.github.v3+json', + 'Authentication': f'token {GITHUB_TOKEN}' + } + for retry in range(1, 6): + debug(f'[{retry}/5]', f'{url = }', f'{params = }') + with requests.get(url, params=params, headers=headers) as req: + try: + req.raise_for_status() + except requests.exceptions.HTTPError as exc: + if exc.response.status_code == 403: + # 403 Client Error: rate limit exceeded for url: ... + now = int(datetime.utcnow().timestamp()) + xrate_limit_reset = int(exc.response.headers['X-RateLimit-Reset']) + wait = xrate_limit_reset - now + if wait > 20: + raise FinishedForNow() + debug(' !', 'Waiting', wait, 'seconds before another try ...') + sleep(wait) + continue + return req.json() + assert ValueError('Rate limit exceeded') + + +def new_person(**kwargs: str) -> Person: + data = deepcopy(DEFAULT_PERSON) + data.update(**kwargs) + return data + + +def user(fullname: Optional[str] = '', github_username: Optional[str] = '') -> UserInfo: + if github_username: + url = f'{API_URL}/users/{github_username}' + return fetch(url) + + url = f'{API_URL}/search/users' + for query in (f'fullname:{fullname}', f'user:{fullname}'): + params = { + 'q': f'repo:{REPO}/{OWNER} {query}', + 'per_page': 1, + } + user_info = fetch(url, params=params) + if user_info['items']: + user_url = user_info['items'][0]['url'] + return fetch(user_url) + + +def fetch_missing_users_details(people: People) -> None: + for name, details in people.items(): + if details['github'] and details['twitter']: + continue + user_info = user(github_username=details['github'], fullname=name) + if not details['github']: + details['github'] = user_info['login'] + if not details['twitter']: + details['twitter'] = user_info['twitter_username'] + + +def save_awesome_people(people: People) -> None: + with DB_FILE.open(mode='w', encoding='utf-8') as fh: + json.dump(people, fh, indent=4, sort_keys=True) + + +def debug(*args: Any) -> None: + if os.getenv('DEBUG') == '1': + print(*args) + + +if __name__ == '__main__': + ret = 1 + try: + ret = main(*sys.argv[1:]) + except TypeError: + ret = 2 + print(f''' +Fetch contributors to a release. + +Usage: + python {sys.argv[0]} {sys.argv[0]} +Example: + python {sys.argv[0]} 2.4.0 2.5.0 + +Define the DEBUG=1 environment variable to enable verbose output. +''') + except KeyboardInterrupt: + ret = 255 + sys.exit(ret) diff --git a/docs/contributors/generate.py b/docs/contributors/generate.py new file mode 100644 index 0000000000..2205d411e0 --- /dev/null +++ b/docs/contributors/generate.py @@ -0,0 +1,41 @@ +""" +Generate snippets to copy-paste. +""" +import sys + +from jinja2 import Template + +from fetch import HERE, load_awesome_people + +TPL_FILE = HERE / 'snippet.jinja2' +HTTPIE_TEAM = {'jakubroztocil', 'BoboTiG', 'claudiatd'} + + +def generate_snippets(release: str) -> str: + people = load_awesome_people() + contributors = { + name: details + for name, details in people.items() + if details['github'] not in HTTPIE_TEAM + and (release in details['committed'] or release in details['reported']) + } + + template = Template(source=TPL_FILE.read_text(encoding='utf-8')) + output = template.render(contributors=contributors, release=release) + print(output) + return 0 + + +if __name__ == '__main__': + ret = 1 + try: + ret = generate_snippets(sys.argv[1]) + except (IndexError, TypeError): + ret = 2 + print(f''' +Generate snippets for contributors to a release. + +Usage: + python {sys.argv[0]} {sys.argv[0]} +''') + sys.exit(ret) diff --git a/docs/contributors/people.json b/docs/contributors/people.json new file mode 100644 index 0000000000..146d9470ce --- /dev/null +++ b/docs/contributors/people.json @@ -0,0 +1,240 @@ +{ + "Almad": { + "committed": [ + "2.5.0" + ], + "github": "Almad", + "reported": [], + "twitter": "almadcz" + }, + "Anton Emelyanov": { + "committed": [ + "2.5.0" + ], + "github": "king-menin", + "reported": [], + "twitter": null + }, + "D8ger": { + "committed": [], + "github": "caofanCPU", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "Dawid Ferenczy Rogo\u017ean": { + "committed": [], + "github": "ferenczy", + "reported": [ + "2.5.0" + ], + "twitter": "DawidFerenczy" + }, + "Elena Lape": { + "committed": [ + "2.5.0" + ], + "github": "elenalape", + "reported": [], + "twitter": "elena_lape" + }, + "F\u00fash\u0113ng": { + "committed": [], + "github": "lienide", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "Giampaolo Rodola": { + "committed": [], + "github": "giampaolo", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "Hugh Williams": { + "committed": [], + "github": "hughpv", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "Ilya Sukhanov": { + "committed": [ + "2.5.0" + ], + "github": "IlyaSukhanov", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "Jakub Roztocil": { + "committed": [ + "2.5.0" + ], + "github": "jakubroztocil", + "reported": [ + "2.5.0" + ], + "twitter": "jakubroztocil" + }, + "Jan Verbeek": { + "committed": [ + "2.5.0" + ], + "github": "blyxxyz", + "reported": [], + "twitter": null + }, + "Jannik Vieten": { + "committed": [ + "2.5.0" + ], + "github": "exploide", + "reported": [], + "twitter": null + }, + "Marcel St\u00f6r": { + "committed": [ + "2.5.0" + ], + "github": "marcelstoer", + "reported": [], + "twitter": "frightanic" + }, + "Mariano Ruiz": { + "committed": [], + "github": "mrsarm", + "reported": [ + "2.5.0" + ], + "twitter": "mrsarm82" + }, + "Micka\u00ebl Schoentgen": { + "committed": [ + "2.5.0" + ], + "github": "BoboTiG", + "reported": [ + "2.5.0" + ], + "twitter": "__tiger222__" + }, + "Miro Hron\u010dok": { + "committed": [ + "2.5.0" + ], + "github": "hroncok", + "reported": [], + "twitter": "hroncok" + }, + "Mohamed Daahir": { + "committed": [], + "github": "ducaale", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "Pavel Alexeev aka Pahan-Hubbitus": { + "committed": [], + "github": "Hubbitus", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "Samuel Marks": { + "committed": [], + "github": "SamuelMarks", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "Sullivan SENECHAL": { + "committed": [], + "github": "soullivaneuh", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "Thomas Klinger": { + "committed": [], + "github": "mosesontheweb", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "Yannic Schneider": { + "committed": [], + "github": "cynay", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "a1346054": { + "committed": [ + "2.5.0" + ], + "github": "a1346054", + "reported": [], + "twitter": null + }, + "bl-ue": { + "committed": [ + "2.5.0" + ], + "github": "FiReBlUe45", + "reported": [], + "twitter": null + }, + "henryhu712": { + "committed": [ + "2.5.0" + ], + "github": "henryhu712", + "reported": [], + "twitter": null + }, + "jungle-boogie": { + "committed": [], + "github": "jungle-boogie", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "nixbytes": { + "committed": [ + "2.5.0" + ], + "github": "nixbytes", + "reported": [], + "twitter": "linuxbyte3" + }, + "qiulang": { + "committed": [], + "github": "qiulang", + "reported": [ + "2.5.0" + ], + "twitter": null + }, + "zwx00": { + "committed": [], + "github": "zwx00", + "reported": [ + "2.5.0" + ], + "twitter": null + } +} \ No newline at end of file diff --git a/docs/contributors/snippet.jinja2 b/docs/contributors/snippet.jinja2 new file mode 100644 index 0000000000..4fa21b12ef --- /dev/null +++ b/docs/contributors/snippet.jinja2 @@ -0,0 +1,13 @@ + + +## Community contributions + +We’d like to thank these amazing people for their contributions to this release: {% for name, details in contributors.items() -%} + [{{ name }}](https://github.com/{{ details.github }}){{ '' if loop.last else ', ' }} +{%- endfor %}. + + + +We’d like to thank these amazing people for their contributions to HTTPie {{ release }}: {% for name, details in contributors.items() if details.twitter -%} + @{{ details.twitter }}{{ '' if loop.last else ', ' }} +{%- endfor %} 🥧 From 42af2f786f4e3bf005636aca02e4442128f0115e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 14 Oct 2021 10:36:39 +0200 Subject: [PATCH 0880/1182] v2.6.0 (#1182) [skip ci] --- CHANGELOG.md | 2 +- docs/README.md | 2 +- httpie/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1340e6d61..1a217cad52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). -## [2.6.0.dev0](https://github.com/httpie/httpie/compare/2.5.0...master) (unreleased) +## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) - Added charset auto-detection when `Content-Type` doesn’t include it. ([#1110](https://github.com/httpie/httpie/issues/1110), [#1168](https://github.com/httpie/httpie/issues/1168)) diff --git a/docs/README.md b/docs/README.md index 45384ed9b4..77fd48cf91 100644 --- a/docs/README.md +++ b/docs/README.md @@ -334,7 +334,7 @@ Verify that now you have the [current development version identifier](https://gi ```bash $ http --version -# 2.6.0.dev0 +# 2.6.0 ``` ## Usage diff --git a/httpie/__init__.py b/httpie/__init__.py index af8f4e01a9..b5b0447ca2 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '2.6.0.dev0' +__version__ = '2.6.0' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 6c6093a46d2453bf649b0c49d8becd03fa73c876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 14 Oct 2021 10:45:31 +0200 Subject: [PATCH 0881/1182] Configure PyPi for the release workflow --- .github/workflows/release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9e1c1f53ed..8d9c79ef57 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,6 +19,9 @@ jobs: - uses: actions/checkout@v2 with: ref: ${{ github.event.inputs.branch }} + - name: PyPi configuration + run: | + echo "[distutils]\nindex-servers=\n httpie\n\n[httpie]\n" > $HOME/.pypirc - uses: actions/setup-python@v2 with: python-version: 3.9 From cdab8e67cbee72edd10f6eab3497e5bbad0b1f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 14 Oct 2021 10:56:13 +0200 Subject: [PATCH 0882/1182] Release workflow: fix --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8d9c79ef57..e2dd258209 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: ref: ${{ github.event.inputs.branch }} - name: PyPi configuration run: | - echo "[distutils]\nindex-servers=\n httpie\n\n[httpie]\n" > $HOME/.pypirc + echo "[distutils]\nindex-servers=\n httpie\n\n[httpie]\nrepository = https://upload.pypi.org/legacy/\n" > $HOME/.pypirc - uses: actions/setup-python@v2 with: python-version: 3.9 From 5c267003c7fc55c5849eb035b88d86c76f66b59c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 14 Oct 2021 11:25:13 +0200 Subject: [PATCH 0883/1182] Update links --- setup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 45826d2d17..91f5be930a 100644 --- a/setup.py +++ b/setup.py @@ -100,9 +100,11 @@ def long_description(): 'Topic :: Utilities' ], project_urls={ + 'Homepage': 'https://httpie.io/', 'GitHub': 'https://github.com/httpie/httpie', 'Twitter': 'https://twitter.com/httpie', - 'Documentation': 'https://httpie.org/docs', - 'Online Demo': 'https://httpie.org/run', + 'Discord': 'https://httpie.io/discord', + 'Documentation': 'https://httpie.io/docs', + 'Online Demo': 'https://httpie.io/run', }, ) From cee283a01ae0c9e7d4079dcfbf1be3426568f71f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 14 Oct 2021 11:27:12 +0200 Subject: [PATCH 0884/1182] Update setup.py --- setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 91f5be930a..ee6a4f4133 100644 --- a/setup.py +++ b/setup.py @@ -69,7 +69,7 @@ def long_description(): description=httpie.__doc__.strip(), long_description=long_description(), long_description_content_type='text/markdown', - url='https://httpie.org/', + url='https://httpie.io/', download_url=f'https://github.com/httpie/httpie/archive/{httpie.__version__}.tar.gz', author=httpie.__author__, author_email='jakub@roztocil.co', @@ -100,7 +100,6 @@ def long_description(): 'Topic :: Utilities' ], project_urls={ - 'Homepage': 'https://httpie.io/', 'GitHub': 'https://github.com/httpie/httpie', 'Twitter': 'https://twitter.com/httpie', 'Discord': 'https://httpie.io/discord', From d8f6a5fe5211eb33d5110770e4f38224ccaf0936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 14 Oct 2021 11:29:36 +0200 Subject: [PATCH 0885/1182] Blank `master_and_released_docs_differ_after` --- docs/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.json b/docs/config.json index 2ba18b9d13..4375a5a5e7 100644 --- a/docs/config.json +++ b/docs/config.json @@ -1,5 +1,5 @@ { "website": { - "master_and_released_docs_differ_after": "8f8851f1dbd511d3bc0ea0f6da7459045610afce" + "master_and_released_docs_differ_after": null } } From 3e414d731c1f24797fd17e5bea29b7a8eeef30f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Thu, 14 Oct 2021 17:17:14 +0200 Subject: [PATCH 0886/1182] Update the awesome contributors list to HTTPie 2.6.0 --- docs/contributors/generate.py | 7 ++- docs/contributors/people.json | 101 ++++++++++++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 7 deletions(-) diff --git a/docs/contributors/generate.py b/docs/contributors/generate.py index 2205d411e0..78682f7d87 100644 --- a/docs/contributors/generate.py +++ b/docs/contributors/generate.py @@ -8,7 +8,12 @@ from fetch import HERE, load_awesome_people TPL_FILE = HERE / 'snippet.jinja2' -HTTPIE_TEAM = {'jakubroztocil', 'BoboTiG', 'claudiatd'} +HTTPIE_TEAM = { + 'BoboTiG', + 'claudiatd', + 'jakubroztocil', + 'jkbr', +} def generate_snippets(release: str) -> str: diff --git a/docs/contributors/people.json b/docs/contributors/people.json index 146d9470ce..aeea1906e9 100644 --- a/docs/contributors/people.json +++ b/docs/contributors/people.json @@ -4,9 +4,19 @@ "2.5.0" ], "github": "Almad", - "reported": [], + "reported": [ + "2.6.0" + ], "twitter": "almadcz" }, + "Annette Wilson": { + "committed": [], + "github": "annettejanewilson", + "reported": [ + "2.6.0" + ], + "twitter": null + }, "Anton Emelyanov": { "committed": [ "2.5.0" @@ -23,6 +33,14 @@ ], "twitter": null }, + "Dave": { + "committed": [ + "2.6.0" + ], + "github": "davecheney", + "reported": [], + "twitter": "davecheney" + }, "Dawid Ferenczy Rogo\u017ean": { "committed": [], "github": "ferenczy", @@ -39,6 +57,14 @@ "reported": [], "twitter": "elena_lape" }, + "Fabio Peruzzo": { + "committed": [], + "github": "peruzzof", + "reported": [ + "2.6.0" + ], + "twitter": null + }, "F\u00fash\u0113ng": { "committed": [], "github": "lienide", @@ -75,11 +101,13 @@ }, "Jakub Roztocil": { "committed": [ - "2.5.0" + "2.5.0", + "2.6.0" ], "github": "jakubroztocil", "reported": [ - "2.5.0" + "2.5.0", + "2.6.0" ], "twitter": "jakubroztocil" }, @@ -117,17 +145,20 @@ }, "Micka\u00ebl Schoentgen": { "committed": [ - "2.5.0" + "2.5.0", + "2.6.0" ], "github": "BoboTiG", "reported": [ - "2.5.0" + "2.5.0", + "2.6.0" ], "twitter": "__tiger222__" }, "Miro Hron\u010dok": { "committed": [ - "2.5.0" + "2.5.0", + "2.6.0" ], "github": "hroncok", "reported": [], @@ -141,6 +172,16 @@ ], "twitter": null }, + "Omer Akram": { + "committed": [ + "2.6.0" + ], + "github": "om26er", + "reported": [ + "2.6.0" + ], + "twitter": "om26er" + }, "Pavel Alexeev aka Pahan-Hubbitus": { "committed": [], "github": "Hubbitus", @@ -173,6 +214,14 @@ ], "twitter": null }, + "Vincent van \u2019t Zand": { + "committed": [], + "github": "vovtz", + "reported": [ + "2.6.0" + ], + "twitter": null + }, "Yannic Schneider": { "committed": [], "github": "cynay", @@ -197,6 +246,22 @@ "reported": [], "twitter": null }, + "claudiatd": { + "committed": [ + "2.6.0" + ], + "github": "claudiatd", + "reported": [], + "twitter": null + }, + "dkreeft": { + "committed": [ + "2.6.0" + ], + "github": "dkreeft", + "reported": [], + "twitter": null + }, "henryhu712": { "committed": [ "2.5.0" @@ -205,6 +270,14 @@ "reported": [], "twitter": null }, + "jakubroztocil": { + "committed": [ + "2.6.0" + ], + "github": "jkbr", + "reported": [], + "twitter": null + }, "jungle-boogie": { "committed": [], "github": "jungle-boogie", @@ -236,5 +309,21 @@ "2.5.0" ], "twitter": null + }, + "\u5d14\u5c0f\u4e8c": { + "committed": [], + "github": "rogerdehe", + "reported": [ + "2.6.0" + ], + "twitter": null + }, + "\u9ec4\u6d77": { + "committed": [], + "github": "hh-in-zhuzhou", + "reported": [ + "2.6.0" + ], + "twitter": null } } \ No newline at end of file From 7885f5cd66dd211437b05ddc36797092e6cd374b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 15 Oct 2021 15:24:21 +0200 Subject: [PATCH 0887/1182] Minor version changes in the Fedora packaging docs (#1185) --- docs/packaging/linux-fedora/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/packaging/linux-fedora/README.md b/docs/packaging/linux-fedora/README.md index ae1d035211..b21e003d25 100644 --- a/docs/packaging/linux-fedora/README.md +++ b/docs/packaging/linux-fedora/README.md @@ -42,7 +42,7 @@ Q: Are new versions backported automatically? A: No. The process is: 1. A new HTTPie release is created on Github. -2. A pull request for Fedora `rawhide` (the development version of Fedora, currently Fedora 35) is created. +2. A pull request for Fedora `rawhide` (the development version of Fedora, currently Fedora 36) is created. 3. A Fedora packager (usually Miro) sanity checks the pull request and merges, builds. HTTPie is updated in `rawhide` within 24 hours (sometimes more, for unrelated issues). -4. A Fedora packager decides whether the upgrade is suitable for stable Fedora releases (currently 34, 33), if so, merges the changes there. +4. A Fedora packager decides whether the upgrade is suitable for stable Fedora releases (currently 35, 34, 33), if so, merges the changes there. 5. (if the above is yes) The new version of HTTPie lands in `updates-testing` repo where it waits for user feedback and lands within ~1 week for broad availability. From 1b4048aefc591445d8039b6b5b191e5e899ee19a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 15 Oct 2021 15:29:06 +0200 Subject: [PATCH 0888/1182] dnf/yum update is the same as dnf upgrade -- it updates all packages (#1184) No reason to run it before installing or upgrading httpie. This is not apt. --- docs/README.md | 4 ---- docs/installation/methods.yml | 4 ---- 2 files changed, 8 deletions(-) diff --git a/docs/README.md b/docs/README.md index 77fd48cf91..7f6a7af928 100644 --- a/docs/README.md +++ b/docs/README.md @@ -190,13 +190,11 @@ $ apt upgrade httpie ```bash # Install httpie -$ dnf update $ dnf install httpie ``` ```bash # Upgrade httpie -$ dnf update $ dnf upgrade httpie ``` @@ -206,14 +204,12 @@ Also works for other RHEL-derived distributions like ClearOS, Oracle Linux, etc. ```bash # Install httpie -$ yum update $ yum install epel-release $ yum install httpie ``` ```bash # Upgrade httpie -$ yum update $ yum upgrade httpie ``` diff --git a/docs/installation/methods.yml b/docs/installation/methods.yml index 77ab986316..8cb1f708e8 100644 --- a/docs/installation/methods.yml +++ b/docs/installation/methods.yml @@ -112,10 +112,8 @@ tools: package: https://src.fedoraproject.org/rpms/httpie commands: install: - - dnf update - dnf install httpie upgrade: - - dnf update - dnf upgrade httpie emerge: @@ -247,9 +245,7 @@ tools: package: https://src.fedoraproject.org/rpms/httpie commands: install: - - yum update - yum install epel-release - yum install httpie upgrade: - - yum update - yum upgrade httpie From 7500912be172e3d7713446e75a2b57a077f1b37f Mon Sep 17 00:00:00 2001 From: hosseingt Date: Fri, 15 Oct 2021 19:31:07 +0330 Subject: [PATCH 0889/1182] Corrected command for installing development version on Windows (#1187) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7dd42c50ee..46749d16d4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -160,7 +160,7 @@ C:\> venv\Scripts\activate Install HTTPie in editable mode with all the dependencies: ```powershell -C:\> python -m pip install --upgrade -e . -r requirements-dev.txt +C:\> python -m pip install --upgrade -e .[dev] ``` You should now see `(httpie)` next to your shell prompt, and From 419427cfb60781c44b9030e84db8f8ad20802284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 19 Oct 2021 10:18:35 +0200 Subject: [PATCH 0890/1182] Update downstream files for HTTPie 2.6.0 (#1186) * Update Alpine package * Add charset-normalizer deps for Alpine It currently does not exist. We will need to add it ourselves. * Update Gentoo package * Update Brew formula * Update MacPorts port * Fix Gentoo deps * Update examples * Update Void Linux package * Update Void Linux commands * Update Chocolateur package * Review DEbian packaging details * Simplify Void Linux package * Update more packages * Update summary everywhere * Remove temporary file * Update Chocolatey package URL * Updates * Update Spack --- docs/README.md | 2 +- docs/packaging/brew/README.md | 2 +- docs/packaging/brew/httpie.rb | 32 +-- docs/packaging/linux-alpine/APKBUILD | 18 +- docs/packaging/linux-aosc/autobuild/defines | 8 + docs/packaging/linux-arch/PKGBUILD | 9 +- docs/packaging/linux-debian/README.md | 4 +- docs/packaging/linux-fedora/httpie.spec.txt | 248 ++++++++++++++++++ docs/packaging/linux-gentoo/Manifest | 1 + docs/packaging/linux-gentoo/README.md | 2 +- ...ttpie-2.5.0.ebuild => httpie-2.6.0.ebuild} | 3 +- docs/packaging/linux-void/README.md | 7 +- docs/packaging/linux-void/template | 11 +- docs/packaging/mac-ports/Portfile | 22 +- docs/packaging/mac-ports/README.md | 2 +- docs/packaging/spack/README.md | 12 +- docs/packaging/spack/package.py | 28 +- .../windows-chocolatey/httpie.nuspec | 8 +- httpie/__init__.py | 2 +- 19 files changed, 348 insertions(+), 73 deletions(-) create mode 100644 docs/packaging/linux-aosc/autobuild/defines create mode 100644 docs/packaging/linux-fedora/httpie.spec.txt rename docs/packaging/linux-gentoo/{httpie-2.5.0.ebuild => httpie-2.6.0.ebuild} (89%) diff --git a/docs/README.md b/docs/README.md index 7f6a7af928..d4e16b6d4e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1422,7 +1422,7 @@ HTTPie does several things by default in order to make its terminal output easy ### Colors and formatting Syntax highlighting is applied to HTTP headers and bodies (where it makes sense). -You can choose your preferred color scheme via the --style option if you don’t like the default one. +You can choose your preferred color scheme via the `--style` option if you don’t like the default one. There are dozens of styles available, here are just a few notable ones: | Style | Description | diff --git a/docs/packaging/brew/README.md b/docs/packaging/brew/README.md index ac5919ead6..2acb3299fb 100644 --- a/docs/packaging/brew/README.md +++ b/docs/packaging/brew/README.md @@ -26,7 +26,7 @@ git commit -s -m 'Update brew formula to XXX' That [GitHub workflow](https://github.com/httpie/httpie/actions/workflows/test-package-mac-brew.yml) will test the formula when `downstream/mac/brew/httpie.rb` is changed in a pull request. -Then, open a pull request with those changes to the [downstream file]([ file](https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb)). +Then, open a pull request with those changes to the [downstream file](https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb). ## Hacking diff --git a/docs/packaging/brew/httpie.rb b/docs/packaging/brew/httpie.rb index d10be2b97d..6a01ca2300 100644 --- a/docs/packaging/brew/httpie.rb +++ b/docs/packaging/brew/httpie.rb @@ -3,29 +3,29 @@ class Httpie < Formula desc "User-friendly cURL replacement (command-line HTTP client)" homepage "https://httpie.io/" - url "https://files.pythonhosted.org/packages/90/64/7ea8066309970f787653bdc8c5328272a5c4d06cbce3a07a6a5c3199c3d7/httpie-2.5.0.tar.gz" - sha256 "fe6a8bc50fb0635a84ebe1296a732e39357c3e1354541bf51a7057b4877e47f9" + url "https://files.pythonhosted.org/packages/53/96/cbcfec73c186f076e4443faf3d91cbbc868f18f6323703afd348b1aba46d/httpie-2.6.0.tar.gz" + sha256 "ef929317b239bbf0a5bb7159b4c5d2edbfc55f8a0bcf9cd24ce597daec2afca5" license "BSD-3-Clause" head "https://github.com/httpie/httpie.git" bottle do - sha256 cellar: :any_skip_relocation, arm64_big_sur: "01115f69aff0399b3f73af09899a42a14343638a4624a35749059cc732c49cdc" - sha256 cellar: :any_skip_relocation, big_sur: "53f07157f00edf8193b7d4f74f247f53e1796fbc3e675cd2fbaa4b9dc2bad62c" - sha256 cellar: :any_skip_relocation, catalina: "7cf216fdee98208856d654060fdcad3968623d7ed27fcdeba27d3120354c9a9f" - sha256 cellar: :any_skip_relocation, mojave: "28adb5aed8c1c2b39c51789f242ff0dffde39073e161deb379c79184d787d063" - sha256 cellar: :any_skip_relocation, x86_64_linux: "91cb8c332c643bd8b1d0a8f3ec0acd4770b407991f6de1fd320d675f2b2e95ec" + sha256 cellar: :any_skip_relocation, arm64_big_sur: "52946f8c07e853a3f4fa4e629c42f3655ba4eaba5fdf204bbc365377e65bbf85" + sha256 cellar: :any_skip_relocation, big_sur: "aa6fdb95027863739c34d53a5788f4dfb4593a6cde1a1f54e2bfb9c25d673ff3" + sha256 cellar: :any_skip_relocation, catalina: "ef2d994c88121e8059952c5716ff81246a8a0745ca2e3ed50249093d76d93f12" + sha256 cellar: :any_skip_relocation, mojave: "9ebdd4ac816cf6d1ed306e8cbef4a7442c7318bedd6b0f9d3809c8963a46a566" + sha256 cellar: :any_skip_relocation, x86_64_linux: "768b8806307683e91867df6975803597437c12966cc9fa4b7a4bda322fa3d7c0" end - depends_on "python@3.9" + depends_on "python@3.10" resource "certifi" do - url "https://files.pythonhosted.org/packages/6d/78/f8db8d57f520a54f0b8a438319c342c61c22759d8f9a1cd2e2180b5e5ea9/certifi-2021.5.30.tar.gz" - sha256 "2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee" + url "https://files.pythonhosted.org/packages/6c/ae/d26450834f0acc9e3d1f74508da6df1551ceab6c2ce0766a593362d6d57f/certifi-2021.10.8.tar.gz" + sha256 "78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872" end resource "charset-normalizer" do - url "https://files.pythonhosted.org/packages/e7/4e/2af0238001648ded297fb54ceb425ca26faa15b341b4fac5371d3938666e/charset-normalizer-2.0.4.tar.gz" - sha256 "f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3" + url "https://files.pythonhosted.org/packages/9f/c5/334c019f92c26e59637bb42bd14a190428874b2b2de75a355da394cf16c1/charset-normalizer-2.0.7.tar.gz" + sha256 "e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0" end resource "defusedxml" do @@ -34,8 +34,8 @@ class Httpie < Formula end resource "idna" do - url "https://files.pythonhosted.org/packages/cb/38/4c4d00ddfa48abe616d7e572e02a04273603db446975ab46bbcd36552005/idna-3.2.tar.gz" - sha256 "467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" + url "https://files.pythonhosted.org/packages/62/08/e3fc7c8161090f742f504f40b1bccbfc544d4a4e09eb774bf40aafce5436/idna-3.3.tar.gz" + sha256 "9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" end resource "Pygments" do @@ -59,8 +59,8 @@ class Httpie < Formula end resource "urllib3" do - url "https://files.pythonhosted.org/packages/4f/5a/597ef5911cb8919efe4d86206aa8b2658616d676a7088f0825ca08bd7cb8/urllib3-1.26.6.tar.gz" - sha256 "f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" + url "https://files.pythonhosted.org/packages/80/be/3ee43b6c5757cabea19e75b8f46eaf05a2f5144107d7db48c7cf3a864f73/urllib3-1.26.7.tar.gz" + sha256 "4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece" end def install diff --git a/docs/packaging/linux-alpine/APKBUILD b/docs/packaging/linux-alpine/APKBUILD index 9669e69b9c..17ffda2d15 100644 --- a/docs/packaging/linux-alpine/APKBUILD +++ b/docs/packaging/linux-alpine/APKBUILD @@ -3,14 +3,22 @@ # Contributor: Daniel Isaksen # Contributor: Mickaël Schoentgen pkgname=httpie -pkgver=2.5.0 +pkgver=2.6.0 pkgrel=0 -pkgdesc="CLI, cURL-like tool" +pkgdesc="Modern, user-friendly command-line HTTP client for the API era" url="https://httpie.org/" arch="noarch" license="BSD-3-Clause" -depends="python3 py3-setuptools py3-requests py3-pygments py3-requests-toolbelt py3-pysocks py3-defusedxml" -makedepends="py3-setuptools" +depends=" + python3 + py3-setuptools + py3-requests + py3-pygments + py3-requests-toolbelt + py3-pysocks + py3-defusedxml + py3-charset-normalizer + " checkdepends="py3-pytest py3-pytest-httpbin py3-responses" source="https://files.pythonhosted.org/packages/source/h/httpie/httpie-$pkgver.tar.gz" @@ -30,4 +38,4 @@ package() { python3 setup.py install --prefix=/usr --root="$pkgdir" } -sha512sums="3bfe572b03bfde87d5a02f9ba238f9493b32e587c33fd30600a4dd6a45082eedcb2b507c7f1e3e75a423cbdcc1ff0556138897dffb7888d191834994eae9a2aa httpie-2.5.0.tar.gz" +sha512sums="a38e9769c1994fcb4e5f898e5a72283c636ea155f1fc4d594eb59c43fe98115335dec4fddd6d4e396bd11b674715c573d2fc40c4afb732ba31da0cb8e2068fd2 httpie-2.6.0.tar.gz" diff --git a/docs/packaging/linux-aosc/autobuild/defines b/docs/packaging/linux-aosc/autobuild/defines new file mode 100644 index 0000000000..e59dea204c --- /dev/null +++ b/docs/packaging/linux-aosc/autobuild/defines @@ -0,0 +1,8 @@ +PKGNAME=httpie +PKGSEC=utils +PKGDEP="charset-normalizer defusedxml requests toolbelt pygments pysocks" +PKGDES="Modern, user-friendly command-line HTTP client for the API era" + +ABHOST=noarch +ABTYPE=python +NOPYTHON2=1 diff --git a/docs/packaging/linux-arch/PKGBUILD b/docs/packaging/linux-arch/PKGBUILD index 7b0b313073..d483fd67b2 100644 --- a/docs/packaging/linux-arch/PKGBUILD +++ b/docs/packaging/linux-arch/PKGBUILD @@ -4,7 +4,7 @@ # Contributor: Thomas Weißschuh pkgname=httpie -pkgver=2.5.0 +pkgver=2.6.0 pkgrel=1 pkgdesc="human-friendly CLI HTTP client for the API era" url="https://github.com/httpie/httpie" @@ -12,7 +12,8 @@ depends=('python-defusedxml' 'python-pygments' 'python-pysocks' 'python-requests' - 'python-requests-toolbelt') + 'python-requests-toolbelt' + 'python-charset-normalizer') makedepends=('python-setuptools') checkdepends=('python-pytest' 'python-pytest-httpbin' @@ -22,7 +23,7 @@ replaces=(python-httpie python2-httpie) license=('BSD') arch=('any') source=($pkgname-$pkgver.tar.gz::"https://github.com/httpie/httpie/archive/$pkgver.tar.gz") -sha256sums=('66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea') +sha256sums=('3bcd9a8cb2b11299da12d3af36c095c6d4b665e41c395898a07f1ae4d99fc14a') build() { cd $pkgname-$pkgver @@ -42,5 +43,5 @@ package() { check() { cd $pkgname-$pkgver - PYTHONDONTWRITEBYTECODE=1 python3 setup.py test + PYTHONDONTWRITEBYTECODE=1 pytest tests } diff --git a/docs/packaging/linux-debian/README.md b/docs/packaging/linux-debian/README.md index dfea5a8af1..f43ff3c40e 100644 --- a/docs/packaging/linux-debian/README.md +++ b/docs/packaging/linux-debian/README.md @@ -19,11 +19,11 @@ Open a new bug on the Debian Bug Tracking System by sending an email: - To: `Debian Bug Tracking System ` - Subject: `httpie: Version XXX available` -- Message template ([example](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=993937)): +- Message template (examples [1](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=993937), and [2](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=996479)): ```email Package: httpie - Severity: wishlist + Severity: normal ``` diff --git a/docs/packaging/linux-fedora/httpie.spec.txt b/docs/packaging/linux-fedora/httpie.spec.txt new file mode 100644 index 0000000000..8dc4e6b3df --- /dev/null +++ b/docs/packaging/linux-fedora/httpie.spec.txt @@ -0,0 +1,248 @@ +Name: httpie +Version: 2.6.0 +Release: 1%{?dist} +Summary: A Curl-like tool for humans + +License: BSD +URL: https://httpie.org/ +Source0: https://github.com/httpie/httpie/archive/%{version}/%{name}-%{version}.tar.gz + +BuildArch: noarch + +BuildRequires: python3-devel +BuildRequires: pyproject-rpm-macros + +BuildRequires: help2man + +%description +HTTPie is a CLI HTTP utility built out of frustration with existing tools. The +goal is to make CLI interaction with HTTP-based services as human-friendly as +possible. + +HTTPie does so by providing an http command that allows for issuing arbitrary +HTTP requests using a simple and natural syntax and displaying colorized +responses. + + +%prep +%autosetup -p1 + + +%generate_buildrequires +%pyproject_buildrequires -rx test + + +%build +%pyproject_wheel + + +%install +%pyproject_install +%pyproject_save_files httpie + +# Bash completion +mkdir -p %{buildroot}%{_datadir}/bash-completion/completions +cp -a extras/httpie-completion.bash %{buildroot}%{_datadir}/bash-completion/completions/http +ln -s ./http %{buildroot}%{_datadir}/bash-completion/completions/https + +# Fish completion +mkdir -p %{buildroot}%{_datadir}/fish/vendor_completions.d/ +cp -a extras/httpie-completion.fish %{buildroot}%{_datadir}/fish/vendor_completions.d/http.fish +ln -s ./http.fish %{buildroot}%{_datadir}/fish/vendor_completions.d/https.fish + + +# Generate man pages for everything +export PYTHONPATH=%{buildroot}%{python3_sitelib} +mkdir -p %{buildroot}%{_mandir}/man1 +help2man %{buildroot}%{_bindir}/http > %{buildroot}%{_mandir}/man1/http.1 +help2man %{buildroot}%{_bindir}/https > %{buildroot}%{_mandir}/man1/https.1 + + +%check +%pytest -v + + +%files -f %{pyproject_files} +%doc README.md +%license LICENSE +%{_bindir}/http +%{_bindir}/https +%{_mandir}/man1/http.1* +%{_mandir}/man1/https.1* +# we co-own the entire directory structures for bash/fish completion to avoid a dependency +%{_datadir}/bash-completion/ +%{_datadir}/fish/ + + +%changelog +* Fri Oct 15 2021 Miro Hrončok - 2.6.0-1 +- Update to 2.6.0 +- Fixes: rhbz#2014022 + +* Tue Sep 07 2021 Miro Hrončok - 2.5.0-1 +- Update to 2.5.0 +- Fixes: rhbz#2001693 + +* Thu Jul 22 2021 Fedora Release Engineering - 2.4.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + +* Fri Jun 04 2021 Python Maint - 2.4.0-3 +- Rebuilt for Python 3.10 + +* Thu May 27 2021 Miro Hrončok - 2.4.0-2 +- Add Bash and Fish completion +- Fixes rhbz#1834441 +- Run tests on build time + +* Wed Mar 24 2021 Mikel Olasagasti Uranga - 2.4.0-1 +- Update to 2.4.0 +- Use pypi_source macro + +* Tue Jan 26 2021 Fedora Release Engineering - 2.3.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Thu Jan 21 2021 Nils Philippsen - 2.3.0-2 +- use macros for Python dependencies +- add missing Python dependencies needed for running help2man +- remove manual Python dependencies +- discard stderr when running help2man + +* Thu Dec 24 2020 Nils Philippsen - 2.3.0-1 +- version 2.3.0 +- Python 2 is no more +- use %%autosetup and Python build macros +- remove EL7-isms +- explicitly require sed for building + +* Tue Jul 28 2020 Fedora Release Engineering - 1.0.3-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Tue May 26 2020 Miro Hrončok - 1.0.3-3 +- Rebuilt for Python 3.9 + +* Wed Jan 29 2020 Fedora Release Engineering - 1.0.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Mon Sep 30 2019 Rick Elrod - 1.0.3-1 +- Latest upstream + +* Mon Aug 19 2019 Miro Hrončok - 0.9.4-15 +- Rebuilt for Python 3.8 + +* Thu Jul 25 2019 Fedora Release Engineering - 0.9.4-14 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Fri Feb 01 2019 Fedora Release Engineering - 0.9.4-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Fri Jul 13 2018 Fedora Release Engineering - 0.9.4-12 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Tue Jun 19 2018 Miro Hrončok - 0.9.4-11 +- Rebuilt for Python 3.7 + +* Wed Feb 07 2018 Fedora Release Engineering - 0.9.4-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 0.9.4-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Fri Mar 10 2017 Ralph Bean - 0.9.4-8 +- Fix help2man usage with python3. + https://bugzilla.redhat.com/show_bug.cgi?id=1430733 + +* Mon Feb 27 2017 Ralph Bean - 0.9.4-7 +- Fix missing Requires. https://bugzilla.redhat.com/show_bug.cgi?id=1417730 + +* Fri Feb 10 2017 Fedora Release Engineering - 0.9.4-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Mon Jan 2 2017 Ricky Elrod - 0.9.4-5 +- Add missing Obsoletes. + +* Mon Jan 2 2017 Ricky Elrod - 0.9.4-4 +- Nuke python-version-specific subpackages. Just use py3 if we can. + +* Mon Dec 19 2016 Miro Hrončok - 0.9.4-3 +- Rebuild for Python 3.6 + +* Tue Jul 19 2016 Fedora Release Engineering - 0.9.4-2 +- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages + +* Tue Jul 05 2016 Ricky Elrod - 0.9.4-1 +- Update to latest upstream. + +* Fri Jun 03 2016 Ricky Elrod - 0.9.3-4 +- Add proper Obsoletes for rhbz#1329226. + +* Wed Feb 03 2016 Fedora Release Engineering - 0.9.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Mon Jan 04 2016 Ralph Bean - 0.9.3-2 +- Modernize python macros and subpackaging. +- Move LICENSE to %%license macro. +- Make python3 the default on modern Fedora. + +* Mon Jan 04 2016 Ralph Bean - 0.9.3-1 +- new version + +* Tue Nov 10 2015 Fedora Release Engineering - 0.9.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Changes/python3.5 + +* Wed Jun 17 2015 Fedora Release Engineering - 0.9.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Thu Mar 26 2015 Ricky Elrod - 0.9.2-1 +- Latest upstream release. + +* Sat Jun 07 2014 Fedora Release Engineering - 0.8.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Wed May 28 2014 Kalev Lember - 0.8.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Python_3.4 + +* Fri Jan 31 2014 Ricky Elrod - 0.8.0-1 +- Latest upstream release. + +* Fri Oct 4 2013 Ricky Elrod - 0.7.2-2 +- Add in patch to work without having python-requests 2.0.0. + +* Sat Sep 28 2013 Ricky Elrod - 0.7.2-1 +- Latest upstream release. + +* Thu Sep 5 2013 Ricky Elrod - 0.6.0-7 +- Only try building the manpage on Fedora, since RHEL's help2man doesn't + have the --no-discard-stderr flag. + +* Thu Sep 5 2013 Ricky Elrod - 0.6.0-6 +- Loosen the requirement on python-pygments. + +* Sat Aug 03 2013 Fedora Release Engineering - 0.6.0-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Tue Jul 2 2013 Ricky Elrod - 0.6.0-4 +- python-requests 1.2.3 exists in rawhide now. + +* Sun Jun 30 2013 Ricky Elrod - 0.6.0-3 +- Patch to use python-requests 1.1.0 for now. + +* Sat Jun 29 2013 Ricky Elrod - 0.6.0-2 +- Update to latest upstream release. + +* Mon Apr 29 2013 Ricky Elrod - 0.5.0-2 +- Fix changelog messup. + +* Mon Apr 29 2013 Ricky Elrod - 0.5.0-1 +- Update to latest upstream release. + +* Mon Apr 8 2013 Ricky Elrod - 0.4.1-3 +- Fix manpage generation by exporting PYTHONPATH. + +* Tue Mar 26 2013 Ricky Elrod - 0.4.1-2 +- Include Python3 support, and fix other review blockers. + +* Mon Mar 11 2013 Ricky Elrod - 0.4.1-1 +- Update to latest upstream release + +* Thu Jul 19 2012 Ricky Elrod - 0.2.5-1 +- Initial build. diff --git a/docs/packaging/linux-gentoo/Manifest b/docs/packaging/linux-gentoo/Manifest index 3779e5c114..e11717c653 100644 --- a/docs/packaging/linux-gentoo/Manifest +++ b/docs/packaging/linux-gentoo/Manifest @@ -1,2 +1,3 @@ DIST httpie-2.4.0.tar.gz 1772537 BLAKE2B 111451cc7dc353d5b586554f98ac715a3198f03e74d261944a5f021d2dcc948455500800222b323d182a2a067d0549bda7c318ab3a6c934b9a9beec64aff2db2 SHA512 44cc7ff4fe0f3d8c53a7dd750465f6b56c36f5bbac06d22b760579bd60949039e82313845699669a659ec91adc69dbeac22c06ddd63af64e6f2e0edecf3e732a DIST httpie-2.5.0.tar.gz 1105177 BLAKE2B 6e16868c81522d4e6d2fc0a4e093c190f18ced720b35217930865ae3f8e168193cc33dfecc13c5d310f52647d6e79d17b247f56e56e8586d633a2d9502be66a7 SHA512 f14aa23fea7578181b9bd6ededea04de9ddf0b2f697b23f76d2d96e2c17b95617318c711750bad6af550400dbc03732ab17fdf84e59d577f33f073e600a55330 +DIST httpie-2.6.0.tar.gz 1133495 BLAKE2B 3ac61fc68ab59ac7523b030a8c7af85c4af05357aa19282b514b813351efabe783f47ab82d292117e0a9170ff793b71356941dc4eb159c585629cae3adec9b5a SHA512 acd7dc847b67e27909c49ccddec84321c4d73fa5b49f06ce3d94d790093a8f168a1c6627bc4921ca8c0e48b9904f38e17935b645495e2313d16ac2eecf659038 diff --git a/docs/packaging/linux-gentoo/README.md b/docs/packaging/linux-gentoo/README.md index 35fbce7cb7..cbb12ce5db 100644 --- a/docs/packaging/linux-gentoo/README.md +++ b/docs/packaging/linux-gentoo/README.md @@ -13,7 +13,7 @@ We will discuss setting up the environment, installing development tools, instal ## Overall process -Open a pull request to create `httpie-XXX.ebuild` and update `Manifest`. +Open a pull request to create `httpie-XXX.ebuild` and update `Manifest` ([example](https://github.com/macports/macports-ports/pull/12583)). - Here is how to calculate the size and checksum (replace `2.5.0` with the correct version): diff --git a/docs/packaging/linux-gentoo/httpie-2.5.0.ebuild b/docs/packaging/linux-gentoo/httpie-2.6.0.ebuild similarity index 89% rename from docs/packaging/linux-gentoo/httpie-2.5.0.ebuild rename to docs/packaging/linux-gentoo/httpie-2.6.0.ebuild index 00420956f6..9190f742b5 100644 --- a/docs/packaging/linux-gentoo/httpie-2.5.0.ebuild +++ b/docs/packaging/linux-gentoo/httpie-2.6.0.ebuild @@ -9,7 +9,7 @@ PYTHON_REQ_USE="ssl(+)" inherit bash-completion-r1 distutils-r1 -DESCRIPTION="Modern command line HTTP client" +DESCRIPTION="Modern, user-friendly command-line HTTP client for the API era" HOMEPAGE="https://httpie.io/ https://pypi.org/project/httpie/" SRC_URI="https://github.com/httpie/httpie/archive/${PV}.tar.gz -> ${P}.tar.gz" @@ -18,6 +18,7 @@ SLOT="0" KEYWORDS="~amd64 ~x86" RDEPEND=" + dev-python/charset_normalizer[${PYTHON_USEDEP}] dev-python/defusedxml[${PYTHON_USEDEP}] dev-python/pygments[${PYTHON_USEDEP}] >=dev-python/requests-2.22.0[${PYTHON_USEDEP}] diff --git a/docs/packaging/linux-void/README.md b/docs/packaging/linux-void/README.md index 3b6c9143e1..7836851da6 100644 --- a/docs/packaging/linux-void/README.md +++ b/docs/packaging/linux-void/README.md @@ -13,8 +13,9 @@ We will discuss setting up the environment, installing development tools, instal ## Overall process -Open a pull request to update the [downstream file](https://github.com/void-linux/void-packages/blob/master/srcpkgs/httpie/template) ([example](https://github.com/void-linux/void-packages/pull/32905)). +Open a pull request to update the [downstream file](https://github.com/void-linux/void-packages/blob/master/srcpkgs/httpie/template) ([example](https://github.com/void-linux/void-packages/pull/33539)). +- The `revision` must be set to `0`. - The commit message must be `httpie: update to XXX.`. - The commit must be signed-off (`git commit -s`). @@ -50,6 +51,10 @@ xlint srcpkgs/httpie/template ln -s / masterdir # Enable ethereal chroot-style +echo XBPS_BUILD_ENVIRONMENT=void-packages-ci >> etc/conf +echo XBPS_ALLOW_RESTRICTED=yes >> etc/conf +echo XBPS_CHROOT_CMD=ethereal >> etc/conf +echo XBPS_ALLOW_CHROOT_BREAKOUT=yes >> etc/conf export XBPS_ALLOW_CHROOT_BREAKOUT=yes ./xbps-src binary-bootstrap ./xbps-src chroot diff --git a/docs/packaging/linux-void/template b/docs/packaging/linux-void/template index 1a9a418a42..86a86bfde0 100644 --- a/docs/packaging/linux-void/template +++ b/docs/packaging/linux-void/template @@ -1,18 +1,19 @@ # Template file for 'httpie' pkgname=httpie -version=2.5.0 +version=2.6.0 revision=1 build_style=python3-module hostmakedepends="python3-setuptools" depends="python3-setuptools python3-requests python3-requests-toolbelt - python3-Pygments python3-pysocks python3-defusedxml" -short_desc="Human-friendly command line HTTP client" + python3-Pygments python3-pysocks python3-defusedxml + python3-charset-normalizer" +short_desc="Modern, user-friendly command-line HTTP client for the API era" maintainer="Mickaël Schoentgen " license="BSD-3-Clause" homepage="https://httpie.io/" -changelog="https://raw.githubusercontent.com/httpie/httpie/${version}/CHANGELOG.md" +changelog="https://raw.githubusercontent.com/httpie/httpie/master/CHANGELOG.md" distfiles="https://github.com/httpie/httpie/archive/${version}.tar.gz" -checksum=66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea +checksum=3bcd9a8cb2b11299da12d3af36c095c6d4b665e41c395898a07f1ae4d99fc14a make_check=no # needs pytest_httpbin which is not packaged post_install() { diff --git a/docs/packaging/mac-ports/Portfile b/docs/packaging/mac-ports/Portfile index 3f6218e963..26c91d820e 100644 --- a/docs/packaging/mac-ports/Portfile +++ b/docs/packaging/mac-ports/Portfile @@ -4,11 +4,11 @@ PortSystem 1.0 PortGroup github 1.0 PortGroup python 1.0 -github.setup httpie httpie 2.5.0 +github.setup httpie httpie 2.6.0 maintainers {g5pw @g5pw} openmaintainer categories net -description HTTPie is a command line HTTP client, a user-friendly cURL replacement. +description Modern, user-friendly command-line HTTP client for the API era long_description HTTPie (pronounced aych-tee-tee-pie) is a command line HTTP \ client. Its goal is to make CLI interaction with web \ services as human-friendly as possible. It provides a simple \ @@ -20,10 +20,11 @@ platforms darwin license BSD homepage https://httpie.io/ -variant python36 conflicts python37 python38 python39 description "Use Python 3.6" {} -variant python37 conflicts python36 python38 python39 description "Use Python 3.7" {} -variant python38 conflicts python36 python37 python39 description "Use Python 3.8" {} -variant python39 conflicts python36 python37 python38 description "Use Python 3.9" {} +variant python36 conflicts python37 python38 python39 python310 description "Use Python 3.6" {} +variant python37 conflicts python36 python38 python39 python310 description "Use Python 3.7" {} +variant python38 conflicts python36 python37 python39 python310 description "Use Python 3.8" {} +variant python39 conflicts python36 python37 python38 python310 description "Use Python 3.9" {} +variant python310 conflicts python36 python37 python38 python39 description "Use Python 3.10" {} if {[variant_isset python36]} { python.default_version 36 @@ -31,6 +32,8 @@ if {[variant_isset python36]} { python.default_version 37 } elseif {[variant_isset python39]} { python.default_version 39 +} elseif {[variant_isset python310]} { + python.default_version 310 } else { default_variants +python38 python.default_version 38 @@ -40,10 +43,11 @@ depends_lib-append port:py${python.version}-requests \ port:py${python.version}-requests-toolbelt \ port:py${python.version}-pygments \ port:py${python.version}-socks \ + port:py${python.version}-charset-normalizer \ port:py${python.version}-defusedxml -checksums rmd160 88d227d52199c232c0ddf704a219d1781b1e77ee \ - sha256 00c4b7bbe7f65abe1473f37b39d9d9f8f53f44069a430ad143a404c01c2179fc \ - size 1105185 +checksums rmd160 07b1d1592da1c505ed3ee4ef3b6056215e16e9ff \ + sha256 63cf104bf3552305c68a74f16494a90172b15296610a875e17918e5e36373c0b \ + size 1133491 python.link_binaries_suffix diff --git a/docs/packaging/mac-ports/README.md b/docs/packaging/mac-ports/README.md index aa7ce3b2c2..2d8170afa4 100644 --- a/docs/packaging/mac-ports/README.md +++ b/docs/packaging/mac-ports/README.md @@ -13,7 +13,7 @@ We will discuss setting up the environment, installing development tools, instal ## Overall process -Open a pull request to update the [downstream file](https://github.com/macports/macports-ports/blob/master/net/httpie/Portfile) ([example](https://github.com/macports/macports-ports/pull/12167)). +Open a pull request to update the [downstream file](https://github.com/macports/macports-ports/blob/master/net/httpie/Portfile) ([example](https://github.com/macports/macports-ports/pull/12583)). - Here is how to calculate the size and checksums (replace `2.5.0` with the correct version): diff --git a/docs/packaging/spack/README.md b/docs/packaging/spack/README.md index dc20604a8a..ccd05977b5 100644 --- a/docs/packaging/spack/README.md +++ b/docs/packaging/spack/README.md @@ -30,20 +30,16 @@ docker run -it --rm spack/centos7 From inside the container: ```bash -# Clone -git clone --depth=1 https://github.com/spack/spack.git -cd spack - # Retrieve the patch of the latest HTTPie version curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/spack/package.py \ - -o var/spack/repos/builtin/packages/httpie/package.py - -# Check the package -spack spec httpie + -o /opt/spack/var/spack/repos/builtin/packages/httpie/package.py # Check available versions (it should show the new version) spack versions httpie +# Check the package +spack spec httpie@XXX + # Install the package spack install httpie@XXX spack load httpie diff --git a/docs/packaging/spack/package.py b/docs/packaging/spack/package.py index b94c0bd61a..af5dffc169 100644 --- a/docs/packaging/spack/package.py +++ b/docs/packaging/spack/package.py @@ -7,24 +7,26 @@ class Httpie(PythonPackage): - """Modern command line HTTP client.""" + """Modern, user-friendly command-line HTTP client for the API era.""" - homepage = "https://httpie.io/" - pypi = "httpie/httpie-2.5.0.tar.gz" + homepage = 'https://httpie.io/' + pypi = 'httpie/httpie-2.6.0.tar.gz' + maintainers = ['BoboTiG'] + version('2.6.0', sha256='ef929317b239bbf0a5bb7159b4c5d2edbfc55f8a0bcf9cd24ce597daec2afca5') version('2.5.0', sha256='fe6a8bc50fb0635a84ebe1296a732e39357c3e1354541bf51a7057b4877e47f9') - version('0.9.9', sha256='f1202e6fa60367e2265284a53f35bfa5917119592c2ab08277efc7fffd744fcb') - version('0.9.8', sha256='515870b15231530f56fe2164190581748e8799b66ef0fe36ec9da3396f0df6e1') - - variant('socks', default=True, - description='Enable SOCKS proxy support') + version('0.9.9', sha256='f1202e6fa60367e2265284a53f35bfa5917119592c2ab08277efc7fffd744fcb', deprecated=True) + version('0.9.8', sha256='515870b15231530f56fe2164190581748e8799b66ef0fe36ec9da3396f0df6e1', deprecated=True) + depends_on('python@3.6:', when='@2.5:', type=('build', 'run')) depends_on('py-setuptools', type=('build', 'run')) - depends_on('py-defusedxml', type=('build', 'run')) - depends_on('py-pygments', type=('build', 'run')) - depends_on('py-requests', type=('build', 'run')) - depends_on('py-requests-toolbelt', type=('build', 'run')) - depends_on('py-pysocks', type=('build', 'run'), when="+socks") + depends_on('py-charset-normalizer@2:', when='@2.6:', type=('build', 'run')) + depends_on('py-defusedxml@0.6:', when='@2.5:', type=('build', 'run')) + depends_on('py-pygments@2.1.3:', type=('build', 'run')) + depends_on('py-pygments@2.5.2:', when='@2.5:', type=('build', 'run')) + depends_on('py-requests@2.11:', type=('build', 'run')) + depends_on('py-requests@2.22:+socks', when='@2.5:', type=('build', 'run')) + depends_on('py-requests-toolbelt@0.9.1:', when='@2.5:', type=('build', 'run')) # Concretization problem breaks this. Unconditional for now... # https://github.com/spack/spack/issues/3628 # depends_on('py-argparse@1.2.1:', type=('build', 'run'), diff --git a/docs/packaging/windows-chocolatey/httpie.nuspec b/docs/packaging/windows-chocolatey/httpie.nuspec index 39e4810d76..48c021464d 100644 --- a/docs/packaging/windows-chocolatey/httpie.nuspec +++ b/docs/packaging/windows-chocolatey/httpie.nuspec @@ -2,8 +2,8 @@ httpie - 2.5.0 - Modern, user-friendly command-line HTTP client for the API era. + 2.6.0 + Modern, user-friendly command-line HTTP client for the API era HTTPie *aitch-tee-tee-pie* is a user-friendly command-line HTTP client for the API era. It comes with JSON support, syntax highlighting, persistent sessions, wget-like downloads, plugins, and more. @@ -33,10 +33,10 @@ Main features: https://raw.githubusercontent.com/httpie/httpie/master/LICENSE https://pie-assets.s3.eu-central-1.amazonaws.com/LogoIcons/GB.png false - See the [changelog](https://github.com/httpie/httpie/blob/2.5.0/CHANGELOG.md). + See the [changelog](https://github.com/httpie/httpie/blob/2.6.0/CHANGELOG.md). httpie http https rest api client curl python ssl cli foss oss url https://httpie.io - https://github.com/httpie/httpie + https://github.com/httpie/httpie/tree/master/docs/packaging/windows-chocolatey https://github.com/httpie/httpie https://httpie.io/docs https://github.com/httpie/httpie/issues diff --git a/httpie/__init__.py b/httpie/__init__.py index b5b0447ca2..1ca8eba575 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -1,5 +1,5 @@ """ -HTTPie: command-line HTTP client for the API era. +HTTPie: modern, user-friendly command-line HTTP client for the API era. """ From 021eb651e06e1559cf83c0149c8c653b84645bf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 19 Oct 2021 10:21:45 +0200 Subject: [PATCH 0891/1182] Bump the version to 2.7.0.dev0 (#1188) --- CHANGELOG.md | 2 ++ docs/README.md | 2 +- httpie/__init__.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a217cad52..35b54e9b4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). +## [2.7.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) + ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) diff --git a/docs/README.md b/docs/README.md index d4e16b6d4e..688075fe4d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -330,7 +330,7 @@ Verify that now you have the [current development version identifier](https://gi ```bash $ http --version -# 2.6.0 +# 2.7.0.dev0 ``` ## Usage diff --git a/httpie/__init__.py b/httpie/__init__.py index 1ca8eba575..a9e24edf40 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '2.6.0' +__version__ = '2.7.0.dev0' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 3abc76f6d5f3f0d47c899b867af7c4cf213566e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 19 Oct 2021 10:24:01 +0200 Subject: [PATCH 0892/1182] Tiny docstring clean-up --- httpie/cli/argtypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index b5069b036b..0ed564804f 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -62,7 +62,7 @@ def __init__(self, *separators: str): self.special_characters.update(separator) def __call__(self, s: str) -> KeyValueArg: - """Parse raw string arg and return `self.key_value_class` instance. + """Parse raw string arg and return `self.key_value_class` instance. The best of `self.separators` is determined (first found, longest). Back slash escaped characters aren't considered as separators From 2be43e698aa9b71df905c574327ad3a7659a42cc Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 24 Oct 2021 19:44:02 +0200 Subject: [PATCH 0893/1182] Add HTTPie 2.6.0 blog post link https://httpie.io/blog/httpie-2.6.0 --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35b54e9b4c..d5ae7f12cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) +[What’s new in HTTPie 2.6.0 →](https://httpie.io/blog/httpie-2.6.0) + - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) - Added charset auto-detection when `Content-Type` doesn’t include it. ([#1110](https://github.com/httpie/httpie/issues/1110), [#1168](https://github.com/httpie/httpie/issues/1168)) - Added `--response-charset` to allow overriding the response encoding for terminal display purposes. ([#1168](https://github.com/httpie/httpie/issues/1168)) @@ -17,7 +19,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06) -Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0) +[What’s new in HTTPie 2.5.0 →](https://httpie.io/blog/httpie-2.5.0) - Added `--raw` to allow specifying the raw request body without extra processing as an alternative to `stdin`. ([#534](https://github.com/httpie/httpie/issues/534)) @@ -27,6 +29,7 @@ Blog post: [What’s new in HTTPie 2.5.0](https://httpie.io/blog/httpie-2.5.0) - Fixed `--verbose` HTTP 307 redirects with streamed request body. ([#1088](https://github.com/httpie/httpie/issues/1088)) - Fixed handling of session files with `Cookie:` followed by other headers. ([#1126](https://github.com/httpie/httpie/issues/1126)) + ## [2.4.0](https://github.com/httpie/httpie/compare/2.3.0...2.4.0) (2021-02-06) - Added support for `--session` cookie expiration based on `Set-Cookie: max-age=`. ([#1029](https://github.com/httpie/httpie/issues/1029)) From 7775422afb16d376b4e858e5ddfb0ae79a8767ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 25 Oct 2021 14:54:59 +0200 Subject: [PATCH 0894/1182] Add contributors list update to the release process --- docs/packaging/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/packaging/README.md b/docs/packaging/README.md index 40099faaae..6654789c58 100644 --- a/docs/packaging/README.md +++ b/docs/packaging/README.md @@ -24,6 +24,7 @@ That is done quite easily by manually triggering the [release workflow](https:// ## Then, company-specific tasks - Blank the `master_and_released_docs_differ_after` value in [config.json](https://github.com/httpie/httpie/blob/master/docs/config.json). +- Update the [contributors list](../contributors). - Update the HTTPie version bundled into [Termible](https://termible.io/) ([example](https://github.com/httpie/termible/pull/1)). ## Finally, spread dowstream From 5dc4a262771e616458feeaa9bf4ca8568736761a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 25 Oct 2021 14:55:45 +0200 Subject: [PATCH 0895/1182] Remove myself from the HTTPie team --- docs/contributors/generate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/contributors/generate.py b/docs/contributors/generate.py index 78682f7d87..d3d6fdd95c 100644 --- a/docs/contributors/generate.py +++ b/docs/contributors/generate.py @@ -9,7 +9,6 @@ TPL_FILE = HERE / 'snippet.jinja2' HTTPIE_TEAM = { - 'BoboTiG', 'claudiatd', 'jakubroztocil', 'jkbr', From 7985cf60c82b621c39bfa41aff1d94f22851fb26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 25 Oct 2021 16:15:27 +0200 Subject: [PATCH 0896/1182] Fix Gentoo example link --- docs/packaging/linux-gentoo/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/packaging/linux-gentoo/README.md b/docs/packaging/linux-gentoo/README.md index cbb12ce5db..d49a25e892 100644 --- a/docs/packaging/linux-gentoo/README.md +++ b/docs/packaging/linux-gentoo/README.md @@ -13,7 +13,7 @@ We will discuss setting up the environment, installing development tools, instal ## Overall process -Open a pull request to create `httpie-XXX.ebuild` and update `Manifest` ([example](https://github.com/macports/macports-ports/pull/12583)). +Open a pull request to create `httpie-XXX.ebuild` and update `Manifest` ([example](https://github.com/gentoo/gentoo/pull/22576)). - Here is how to calculate the size and checksum (replace `2.5.0` with the correct version): From a9b8513f623b4b2d794c597737d0d1a56b029cf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 25 Oct 2021 16:16:26 +0200 Subject: [PATCH 0897/1182] Update Gentoo metadata --- docs/packaging/linux-gentoo/metadata.xml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/docs/packaging/linux-gentoo/metadata.xml b/docs/packaging/linux-gentoo/metadata.xml index 4bfbb6afe5..cba10e14d2 100644 --- a/docs/packaging/linux-gentoo/metadata.xml +++ b/docs/packaging/linux-gentoo/metadata.xml @@ -1,14 +1,7 @@ - - mickael@apible.io - Mickaël Schoentgen - - - proxy-maint@gentoo.org - Proxy Maintainers - + HTTPie (pronounced aitch-tee-tee-pie) is a command line HTTP client. Its goal is to make CLI interaction with web services as From 19e48ba901e1921a9ca27852c250f040fa14a7bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 25 Oct 2021 16:19:49 +0200 Subject: [PATCH 0898/1182] Update Spack metadata --- docs/packaging/spack/package.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/packaging/spack/package.py b/docs/packaging/spack/package.py index af5dffc169..7ac511563a 100644 --- a/docs/packaging/spack/package.py +++ b/docs/packaging/spack/package.py @@ -11,10 +11,11 @@ class Httpie(PythonPackage): homepage = 'https://httpie.io/' pypi = 'httpie/httpie-2.6.0.tar.gz' - maintainers = ['BoboTiG'] + maintainers = ['jakubroztocil'] version('2.6.0', sha256='ef929317b239bbf0a5bb7159b4c5d2edbfc55f8a0bcf9cd24ce597daec2afca5') version('2.5.0', sha256='fe6a8bc50fb0635a84ebe1296a732e39357c3e1354541bf51a7057b4877e47f9') + # TODO: Remove both versions for HTTPie 2.7.0. version('0.9.9', sha256='f1202e6fa60367e2265284a53f35bfa5917119592c2ab08277efc7fffd744fcb', deprecated=True) version('0.9.8', sha256='515870b15231530f56fe2164190581748e8799b66ef0fe36ec9da3396f0df6e1', deprecated=True) @@ -27,6 +28,7 @@ class Httpie(PythonPackage): depends_on('py-requests@2.11:', type=('build', 'run')) depends_on('py-requests@2.22:+socks', when='@2.5:', type=('build', 'run')) depends_on('py-requests-toolbelt@0.9.1:', when='@2.5:', type=('build', 'run')) + # TODO: Remove completely py-argparse for HTTPie 2.7.0. # Concretization problem breaks this. Unconditional for now... # https://github.com/spack/spack/issues/3628 # depends_on('py-argparse@1.2.1:', type=('build', 'run'), From e75e0a0565f2bbf4db6e9b4ac6719abc7435ba94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 25 Oct 2021 16:25:59 +0200 Subject: [PATCH 0899/1182] Change Void Linux maintainer --- docs/packaging/linux-void/template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/packaging/linux-void/template b/docs/packaging/linux-void/template index 86a86bfde0..c4a64ff89e 100644 --- a/docs/packaging/linux-void/template +++ b/docs/packaging/linux-void/template @@ -8,7 +8,7 @@ depends="python3-setuptools python3-requests python3-requests-toolbelt python3-Pygments python3-pysocks python3-defusedxml python3-charset-normalizer" short_desc="Modern, user-friendly command-line HTTP client for the API era" -maintainer="Mickaël Schoentgen " +maintainer="Jakub Roztocil " license="BSD-3-Clause" homepage="https://httpie.io/" changelog="https://raw.githubusercontent.com/httpie/httpie/master/CHANGELOG.md" From cff45276b56d7acb3ba7ef1a34a4f715b8368284 Mon Sep 17 00:00:00 2001 From: Gaurav Date: Mon, 25 Oct 2021 20:06:34 +0530 Subject: [PATCH 0900/1182] Fix Snap autocompletion (#1189) --- extras/httpie-completion.bash | 2 +- snapcraft.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extras/httpie-completion.bash b/extras/httpie-completion.bash index 76af2debcf..6abbc2176a 100644 --- a/extras/httpie-completion.bash +++ b/extras/httpie-completion.bash @@ -7,7 +7,7 @@ _http_complete() { fi } -complete -o default -F _http_complete http +complete -o default -F _http_complete http httpie.http httpie.https https _http_complete_options() { local cur_word=$1 diff --git a/snapcraft.yaml b/snapcraft.yaml index 0b9b07d85a..ce4fe79bbb 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -81,7 +81,7 @@ parts: python -m compileall -f $packages echo "Copying extra files ..." - cp $SNAPCRAFT_PART_SRC/extras/httpie-completion.bash $SNAPCRAFT_PRIME/bin/ + cp $SNAPCRAFT_PART_SRC/extras/httpie-completion.bash $SNAPCRAFT_PRIME/ plugs: dot-config-httpie: @@ -102,13 +102,13 @@ apps: - home - network - removable-media - completer: bin/httpie-completion.bash + completer: httpie-completion.bash environment: LC_ALL: C.UTF-8 https: command: bin/https plugs: *plugs - completer: bin/httpie-completion.bash + completer: httpie-completion.bash environment: LC_ALL: C.UTF-8 From 0d9c8b88b3c2480a03e3e73ebebf5fc88b8e764d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Mon, 25 Oct 2021 17:18:53 +0200 Subject: [PATCH 0901/1182] Change Chocolatey owner --- docs/packaging/windows-chocolatey/httpie.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/packaging/windows-chocolatey/httpie.nuspec b/docs/packaging/windows-chocolatey/httpie.nuspec index 48c021464d..e43b71ee32 100644 --- a/docs/packaging/windows-chocolatey/httpie.nuspec +++ b/docs/packaging/windows-chocolatey/httpie.nuspec @@ -28,7 +28,7 @@ Main features: HTTPie HTTPie - Tiger-222 + jakubroztocil 2012-2021 Jakub Roztocil https://raw.githubusercontent.com/httpie/httpie/master/LICENSE https://pie-assets.s3.eu-central-1.amazonaws.com/LogoIcons/GB.png From d40f06687f8cbbd22bf7dba05bee93aea11a169f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 29 Oct 2021 11:33:46 +0200 Subject: [PATCH 0902/1182] Update README.md --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 688075fe4d..494e7131f2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1913,7 +1913,7 @@ HTTPie has the following community channels: - [GitHub Issues](https://github.com/httpie/httpie/issues) for bug reports and feature requests - [Discord server](https://httpie.io/discord) to ask questions, discuss features, and for general API development discussion - [StackOverflow](https://stackoverflow.com) to ask questions (make sure to use the [httpie](https://stackoverflow.com/questions/tagged/httpie) tag) -- Twitter; where you can tweet directly to (and follow!) [@httpie](https://twitter.com/httpie) + ### Related projects From 7cdd74fece577cea09c0709455f494dbe0c323b3 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Sun, 31 Oct 2021 15:04:39 +0100 Subject: [PATCH 0903/1182] Support multiple headers sharing the same name (#1190) * Support multiple headers sharing the same name * Apply suggestions * Don't normalize HTTP header names * apply visual suggestions Co-authored-by: Jakub Roztocil * bump down multidict to 4.7.0 Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 2 + docs/README.md | 33 +++++++++++++++ httpie/cli/dicts.py | 32 +++++++++++++-- httpie/cli/requestitems.py | 10 +++-- httpie/client.py | 33 ++++++++++++++- httpie/models.py | 2 +- setup.py | 1 + tests/test_cli.py | 8 ++-- tests/test_httpie.py | 82 ++++++++++++++++++++++++++++++++++++++ tests/test_redirects.py | 11 +++++ tests/test_sessions.py | 18 +++++++++ 11 files changed, 220 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5ae7f12cc..6d2a73c945 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.7.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) +- Added support for sending multiple HTTP headers with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) + ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) [What’s new in HTTPie 2.6.0 →](https://httpie.io/blog/httpie-2.6.0) diff --git a/docs/README.md b/docs/README.md index 494e7131f2..ff6fbad163 100644 --- a/docs/README.md +++ b/docs/README.md @@ -869,6 +869,39 @@ To send a header with an empty value, use `Header;`, with a semicolon: $ http pie.dev/headers 'Header;' ``` +Please note that some internal headers, such as `Content-Length`, can't be unset if +they are automatically added by the client itself. + +### Multiple header values with the same name + +If the request is sent with multiple headers that are sharing the same name, then +the HTTPie will send them individually. + +```bash +http --offline example.org Cookie:one Cookie:two +``` + +```http +GET / HTTP/1.1 +Cookie: one +Cookie: two +``` + +It is also possible to pass a single header value pair, where the value is a comma +separated list of header values. Then the client will send it as a single header. + +```bash +http --offline example.org Numbers:one,two +``` + +```http +GET / HTTP/1.1 +Numbers: one,two +``` + +Also be aware that if the current session contains any headers they will get overwriten +by individual commands when sending a request instead of being joined together. + ### Limiting response headers The `--max-headers=n` options allows you to control the number of headers HTTPie reads before giving up (the default `0`, i.e., there’s no limit). diff --git a/httpie/cli/dicts.py b/httpie/cli/dicts.py index 84178236b0..43a624eeea 100644 --- a/httpie/cli/dicts.py +++ b/httpie/cli/dicts.py @@ -1,14 +1,40 @@ from collections import OrderedDict -from requests.structures import CaseInsensitiveDict +from multidict import MultiDict, CIMultiDict -class RequestHeadersDict(CaseInsensitiveDict): +class BaseMultiDict(MultiDict): """ - Headers are case-insensitive and multiple values are currently not supported. + Base class for all MultiDicts. + """ + +class RequestHeadersDict(CIMultiDict, BaseMultiDict): + """ + Headers are case-insensitive and multiple values are supported + through the `add()` API. """ + def add(self, key, value): + """ + Add or update a new header. + + If the given `value` is `None`, then all the previous + values will be overwritten and the value will be set + to `None`. + """ + if value is None: + self[key] = value + return None + + # If the previous value for the given header is `None` + # then discard it since we are explicitly giving a new + # value for it. + if key in self and self.getone(key) is None: + self.popone(key) + + super().add(key, value) + class RequestJSONDataDict(OrderedDict): pass diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index 1dd6594ccd..73d5e4d0a2 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -10,8 +10,8 @@ SEPARATOR_QUERY_PARAM, ) from .dicts import ( - MultipartRequestDataDict, RequestDataDict, RequestFilesDict, - RequestHeadersDict, RequestJSONDataDict, + BaseMultiDict, MultipartRequestDataDict, RequestDataDict, + RequestFilesDict, RequestHeadersDict, RequestJSONDataDict, RequestQueryParamsDict, ) from .exceptions import ParseError @@ -73,11 +73,15 @@ def from_args( for arg in request_item_args: processor_func, target_dict = rules[arg.sep] value = processor_func(arg) - target_dict[arg.key] = value if arg.sep in SEPARATORS_GROUP_MULTIPART: instance.multipart_data[arg.key] = value + if isinstance(target_dict, BaseMultiDict): + target_dict.add(arg.key, value) + else: + target_dict[arg.key] = value + return instance diff --git a/httpie/client.py b/httpie/client.py index 5feaf48301..45b4327651 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -79,6 +79,7 @@ def collect_messages( request = requests.Request(**request_kwargs) prepared_request = requests_session.prepare_request(request) + apply_missing_repeated_headers(prepared_request, request.headers) if args.path_as_is: prepared_request.url = ensure_path_as_is( orig_url=args.url, @@ -190,10 +191,40 @@ def finalize_headers(headers: RequestHeadersDict) -> RequestHeadersDict: if isinstance(value, str): # See value = value.encode() - final_headers[name] = value + final_headers.add(name, value) return final_headers +def apply_missing_repeated_headers( + prepared_request: requests.PreparedRequest, + original_headers: RequestHeadersDict +) -> None: + """Update the given `prepared_request`'s headers with the original + ones. This allows the requests to be prepared as usual, and then later + merged with headers that are specified multiple times.""" + + new_headers = RequestHeadersDict(prepared_request.headers) + for prepared_name, prepared_value in prepared_request.headers.items(): + if prepared_name not in original_headers: + continue + + original_keys, original_values = zip(*filter( + lambda item: item[0].casefold() == prepared_name.casefold(), + original_headers.items() + )) + + if prepared_value not in original_values: + # If the current value is not among the initial values + # set for this field, then it means that this field got + # overridden on the way, and we should preserve it. + continue + + new_headers.popone(prepared_name) + new_headers.update(zip(original_keys, original_values)) + + prepared_request.headers = new_headers + + def make_default_headers(args: argparse.Namespace) -> RequestHeadersDict: default_headers = RequestHeadersDict({ 'User-Agent': DEFAULT_UA diff --git a/httpie/models.py b/httpie/models.py index c554dca97b..9c72518aaf 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -96,7 +96,7 @@ def headers(self): query=f'?{url.query}' if url.query else '' ) - headers = dict(self._orig.headers) + headers = self._orig.headers.copy() if 'Host' not in self._orig.headers: headers['Host'] = url.netloc.split('@')[-1] diff --git a/setup.py b/setup.py index ee6a4f4133..1238bfd31b 100644 --- a/setup.py +++ b/setup.py @@ -33,6 +33,7 @@ 'requests[socks]>=2.22.0', 'Pygments>=2.5.2', 'requests-toolbelt>=0.9.1', + 'multidict>=4.7.0', 'setuptools', ] install_requires_win_only = [ diff --git a/tests/test_cli.py b/tests/test_cli.py index 4562deb6ca..e0f5214798 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -39,8 +39,8 @@ def test_escape_separator(self): # files self.key_value_arg(fr'bar\@baz@{FILE_PATH_ARG}'), ]) - # `requests.structures.CaseInsensitiveDict` => `dict` - headers = dict(items.headers._store.values()) + # `RequestHeadersDict` => `dict` + headers = dict(items.headers) assert headers == { 'foo:bar': 'baz', @@ -88,8 +88,8 @@ def test_valid_items(self): ]) # Parsed headers - # `requests.structures.CaseInsensitiveDict` => `dict` - headers = dict(items.headers._store.values()) + # `RequestHeadersDict` => `dict` + headers = dict(items.headers) assert headers == { 'Header': 'value', 'Unset-Header': None, diff --git a/tests/test_httpie.py b/tests/test_httpie.py index a6cda1c393..748e876943 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -209,6 +209,88 @@ def test_headers_empty_value_with_value_gives_error(httpbin): http('GET', httpbin + '/headers', 'Accept;SYNTAX_ERROR') +def test_headers_omit(httpbin_both): + r = http('GET', httpbin_both + '/headers', 'Accept:') + assert 'Accept' not in r.json['headers'] + + +def test_headers_multiple_omit(httpbin_both): + r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Bar:baz', + 'Foo:', 'Baz:quux') + assert 'Foo' not in r.json['headers'] + assert r.json['headers']['Bar'] == 'baz' + assert r.json['headers']['Baz'] == 'quux' + + +def test_headers_same_after_omit(httpbin_both): + r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Foo:', + 'Foo:quux') + assert r.json['headers']['Foo'] == 'quux' + + +def test_headers_fully_omit(httpbin_both): + r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Foo:baz', + 'Foo:') + assert 'Foo' not in r.json['headers'] + + +def test_headers_multiple_values(httpbin_both): + r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Foo:baz') + assert r.json['headers']['Foo'] == 'bar,baz' + + +def test_headers_multiple_values_repeated(httpbin_both): + r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Foo:baz', + 'Foo:bar') + assert r.json['headers']['Foo'] == 'bar,baz,bar' + + +@pytest.mark.parametrize("headers, expected", [ + ( + ["Foo;", "Foo:bar"], + ",bar" + ), + ( + ["Foo:bar", "Foo;"], + "bar," + ), + ( + ["Foo:bar", "Foo;", "Foo:baz"], + "bar,,baz" + ), +]) +def test_headers_multiple_values_with_empty(httpbin_both, headers, expected): + r = http('GET', httpbin_both + '/headers', *headers) + assert r.json['headers']['Foo'] == expected + + +def test_headers_multiple_values_mixed(httpbin_both): + r = http('GET', httpbin_both + '/headers', 'Foo:bar', 'Vary:XXX', + 'Foo:baz', 'Vary:YYY', 'Foo:quux') + assert r.json['headers']['Vary'] == 'XXX,YYY' + assert r.json['headers']['Foo'] == 'bar,baz,quux' + + +def test_headers_preserve_prepared_headers(httpbin_both): + r = http('POST', httpbin_both + '/post', 'Content-Length:0', + '--raw', 'foo') + assert r.json['headers']['Content-Length'] == '3' + + +@pytest.mark.parametrize('pretty', ['format', 'none']) +def test_headers_multiple_headers_representation(httpbin_both, pretty): + r = http('--offline', '--pretty', pretty, 'example.org', + 'A:A', 'A:B', 'A:C', 'B:A', 'B:B', 'C:C', 'c:c') + + assert 'A: A' in r + assert 'A: B' in r + assert 'A: C' in r + assert 'B: A' in r + assert 'B: B' in r + assert 'C: C' in r + assert 'c: c' in r + + def test_json_input_preserve_order(httpbin_both): r = http('PATCH', httpbin_both + '/patch', 'order:={"map":{"1":"first","2":"second"}}') diff --git a/tests/test_redirects.py b/tests/test_redirects.py index 9aa6e1ced9..81dcb2befd 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -73,12 +73,17 @@ def test_follow_redirect_with_repost(httpbin, status_code): r = http( '--follow', httpbin.url + '/redirect-to', + 'A:A', + 'A:B', + 'B:B', f'url=={httpbin.url}/post', f'status_code=={status_code}', '@' + FILE_PATH_ARG, ) assert HTTP_OK in r assert FILE_CONTENT in r + assert r.json['headers']['A'] == 'A,B' + assert r.json['headers']['B'] == 'B' @pytest.mark.skipif(is_windows, reason='occasionally fails w/ ConnectionError for no apparent reason') @@ -88,11 +93,17 @@ def test_verbose_follow_redirect_with_repost(httpbin, status_code): '--follow', '--verbose', httpbin.url + '/redirect-to', + 'A:A', + 'A:B', + 'B:B', f'url=={httpbin.url}/post', f'status_code=={status_code}', '@' + FILE_PATH_ARG, ) assert f'HTTP/1.1 {status_code}' in r + assert 'A: A' in r + assert 'A: B' in r + assert 'B: B' in r assert r.count('POST /redirect-to') == 1 assert r.count('POST /post') == 1 assert r.count(FILE_CONTENT) == 3 # two requests + final response contain it diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 7f6af2eaf1..5615c08f05 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -143,6 +143,24 @@ def test_session_read_only(self, httpbin): # Should be the same as before r3. assert r2.json == r4.json + def test_session_overwrite_header(self, httpbin): + self.start_session(httpbin) + + r2 = http('--session=test', 'GET', httpbin.url + '/get', + 'Hello:World2', env=self.env()) + assert HTTP_OK in r2 + assert r2.json['headers']['Hello'] == 'World2' + + r3 = http('--session=test', 'GET', httpbin.url + '/get', + 'Hello:World2', 'Hello:World3', env=self.env()) + assert HTTP_OK in r3 + assert r3.json['headers']['Hello'] == 'World2,World3' + + r3 = http('--session=test', 'GET', httpbin.url + '/get', + 'Hello:', 'Hello:World3', env=self.env()) + assert HTTP_OK in r3 + assert 'Hello' not in r3.json['headers']['Hello'] + class TestSession(SessionTestBase): """Stand-alone session tests.""" From 72735d9d59e530110af92d64b4f3150e7ae497a9 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 3 Nov 2021 12:50:07 +0100 Subject: [PATCH 0904/1182] Update config.json --- docs/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.json b/docs/config.json index 4375a5a5e7..4012933dcf 100644 --- a/docs/config.json +++ b/docs/config.json @@ -1,5 +1,5 @@ { "website": { - "master_and_released_docs_differ_after": null + "master_and_released_docs_differ_after": "d40f06687f8cbbd22bf7dba05bee93aea11a169f" } } From 434512e92f9577440ac64e39b5f0617926cf1d16 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 4 Nov 2021 23:20:46 +0100 Subject: [PATCH 0905/1182] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 9b0f05023c..76d78512c5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -3,7 +3,7 @@ name: Bug report about: Report a possible bug in HTTPie title: '' labels: "new, bug" -assignees: 'BoboTiG' +assignees: '' --- From 861b8b36a88a83371f8d2a97593aa7b3798ee2b3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 5 Nov 2021 13:59:23 +0100 Subject: [PATCH 0906/1182] Strip leading `://` from URLs to allow quick conversion of a pasted URL to calls (#1197) * Strip leading `://` from URLs to allow quick conversion of a pasted URL to calls Closes #1195 * Markdown lint * Cleanup * Cleanup * Drop extraneous space * Fix example --- CHANGELOG.md | 2 +- docs/README.md | 17 ++++++++++++++--- httpie/cli/argparser.py | 3 +++ tests/test_cli.py | 10 ++++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d2a73c945..74b4956cb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.7.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) - Added support for sending multiple HTTP headers with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) +- Added support for keeping `://` in the URL argument to allow quick conversions of pasted URLs into HTTPie calls just by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) @@ -31,7 +32,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed `--verbose` HTTP 307 redirects with streamed request body. ([#1088](https://github.com/httpie/httpie/issues/1088)) - Fixed handling of session files with `Cookie:` followed by other headers. ([#1126](https://github.com/httpie/httpie/issues/1126)) - ## [2.4.0](https://github.com/httpie/httpie/compare/2.3.0...2.4.0) (2021-02-06) - Added support for `--session` cookie expiration based on `Set-Cookie: max-age=`. ([#1029](https://github.com/httpie/httpie/issues/1029)) diff --git a/docs/README.md b/docs/README.md index ff6fbad163..4490ee9544 100644 --- a/docs/README.md +++ b/docs/README.md @@ -482,14 +482,26 @@ The default scheme is `http://` and can be omitted from the argument: ```bash $ http example.org -# => http://example.org +# → http://example.org ``` HTTPie also installs an `https` executable, where the default scheme is `https://`: ```bash $ https example.org -# => https://example.org +# → https://example.org +``` + +When you paste a URL into the terminal, you can even keep the `://` bit in the URL argument to quickly convert the URL into an HTTPie call just by adding a space after the protocol name. + +```bash +$ https ://example.org +# → https://example.org +``` + +```bash +$ http ://example.org +# → http://example.org ``` ### Querystring parameters @@ -1947,7 +1959,6 @@ HTTPie has the following community channels: - [Discord server](https://httpie.io/discord) to ask questions, discuss features, and for general API development discussion - [StackOverflow](https://stackoverflow.com) to ask questions (make sure to use the [httpie](https://stackoverflow.com/questions/tagged/httpie) tag) - ### Related projects #### Dependencies diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 0b68941092..54c899651a 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -120,6 +120,9 @@ def _process_request_type(self): } def _process_url(self): + if self.args.url.startswith('://'): + # Paste URL & add space shortcut: `http ://pie.dev` → `http://pie.dev` + self.args.url = self.args.url[3:] if not URL_SCHEME_RE.match(self.args.url): if os.path.basename(self.env.program_name) == 'https': scheme = 'https://' diff --git a/tests/test_cli.py b/tests/test_cli.py index e0f5214798..3754a74a13 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -169,6 +169,16 @@ def test_query_string_params_in_url_and_items_with_duplicates(self, assert f'"url": "{url}"' in r +@pytest.mark.parametrize(['program_name', 'url_arg', 'parsed_url'], [ + ('http', '://pie.dev/get', 'http://pie.dev/get'), + ('https', '://pie.dev/get', 'https://pie.dev/get'), +]) +def test_url_leading_colon_slash_slash(program_name, url_arg, parsed_url): + env = MockEnvironment(program_name=program_name) + args = parser.parse_args(args=[url_arg], env=env) + assert args.url == parsed_url + + class TestLocalhostShorthand: def test_expand_localhost_shorthand(self): args = parser.parse_args(args=[':'], env=MockEnvironment()) From 06d9c14e7a0a8c5637a90931a5660401535a4d9b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 5 Nov 2021 14:10:32 +0100 Subject: [PATCH 0907/1182] Add `$ http ://` error handling test --- tests/test_cli.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_cli.py b/tests/test_cli.py index 3754a74a13..a478fcd2e4 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -179,6 +179,11 @@ def test_url_leading_colon_slash_slash(program_name, url_arg, parsed_url): assert args.url == parsed_url +def test_url_colon_slash_slash_only(): + r = http('://', tolerate_error_exit_status=True) + assert r.stderr.strip() == "http: error: InvalidURL: Invalid URL 'http://': No host supplied" + + class TestLocalhostShorthand: def test_expand_localhost_shorthand(self): args = parser.parse_args(args=[':'], env=MockEnvironment()) From 7dfa001d2cbd92021269b5184eb3d5d09844f61a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bra=C5=A1na?= <1784648+janbrasna@users.noreply.github.com> Date: Sun, 21 Nov 2021 11:32:00 +0100 Subject: [PATCH 0908/1182] Consistent userdir/name example (#1210) --- CONTRIBUTING.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 46749d16d4..6b015ca6fd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -168,19 +168,19 @@ the `http` command should point to your development copy: ```powershell # In PowerShell: -(httpie) PS C:\Users\ovezovs\httpie> Get-Command http +(httpie) PS C:\Users\\httpie> Get-Command http CommandType Name Version Source ----------- ---- ------- ------ -Application http.exe 0.0.0.0 C:\Users\ovezovs\httpie\venv\Scripts\http.exe +Application http.exe 0.0.0.0 C:\Users\\httpie\venv\Scripts\http.exe ``` ```bash # In CMD: -(httpie) C:\Users\ovezovs\httpie> where http -C:\Users\ovezovs\httpie\venv\Scripts\http.exe -C:\Users\ovezovs\AppData\Local\Programs\Python\Python38-32\Scripts\http.exe +(httpie) C:\Users\\httpie> where http +C:\Users\\httpie\venv\Scripts\http.exe +C:\Users\\AppData\Local\Programs\Python\Python38-32\Scripts\http.exe -(httpie) C:\Users\ovezovs\httpie> http --version +(httpie) C:\Users\\httpie> http --version 2.3.0-dev ``` From cfcd7413d1afbabc5ab3c88a892851335be4944a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bra=C5=A1na?= <1784648+janbrasna@users.noreply.github.com> Date: Sun, 21 Nov 2021 11:38:05 +0100 Subject: [PATCH 0909/1182] Fix README broken links to old locations (#1209) --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 4490ee9544..442d2580ee 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1994,7 +1994,7 @@ See [CHANGELOG](https://github.com/httpie/httpie/blob/master/CHANGELOG.md). ### Artwork -- [README Animation](https://raw.githubusercontent.com/httpie/httpie/master/httpie.gif) by [Allen Smith](https://github.com/loranallensmith). +- [README Animation](https://github.com/httpie/httpie/blob/master/docs/httpie-animation.gif) by [Allen Smith](https://github.com/loranallensmith). ### Licence @@ -2002,4 +2002,4 @@ BSD-3-Clause: [LICENSE](https://github.com/httpie/httpie/blob/master/LICENSE). ### Authors -[Jakub Roztocil](https://roztocil.co) ([@jakubroztocil](https://twitter.com/jakubroztocil)) created HTTPie and [these fine people](https://github.com/httpie/httpie/AUTHORS.md) have contributed. +[Jakub Roztocil](https://roztocil.co) ([@jakubroztocil](https://twitter.com/jakubroztocil)) created HTTPie and [these fine people](https://github.com/httpie/httpie/blob/master/AUTHORS.md) have contributed. From c000886546cb6d3a8d49f48054a793d84f4b3eb6 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 25 Nov 2021 02:41:37 +0300 Subject: [PATCH 0910/1182] Preserve individual headers with the same name on responses (#1208) * Preserve individual headers with the same name on responses * Rename RequestHeadersDict to HTTPHeadersDict * Update tests/utils/http_server.py * Update tests/utils/http_server.py * Update httpie/adapters.py Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 1 + httpie/adapters.py | 13 ++++++++++ httpie/cli/dicts.py | 2 +- httpie/cli/requestitems.py | 4 +-- httpie/client.py | 19 +++++++++------ httpie/models.py | 4 ++- httpie/sessions.py | 8 +++--- httpie/ssl.py | 2 +- tests/conftest.py | 1 + tests/test_cli.py | 4 +-- tests/test_httpie.py | 27 ++++++++++++++++++++ tests/utils/http_server.py | 50 ++++++++++++++++++++++++++++++++++++++ 12 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 httpie/adapters.py create mode 100644 tests/utils/http_server.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 74b4956cb3..13a79a767a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.7.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) - Added support for sending multiple HTTP headers with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) +- Added support for receving multiple HTTP headers with the same name, individually. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for keeping `://` in the URL argument to allow quick conversions of pasted URLs into HTTPie calls just by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) diff --git a/httpie/adapters.py b/httpie/adapters.py new file mode 100644 index 0000000000..8e2dd7397f --- /dev/null +++ b/httpie/adapters.py @@ -0,0 +1,13 @@ +from httpie.cli.dicts import HTTPHeadersDict +from requests.adapters import HTTPAdapter + + +class HTTPieHTTPAdapter(HTTPAdapter): + + def build_response(self, req, resp): + """Wrap the original headers with the `HTTPHeadersDict` + to preserve multiple headers that have the same name""" + + response = super().build_response(req, resp) + response.headers = HTTPHeadersDict(getattr(resp, 'headers', {})) + return response diff --git a/httpie/cli/dicts.py b/httpie/cli/dicts.py index 43a624eeea..3d0cab5a45 100644 --- a/httpie/cli/dicts.py +++ b/httpie/cli/dicts.py @@ -9,7 +9,7 @@ class BaseMultiDict(MultiDict): """ -class RequestHeadersDict(CIMultiDict, BaseMultiDict): +class HTTPHeadersDict(CIMultiDict, BaseMultiDict): """ Headers are case-insensitive and multiple values are supported through the `add()` API. diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index 73d5e4d0a2..c1c2568e2e 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -11,7 +11,7 @@ ) from .dicts import ( BaseMultiDict, MultipartRequestDataDict, RequestDataDict, - RequestFilesDict, RequestHeadersDict, RequestJSONDataDict, + RequestFilesDict, HTTPHeadersDict, RequestJSONDataDict, RequestQueryParamsDict, ) from .exceptions import ParseError @@ -21,7 +21,7 @@ class RequestItems: def __init__(self, as_form=False): - self.headers = RequestHeadersDict() + self.headers = HTTPHeadersDict() self.data = RequestDataDict() if as_form else RequestJSONDataDict() self.files = RequestFilesDict() self.params = RequestQueryParamsDict() diff --git a/httpie/client.py b/httpie/client.py index 45b4327651..a48527a206 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -11,7 +11,8 @@ # noinspection PyPackageRequirements import urllib3 from . import __version__ -from .cli.dicts import RequestHeadersDict +from .adapters import HTTPieHTTPAdapter +from .cli.dicts import HTTPHeadersDict from .encoding import UTF8 from .plugins.registry import plugin_manager from .sessions import get_httpie_session @@ -153,6 +154,7 @@ def build_requests_session( requests_session = requests.Session() # Install our adapter. + http_adapter = HTTPieHTTPAdapter() https_adapter = HTTPieHTTPSAdapter( ciphers=ciphers, verify=verify, @@ -161,6 +163,7 @@ def build_requests_session( if ssl_version else None ), ) + requests_session.mount('http://', http_adapter) requests_session.mount('https://', https_adapter) # Install adapters from plugins. @@ -179,8 +182,8 @@ def dump_request(kwargs: dict): f'\n>>> requests.request(**{repr_dict(kwargs)})\n\n') -def finalize_headers(headers: RequestHeadersDict) -> RequestHeadersDict: - final_headers = RequestHeadersDict() +def finalize_headers(headers: HTTPHeadersDict) -> HTTPHeadersDict: + final_headers = HTTPHeadersDict() for name, value in headers.items(): if value is not None: # “leading or trailing LWS MAY be removed without @@ -197,13 +200,13 @@ def finalize_headers(headers: RequestHeadersDict) -> RequestHeadersDict: def apply_missing_repeated_headers( prepared_request: requests.PreparedRequest, - original_headers: RequestHeadersDict + original_headers: HTTPHeadersDict ) -> None: """Update the given `prepared_request`'s headers with the original ones. This allows the requests to be prepared as usual, and then later merged with headers that are specified multiple times.""" - new_headers = RequestHeadersDict(prepared_request.headers) + new_headers = HTTPHeadersDict(prepared_request.headers) for prepared_name, prepared_value in prepared_request.headers.items(): if prepared_name not in original_headers: continue @@ -225,8 +228,8 @@ def apply_missing_repeated_headers( prepared_request.headers = new_headers -def make_default_headers(args: argparse.Namespace) -> RequestHeadersDict: - default_headers = RequestHeadersDict({ +def make_default_headers(args: argparse.Namespace) -> HTTPHeadersDict: + default_headers = HTTPHeadersDict({ 'User-Agent': DEFAULT_UA }) @@ -271,7 +274,7 @@ def make_send_kwargs_mergeable_from_env(args: argparse.Namespace) -> dict: def make_request_kwargs( args: argparse.Namespace, - base_headers: RequestHeadersDict = None, + base_headers: HTTPHeadersDict = None, request_body_read_callback=lambda chunk: chunk ) -> dict: """ diff --git a/httpie/models.py b/httpie/models.py index 9c72518aaf..64079d0c21 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -72,7 +72,9 @@ def headers(self): ) headers.extend( f'Set-Cookie: {cookie}' - for cookie in split_cookies(original.headers.get('Set-Cookie')) + for header, value in original.headers.items() + for cookie in split_cookies(value) + if header == 'Set-Cookie' ) return '\r\n'.join(headers) diff --git a/httpie/sessions.py b/httpie/sessions.py index 0a04fb7446..176c03e76d 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -13,7 +13,7 @@ from requests.auth import AuthBase from requests.cookies import RequestsCookieJar, create_cookie -from .cli.dicts import RequestHeadersDict +from .cli.dicts import HTTPHeadersDict from .config import BaseConfigDict, DEFAULT_CONFIG_DIR from .plugins.registry import plugin_manager @@ -65,7 +65,7 @@ def __init__(self, path: Union[str, Path]): 'password': None } - def update_headers(self, request_headers: RequestHeadersDict): + def update_headers(self, request_headers: HTTPHeadersDict): """ Update the session headers with the request ones while ignoring certain name prefixes. @@ -98,8 +98,8 @@ def update_headers(self, request_headers: RequestHeadersDict): self['headers'] = dict(headers) @property - def headers(self) -> RequestHeadersDict: - return RequestHeadersDict(self['headers']) + def headers(self) -> HTTPHeadersDict: + return HTTPHeadersDict(self['headers']) @property def cookies(self) -> RequestsCookieJar: diff --git a/httpie/ssl.py b/httpie/ssl.py index f41b802027..cdec18f87b 100644 --- a/httpie/ssl.py +++ b/httpie/ssl.py @@ -1,6 +1,6 @@ import ssl -from requests.adapters import HTTPAdapter +from httpie.adapters import HTTPAdapter # noinspection PyPackageRequirements from urllib3.util.ssl_ import ( DEFAULT_CIPHERS, create_urllib3_context, diff --git a/tests/conftest.py b/tests/conftest.py index a65df162f5..fe5f21165a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,7 @@ from pytest_httpbin import certs from .utils import HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN, HTTPBIN_WITH_CHUNKED_SUPPORT +from .utils.http_server import http_server # noqa @pytest.fixture(scope='function', autouse=True) diff --git a/tests/test_cli.py b/tests/test_cli.py index a478fcd2e4..09a39c11f9 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -39,7 +39,7 @@ def test_escape_separator(self): # files self.key_value_arg(fr'bar\@baz@{FILE_PATH_ARG}'), ]) - # `RequestHeadersDict` => `dict` + # `HTTPHeadersDict` => `dict` headers = dict(items.headers) assert headers == { @@ -88,7 +88,7 @@ def test_valid_items(self): ]) # Parsed headers - # `RequestHeadersDict` => `dict` + # `HTTPHeadersDict` => `dict` headers = dict(items.headers) assert headers == { 'Header': 'value', diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 748e876943..f646d4e04a 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -291,6 +291,33 @@ def test_headers_multiple_headers_representation(httpbin_both, pretty): assert 'c: c' in r +def test_response_headers_multiple(http_server): + r = http('GET', http_server + '/headers', 'Foo:bar', 'Foo:baz') + assert 'Foo: bar' in r + assert 'Foo: baz' in r + + +def test_response_headers_multiple_repeated(http_server): + r = http('GET', http_server + '/headers', 'Foo:bar', 'Foo:baz', + 'Foo:bar') + assert r.count('Foo: bar') == 2 + assert 'Foo: baz' in r + + +@pytest.mark.parametrize('pretty', ['format', 'none']) +def test_response_headers_multiple_representation(http_server, pretty): + r = http('--pretty', pretty, http_server + '/headers', + 'A:A', 'A:B', 'A:C', 'B:A', 'B:B', 'C:C', 'C:c') + + assert 'A: A' in r + assert 'A: B' in r + assert 'A: C' in r + assert 'B: A' in r + assert 'B: B' in r + assert 'C: C' in r + assert 'C: c' in r + + def test_json_input_preserve_order(httpbin_both): r = http('PATCH', httpbin_both + '/patch', 'order:={"map":{"1":"first","2":"second"}}') diff --git a/tests/utils/http_server.py b/tests/utils/http_server.py new file mode 100644 index 0000000000..42be768b46 --- /dev/null +++ b/tests/utils/http_server.py @@ -0,0 +1,50 @@ +import threading + +from collections import defaultdict +from http import HTTPStatus +from http.server import HTTPServer, BaseHTTPRequestHandler +from urllib.parse import urlparse + +import pytest + + +class TestHandler(BaseHTTPRequestHandler): + handlers = defaultdict(dict) + + @classmethod + def handler(cls, method, path): + def inner(func): + cls.handlers[method][path] = func + return func + return inner + + def do_GET(self): + parse_result = urlparse(self.path) + func = self.handlers['GET'].get(parse_result.path) + if func is None: + return self.send_error(HTTPStatus.NOT_FOUND) + + return func(self) + + +@TestHandler.handler('GET', '/headers') +def get_headers(handler): + handler.send_response(200) + for key, value in handler.headers.items(): + handler.send_header(key, value) + handler.send_header('Content-Length', 0) + handler.end_headers() + + +@pytest.fixture(scope="function") +def http_server(): + """A custom HTTP server implementation for our tests, that is + built on top of the http.server module. Handy when we need to + deal with details which httpbin can not capture.""" + + server = HTTPServer(('localhost', 0), TestHandler) + thread = threading.Thread(target=server.serve_forever) + thread.start() + yield '{}:{}'.format(*server.socket.getsockname()) + server.shutdown() + thread.join(timeout=0.5) From ef62fc11bfe8d0b2adab0c6db2a66eb3e1412c65 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 25 Nov 2021 02:45:39 +0300 Subject: [PATCH 0911/1182] core: support custom request/response classes (#1205) * core: support custom request/response classes * Move to `httpie.models`, prefix with `Requests` --- httpie/client.py | 5 +++-- httpie/core.py | 13 +++++++++---- httpie/models.py | 22 +++++++++++++++++++++- httpie/output/writer.py | 21 +++++++++++++-------- 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/httpie/client.py b/httpie/client.py index a48527a206..8d33857668 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -4,7 +4,7 @@ import sys from contextlib import contextmanager from pathlib import Path -from typing import Callable, Iterable, Union +from typing import Callable, Iterable from urllib.parse import urlparse, urlunparse import requests @@ -14,6 +14,7 @@ from .adapters import HTTPieHTTPAdapter from .cli.dicts import HTTPHeadersDict from .encoding import UTF8 +from .models import RequestsMessage from .plugins.registry import plugin_manager from .sessions import get_httpie_session from .ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter @@ -36,7 +37,7 @@ def collect_messages( args: argparse.Namespace, config_dir: Path, request_body_read_callback: Callable[[bytes], None] = None, -) -> Iterable[Union[requests.PreparedRequest, requests.Response]]: +) -> Iterable[RequestsMessage]: httpie_session = None httpie_session_headers = None if args.session or args.session_read_only: diff --git a/httpie/core.py b/httpie/core.py index 44b3f5c5f2..3c6c10217c 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -13,6 +13,11 @@ from .client import collect_messages from .context import Environment from .downloads import Downloader +from .models import ( + RequestsMessage, + RequestsMessageKind, + infer_requests_message_kind +) from .output.writer import write_message, write_stream, MESSAGE_SEPARATOR_BYTES from .plugins.registry import plugin_manager from .status import ExitStatus, http_status_to_exit_status @@ -111,18 +116,18 @@ def main(args: List[Union[str, bytes]] = sys.argv, env=Environment()) -> ExitSta def get_output_options( args: argparse.Namespace, - message: Union[requests.PreparedRequest, requests.Response] + message: RequestsMessage ) -> Tuple[bool, bool]: return { - requests.PreparedRequest: ( + RequestsMessageKind.REQUEST: ( OUT_REQ_HEAD in args.output_options, OUT_REQ_BODY in args.output_options, ), - requests.Response: ( + RequestsMessageKind.RESPONSE: ( OUT_RESP_HEAD in args.output_options, OUT_RESP_BODY in args.output_options, ), - }[type(message)] + }[infer_requests_message_kind(message)] def program(args: argparse.Namespace, env: Environment) -> ExitStatus: diff --git a/httpie/models.py b/httpie/models.py index 64079d0c21..af3e5a9831 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -1,4 +1,7 @@ -from typing import Iterable +import requests + +from enum import Enum, auto +from typing import Iterable, Union from urllib.parse import urlsplit from .utils import split_cookies, parse_content_type_header @@ -118,3 +121,20 @@ def body(self): # Happens with JSON/form request data parsed from the command line. body = body.encode() return body or b'' + + +RequestsMessage = Union[requests.PreparedRequest, requests.Response] + + +class RequestsMessageKind(Enum): + REQUEST = auto() + RESPONSE = auto() + + +def infer_requests_message_kind(message: RequestsMessage) -> RequestsMessageKind: + if isinstance(message, requests.PreparedRequest): + return RequestsMessageKind.REQUEST + elif isinstance(message, requests.Response): + return RequestsMessageKind.RESPONSE + else: + raise TypeError(f"Unexpected message type: {type(message).__name__}") diff --git a/httpie/output/writer.py b/httpie/output/writer.py index 6f251f7cea..4650264db6 100644 --- a/httpie/output/writer.py +++ b/httpie/output/writer.py @@ -2,10 +2,15 @@ import errno from typing import IO, TextIO, Tuple, Type, Union -import requests - from ..context import Environment -from ..models import HTTPRequest, HTTPResponse, HTTPMessage +from ..models import ( + HTTPRequest, + HTTPResponse, + HTTPMessage, + RequestsMessage, + RequestsMessageKind, + infer_requests_message_kind +) from .processing import Conversion, Formatting from .streams import ( BaseStream, BufferedPrettyStream, EncodedStream, PrettyStream, RawStream, @@ -17,7 +22,7 @@ def write_message( - requests_message: Union[requests.PreparedRequest, requests.Response], + requests_message: RequestsMessage, env: Environment, args: argparse.Namespace, with_headers=False, @@ -93,14 +98,14 @@ def write_stream_with_colors_win( def build_output_stream_for_message( args: argparse.Namespace, env: Environment, - requests_message: Union[requests.PreparedRequest, requests.Response], + requests_message: RequestsMessage, with_headers: bool, with_body: bool, ): message_type = { - requests.PreparedRequest: HTTPRequest, - requests.Response: HTTPResponse, - }[type(requests_message)] + RequestsMessageKind.REQUEST: HTTPRequest, + RequestsMessageKind.RESPONSE: HTTPResponse, + }[infer_requests_message_kind(requests_message)] stream_class, stream_kwargs = get_stream_type_and_kwargs( env=env, args=args, From 0fc6331ee02d5a2862684dd5c2885ea4d6eb39a0 Mon Sep 17 00:00:00 2001 From: Vivaan Verma Date: Thu, 25 Nov 2021 22:06:34 +0000 Subject: [PATCH 0912/1182] Change `PyPi` to `PyPI` (#1203) * Change `PyPi` to `PyPI` * fix: change `PyPi` to `PyPI` in method yaml file --- docs/README.md | 2 +- docs/installation/methods.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 442d2580ee..b6ced336f5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -58,7 +58,7 @@ Do not edit here, but in docs/installation/. ### Universal -#### PyPi +#### PyPI Please make sure you have Python 3.6 or newer (`python --version`). diff --git a/docs/installation/methods.yml b/docs/installation/methods.yml index 8cb1f708e8..d84b30cfbf 100644 --- a/docs/installation/methods.yml +++ b/docs/installation/methods.yml @@ -171,7 +171,7 @@ tools: - port upgrade httpie pypi: - title: PyPi + title: PyPI name: pip note: Please make sure you have Python 3.6 or newer (`python --version`). links: From 6bdcdf1eba5a0b15e025388c84e34eecbe0394ee Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 26 Nov 2021 14:45:46 +0300 Subject: [PATCH 0913/1182] Proper JSON handling for :=/:=@ (#1213) * Proper JSON handling for :=/:=@ * document the behavior * fixup docs --- CHANGELOG.md | 1 + docs/README.md | 4 ++++ httpie/cli/argparser.py | 2 +- httpie/cli/requestitems.py | 40 +++++++++++++++++++++++++++++++------- tests/test_cli.py | 2 +- tests/test_json.py | 36 ++++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13a79a767a..a48efcbd7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for sending multiple HTTP headers with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) - Added support for receving multiple HTTP headers with the same name, individually. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for keeping `://` in the URL argument to allow quick conversions of pasted URLs into HTTPie calls just by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) +- Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) diff --git a/docs/README.md b/docs/README.md index b6ced336f5..a887e937b8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -710,6 +710,10 @@ Host: pie.dev } ``` +The `:=`/`:=@` syntax is JSON-specific. You can switch your request to `--form` or `--multipart`, +and string, float, and number values will continue to be serialized (as string form values). +Other JSON types, however, are not allowed with `--form` or `--multipart`. + ### Raw and complex JSON Please note that with the [request items](#request-items) data field syntax, commands can quickly become unwieldy when sending complex structures. diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 54c899651a..1a3d758964 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -364,7 +364,7 @@ def _parse_items(self): try: request_items = RequestItems.from_args( request_item_args=self.args.request_items, - as_form=self.args.form, + request_type=self.args.request_type, ) except ParseError as e: if self.args.traceback: diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index c1c2568e2e..c91019439a 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -1,4 +1,5 @@ import os +import functools from typing import Callable, Dict, IO, List, Optional, Tuple, Union from .argtypes import KeyValueArg @@ -7,7 +8,7 @@ SEPARATOR_DATA_EMBED_RAW_JSON_FILE, SEPARATOR_DATA_RAW_JSON, SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD, SEPARATOR_FILE_UPLOAD_TYPE, SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY, - SEPARATOR_QUERY_PARAM, + SEPARATOR_QUERY_PARAM, RequestType ) from .dicts import ( BaseMultiDict, MultipartRequestDataDict, RequestDataDict, @@ -20,9 +21,11 @@ class RequestItems: - def __init__(self, as_form=False): + def __init__(self, request_type: Optional[RequestType] = None): self.headers = HTTPHeadersDict() - self.data = RequestDataDict() if as_form else RequestJSONDataDict() + self.request_type = request_type + self.is_json = request_type is None or request_type is RequestType.JSON + self.data = RequestJSONDataDict() if self.is_json else RequestDataDict() self.files = RequestFilesDict() self.params = RequestQueryParamsDict() # To preserve the order of fields in file upload multipart requests. @@ -32,9 +35,9 @@ def __init__(self, as_form=False): def from_args( cls, request_item_args: List[KeyValueArg], - as_form=False, + request_type: Optional[RequestType] = None, ) -> 'RequestItems': - instance = cls(as_form=as_form) + instance = cls(request_type=request_type) rules: Dict[str, Tuple[Callable, dict]] = { SEPARATOR_HEADER: ( process_header_arg, @@ -61,11 +64,11 @@ def from_args( instance.data, ), SEPARATOR_DATA_RAW_JSON: ( - process_data_raw_json_embed_arg, + json_only(instance, process_data_raw_json_embed_arg), instance.data, ), SEPARATOR_DATA_EMBED_RAW_JSON_FILE: ( - process_data_embed_raw_json_file_arg, + json_only(instance, process_data_embed_raw_json_file_arg), instance.data, ), } @@ -127,6 +130,29 @@ def process_data_embed_file_contents_arg(arg: KeyValueArg) -> str: return load_text_file(arg) +def json_only(items: RequestItems, func: Callable[[KeyValueArg], JSONType]) -> str: + if items.is_json: + return func + + @functools.wraps(func) + def wrapper(*args, **kwargs) -> str: + try: + ret = func(*args, **kwargs) + except ParseError: + ret = None + + # If it is a basic type, then allow it + if isinstance(ret, (str, int, float)): + return str(ret) + else: + raise ParseError( + 'Can\'t use complex JSON value types with ' + '--form/--multipart.' + ) + + return wrapper + + def process_data_embed_raw_json_file_arg(arg: KeyValueArg) -> JSONType: contents = load_text_file(arg) value = load_json(arg, contents) diff --git a/tests/test_cli.py b/tests/test_cli.py index 09a39c11f9..fd3f0dd0c1 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -132,7 +132,7 @@ def test_multiple_text_fields_with_same_field_name(self): self.key_value_arg('text_field=a'), self.key_value_arg('text_field=b') ], - as_form=True, + request_type=constants.RequestType.FORM, ) assert items.data['text_field'] == ['a', 'b'] assert list(items.data.items()) == [ diff --git a/tests/test_json.py b/tests/test_json.py index 9b0f17ce68..f19aa7e158 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -4,6 +4,7 @@ import responses from httpie.cli.constants import PRETTY_MAP +from httpie.cli.exceptions import ParseError from httpie.compat import is_windows from httpie.output.formatters.colors import ColorFormatter from httpie.utils import JsonDictPreservingDuplicateKeys @@ -116,3 +117,38 @@ def test_duplicate_keys_support_from_input_file(): # Check --unsorted r = http(*args, '--unsorted') assert JSON_WITH_DUPES_FORMATTED_UNSORTED in r + + +@pytest.mark.parametrize("value", [ + 1, + 1.1, + True, + 'some_value' +]) +def test_simple_json_arguments_with_non_json(httpbin, value): + r = http( + '--form', + httpbin + '/post', + f'option:={json.dumps(value)}', + ) + assert r.json['form'] == {'option': str(value)} + + +@pytest.mark.parametrize("request_type", [ + "--form", + "--multipart", +]) +@pytest.mark.parametrize("value", [ + [1, 2, 3], + {'a': 'b'}, + None +]) +def test_complex_json_arguments_with_non_json(httpbin, request_type, value): + with pytest.raises(ParseError) as cm: + http( + request_type, + httpbin + '/post', + f'option:={json.dumps(value)}', + ) + + cm.match('Can\'t use complex JSON value types') From 245cede2c274bef7b172fe65814bfabc6f87b0b4 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 30 Nov 2021 11:12:51 +0300 Subject: [PATCH 0914/1182] cmd: Implement httpie plugins interface (#1200) --- docs/README.md | 69 ++++++++++++ docs/markdownlint.rb | 3 + httpie/cli/argparser.py | 81 ++++++++++---- httpie/cli/definition.py | 2 +- httpie/client.py | 2 +- httpie/compat.py | 36 ++++++ httpie/config.py | 4 + httpie/context.py | 16 ++- httpie/core.py | 48 +++++--- httpie/manager/__init__.py | 0 httpie/manager/__main__.py | 61 ++++++++++ httpie/manager/cli.py | 93 ++++++++++++++++ httpie/manager/core.py | 33 ++++++ httpie/manager/plugins.py | 188 +++++++++++++++++++++++++++++++ httpie/plugins/manager.py | 73 +++++++++--- httpie/{ssl.py => ssl_.py} | 0 httpie/utils.py | 11 ++ setup.py | 2 + tests/conftest.py | 7 ++ tests/test_plugins_cli.py | 132 ++++++++++++++++++++++ tests/test_ssl.py | 2 +- tests/utils/__init__.py | 52 ++++++++- tests/utils/plugins_cli.py | 222 +++++++++++++++++++++++++++++++++++++ 23 files changed, 1075 insertions(+), 62 deletions(-) create mode 100644 httpie/manager/__init__.py create mode 100644 httpie/manager/__main__.py create mode 100644 httpie/manager/cli.py create mode 100644 httpie/manager/core.py create mode 100644 httpie/manager/plugins.py rename httpie/{ssl.py => ssl_.py} (100%) create mode 100644 tests/test_plugins_cli.py create mode 100644 tests/utils/plugins_cli.py diff --git a/docs/README.md b/docs/README.md index a887e937b8..de5d28e169 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1880,6 +1880,11 @@ $ cat ~/.config/httpie/config.json Technically, it is possible to include any HTTPie options in there. However, it is not recommended to modify the default behavior in a way that would break your compatibility with the wider world as that may become confusing. +#### `plugins_dir` + +The directory where the plugins will be installed. HTTPie needs to have read/write access on that directory, since +`httpie plugins install` will download new plugins to there. + ### Un-setting previously specified options Default options from the config file, or specified any other way, can be unset for a particular invocation via `--no-OPTION` arguments passed via the command line (e.g., `--no-style` or `--no-session`). @@ -1919,6 +1924,70 @@ And since there’s neither data nor `EOF`, it will get stuck. So unless you’r Also, it might be good to set a connection `--timeout` limit to prevent your program from hanging if the server never responds. +## Plugins Manager + +HTTPie offers extensibility through plugins, and there are over 50+ of them available to try! +They add things like new authentication methods ([akamai/httpie-edgegrid](https://github.com/akamai/httpie-edgegrid)), +transport mechanisms ([httpie/httpie-unixsocket](https://github.com/httpie/httpie-unixsocket)), +message convertors ([banteg/httpie-image](https://github.com/banteg/httpie-image)), or simply +change how a response is formatted. + +> Note: Plugins are usually made by our community members, and thus have no direct relationship with +> the HTTPie project. We do not control / review them at the moment, so use them at your own discretion. + +For managing these plugins; starting with 3.0, we are offering a new plugin manager. + +This command is currently in beta. + +### `httpie plugins` + +`plugins` interface is a very simple plugin manager for installing, listing and uninstalling HTTPie plugins. + +> In the past `pip` was used to install/uninstall plugins, but on some environments (e.g brew installed +packages) it wasn't working properly. The new interface is a very simple overlay on top of `pip` to allow +plugin installations on every installation method. + +> By default the plugins (and their missing dependencies) will be stored under the configuration directory, +but this can be modified through `plugins_dir` variable on the config. + +#### `httpie plugins install` + +For installing plugins from [PyPI](https://pypi.org/) or from local paths, `httpie plugins install` +can be used. + +```bash +$ httpie plugins install httpie-plugin +Installing httpie-plugin... +Successfully installed httpie-plugin-1.0.2 +``` + +> Tip: Generally HTTPie plugins start with `httpie-` prefix. Try searching for it on [PyPI](https://pypi.org/search/?q=httpie-) +> to find out all plugins from the community. + +#### `httpie plugins list` + +List all installed plugins. + +```bash +$ httpie plugins list +httpie_plugin (1.0.2) + httpie_plugin (httpie.plugins.auth.v1) +httpie_plugin_2 (1.0.6) + httpie_plugin_2 (httpie.plugins.auth.v1) +httpie_converter (1.0.0) + httpie_iterm_converter (httpie.plugins.converter.v1) + httpie_konsole_konverter (httpie.plugins.converter.v1) +``` + +#### `httpie plugins uninstall` + +Uninstall plugins from the isolated plugins directory. If the plugin is not installed +through `httpie plugins install`, it won't uninstall it. + +```bash +$ httpie plugins uninstall httpie-plugin +``` + ## Meta ### Interface design diff --git a/docs/markdownlint.rb b/docs/markdownlint.rb index 397f475755..c31232d8af 100644 --- a/docs/markdownlint.rb +++ b/docs/markdownlint.rb @@ -17,6 +17,9 @@ # MD014 Dollar signs used before commands without showing output exclude_rule 'MD014' +# MD028 Blank line inside blockquote +exclude_rule 'MD028' + # Tell the linter to use ordered lists: # 1. Foo # 2. Bar diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 1a3d758964..28dcd96c0e 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -50,7 +50,64 @@ def _split_lines(self, text, width): # TODO: refactor and design type-annotated data structures # for raw args + parsed args and keep things immutable. -class HTTPieArgumentParser(argparse.ArgumentParser): +class BaseHTTPieArgumentParser(argparse.ArgumentParser): + def __init__(self, *args, formatter_class=HTTPieHelpFormatter, **kwargs): + super().__init__(*args, formatter_class=formatter_class, **kwargs) + self.env = None + self.args = None + self.has_stdin_data = False + self.has_input_data = False + + # noinspection PyMethodOverriding + def parse_args( + self, + env: Environment, + args=None, + namespace=None + ) -> argparse.Namespace: + self.env = env + self.args, no_options = self.parse_known_args(args, namespace) + if self.args.debug: + self.args.traceback = True + self.has_stdin_data = ( + self.env.stdin + and not getattr(self.args, 'ignore_stdin', False) + and not self.env.stdin_isatty + ) + self.has_input_data = self.has_stdin_data or getattr(self.args, 'raw', None) is not None + return self.args + + # noinspection PyShadowingBuiltins + def _print_message(self, message, file=None): + # Sneak in our stderr/stdout. + if hasattr(self, 'root'): + env = self.root.env + else: + env = self.env + + if env is not None: + file = { + sys.stdout: env.stdout, + sys.stderr: env.stderr, + None: env.stderr + }.get(file, file) + + if not hasattr(file, 'buffer') and isinstance(message, str): + message = message.encode(env.stdout_encoding) + super()._print_message(message, file) + + +class HTTPieManagerArgumentParser(BaseHTTPieArgumentParser): + def parse_known_args(self, args=None, namespace=None): + try: + return super().parse_known_args(args, namespace) + except SystemExit as exc: + if not hasattr(self, 'root') and exc.code == 2: # Argument Parser Error + raise argparse.ArgumentError(None, None) + raise + + +class HTTPieArgumentParser(BaseHTTPieArgumentParser): """Adds additional logic to `argparse.ArgumentParser`. Handles all input (CLI args, file args, stdin), applies defaults, @@ -58,13 +115,9 @@ class HTTPieArgumentParser(argparse.ArgumentParser): """ - def __init__(self, *args, formatter_class=HTTPieHelpFormatter, **kwargs): - kwargs['add_help'] = False - super().__init__(*args, formatter_class=formatter_class, **kwargs) - self.env = None - self.args = None - self.has_stdin_data = False - self.has_input_data = False + def __init__(self, *args, **kwargs): + kwargs.setdefault('add_help', False) + super().__init__(*args, **kwargs) # noinspection PyMethodOverriding def parse_args( @@ -141,18 +194,6 @@ def _process_url(self): else: self.args.url = scheme + self.args.url - # noinspection PyShadowingBuiltins - def _print_message(self, message, file=None): - # Sneak in our stderr/stdout. - file = { - sys.stdout: self.env.stdout, - sys.stderr: self.env.stderr, - None: self.env.stderr - }.get(file, file) - if not hasattr(file, 'buffer') and isinstance(message, str): - message = message.encode(self.env.stdout_encoding) - super()._print_message(message, file) - def _setup_standard_streams(self): """ Modify `env.stdout` and `env.stdout_isatty` based on args, if needed. diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 6ebb50c50e..98c45987d9 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -25,7 +25,7 @@ from ..plugins.builtin import BuiltinAuthPlugin from ..plugins.registry import plugin_manager from ..sessions import DEFAULT_SESSIONS_DIR -from ..ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS +from ..ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS parser = HTTPieArgumentParser( diff --git a/httpie/client.py b/httpie/client.py index 8d33857668..374e14fd23 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -17,7 +17,7 @@ from .models import RequestsMessage from .plugins.registry import plugin_manager from .sessions import get_httpie_session -from .ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter +from .ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter from .uploads import ( compress_request, prepare_request_body, get_multipart_data_and_content_type, diff --git a/httpie/compat.py b/httpie/compat.py index 43333571d4..3b89f8ca4d 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -1,4 +1,5 @@ import sys +from typing import Any, Optional, Iterable is_windows = 'win32' in str(sys.platform).lower() @@ -52,3 +53,38 @@ def __get__(self, instance, cls=None): return self res = instance.__dict__[self.name] = self.func(instance) return res + + +# importlib_metadata was a provisional module, so the APIs changed quite a few times +# between 3.8-3.10. It was also not included in the standard library until 3.8, so +# we install the backport for <3.8. + +if sys.version_info >= (3, 8): + import importlib.metadata as importlib_metadata +else: + import importlib_metadata + + +def find_entry_points(entry_points: Any, group: str) -> Iterable[importlib_metadata.EntryPoint]: + if hasattr(entry_points, "select"): # Python 3.10+ / importlib_metadata >= 3.9.0 + return entry_points.select(group=group) + else: + return set(entry_points.get(group, ())) + + +def get_dist_name(entry_point: importlib_metadata.EntryPoint) -> Optional[str]: + dist = getattr(entry_point, "dist", None) + if dist is not None: # Python 3.10+ + return dist.name + + match = entry_point.pattern.match(entry_point.value) + if not (match and match.group('module')): + return None + + package = match.group('module').split('.')[0] + try: + metadata = importlib_metadata.metadata(package) + except importlib_metadata.PackageNotFoundError: + return None + else: + return metadata.get('name') diff --git a/httpie/config.py b/httpie/config.py index e2cc5e0ec3..28574e4ae7 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -128,3 +128,7 @@ def __init__(self, directory: Union[str, Path] = DEFAULT_CONFIG_DIR): @property def default_options(self) -> list: return self['default_options'] + + @property + def plugins_dir(self) -> Path: + return Path(self.get('plugins_dir', self.directory / 'plugins')).resolve() diff --git a/httpie/context.py b/httpie/context.py index be2e0565b2..7a6e6a865c 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -1,7 +1,8 @@ import sys import os +from contextlib import contextmanager from pathlib import Path -from typing import IO, Optional +from typing import Iterator, IO, Optional try: @@ -120,6 +121,19 @@ def devnull(self) -> IO: self._devnull = open(os.devnull, 'w+') return self._devnull + @contextmanager + def as_silent(self) -> Iterator[None]: + original_stdout = self.stdout + original_stderr = self.stderr + + try: + self.stdout = self.devnull + self.stderr = self.devnull + yield + finally: + self.stdout = original_stdout + self.stderr = original_stderr + def log_error(self, msg, level='error'): assert level in ['error', 'warning'] self._orig_stderr.write(f'\n{self.program_name}: {level}: {msg}\n\n') diff --git a/httpie/core.py b/httpie/core.py index 3c6c10217c..48d21bc4f0 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -2,7 +2,7 @@ import os import platform import sys -from typing import List, Optional, Tuple, Union +from typing import List, Optional, Tuple, Union, Callable import requests from pygments import __version__ as pygments_version @@ -24,22 +24,16 @@ # noinspection PyDefaultArgument -def main(args: List[Union[str, bytes]] = sys.argv, env=Environment()) -> ExitStatus: - """ - The main function. - - Pre-process args, handle some special types of invocations, - and run the main program with error handling. - - Return exit status code. - - """ +def raw_main( + parser: argparse.ArgumentParser, + main_program: Callable[[argparse.Namespace, Environment], ExitStatus], + args: List[Union[str, bytes]] = sys.argv, + env: Environment = Environment() +) -> ExitStatus: program_name, *args = args env.program_name = os.path.basename(program_name) args = decode_raw_args(args, env.stdin_encoding) - plugin_manager.load_installed_plugins() - - from .cli.definition import parser + plugin_manager.load_installed_plugins(env.config.plugins_dir) if env.config.default_options: args = env.config.default_options + args @@ -72,7 +66,7 @@ def main(args: List[Union[str, bytes]] = sys.argv, env=Environment()) -> ExitSta exit_status = ExitStatus.ERROR else: try: - exit_status = program( + exit_status = main_program( args=parsed_args, env=env, ) @@ -114,6 +108,30 @@ def main(args: List[Union[str, bytes]] = sys.argv, env=Environment()) -> ExitSta return exit_status +def main( + args: List[Union[str, bytes]] = sys.argv, + env: Environment = Environment() +) -> ExitStatus: + """ + The main function. + + Pre-process args, handle some special types of invocations, + and run the main program with error handling. + + Return exit status code. + + """ + + from .cli.definition import parser + + return raw_main( + parser=parser, + main_program=program, + args=args, + env=env + ) + + def get_output_options( args: argparse.Namespace, message: RequestsMessage diff --git a/httpie/manager/__init__.py b/httpie/manager/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/httpie/manager/__main__.py b/httpie/manager/__main__.py new file mode 100644 index 0000000000..50a5fbd3e4 --- /dev/null +++ b/httpie/manager/__main__.py @@ -0,0 +1,61 @@ +import argparse +import sys + +from typing import List, Union + +from httpie.context import Environment +from httpie.status import ExitStatus +from httpie.manager.cli import parser +from httpie.manager.core import MSG_COMMAND_CONFUSION, program as main_program + + +def is_http_command(args: List[Union[str, bytes]], env: Environment) -> bool: + """Check whether http/https parser can parse the arguments.""" + + from httpie.cli.definition import parser as http_parser + from httpie.manager.cli import COMMANDS + + # If the user already selected a top-level sub-command, never + # show the http/https version. E.g httpie plugins pie.dev/post + if len(args) >= 1 and args[0] in COMMANDS: + return False + + with env.as_silent(): + try: + http_parser.parse_args(env=env, args=args) + except (Exception, SystemExit): + return False + else: + return True + + +def main(args: List[Union[str, bytes]] = sys.argv, env: Environment = Environment()) -> ExitStatus: + from httpie.core import raw_main + + try: + return raw_main( + parser=parser, + main_program=main_program, + args=args, + env=env + ) + except argparse.ArgumentError: + program_args = args[1:] + if is_http_command(program_args, env): + env.stderr.write(MSG_COMMAND_CONFUSION.format(args=' '.join(program_args)) + "\n") + + return ExitStatus.ERROR + + +def program(): + try: + exit_status = main() + except KeyboardInterrupt: + from httpie.status import ExitStatus + exit_status = ExitStatus.ERROR_CTRL_C + + return exit_status + + +if __name__ == '__main__': # pragma: nocover + sys.exit(program()) diff --git a/httpie/manager/cli.py b/httpie/manager/cli.py new file mode 100644 index 0000000000..52a6764a13 --- /dev/null +++ b/httpie/manager/cli.py @@ -0,0 +1,93 @@ +from textwrap import dedent +from httpie.cli.argparser import HTTPieManagerArgumentParser + +COMMANDS = { + 'plugins': { + 'help': 'Manage HTTPie plugins.', + 'install': [ + 'Install the given targets from PyPI ' + 'or from a local paths.', + { + 'dest': 'targets', + 'nargs': '+', + 'help': 'targets to install' + } + ], + 'uninstall': [ + 'Uninstall the given HTTPie plugins.', + { + 'dest': 'targets', + 'nargs': '+', + 'help': 'targets to install' + } + ], + 'list': [ + 'List all installed HTTPie plugins.' + ], + }, +} + + +def missing_subcommand(*args) -> str: + base = COMMANDS + for arg in args: + base = base[arg] + + assert isinstance(base, dict) + subcommands = ', '.join(map(repr, base.keys())) + return f'Please specify one of these: {subcommands}' + + +def generate_subparsers(root, parent_parser, definitions): + action_dest = '_'.join(parent_parser.prog.split()[1:] + ['action']) + actions = parent_parser.add_subparsers( + dest=action_dest + ) + for command, properties in definitions.items(): + is_subparser = isinstance(properties, dict) + descr = properties.pop('help', None) if is_subparser else properties.pop(0) + command_parser = actions.add_parser(command, description=descr) + command_parser.root = root + if is_subparser: + generate_subparsers(root, command_parser, properties) + continue + + for argument in properties: + command_parser.add_argument(**argument) + + +parser = HTTPieManagerArgumentParser( + prog='httpie', + description=dedent( + ''' + Managing interface for the HTTPie itself. + + Be aware that you might be looking for http/https commands for sending + HTTP requests. This command is only available for managing the HTTTPie + plugins and the configuration around it. + ''' + ), +) + +parser.add_argument( + '--debug', + action='store_true', + default=False, + help=''' + Prints the exception traceback should one occur, as well as other + information useful for debugging HTTPie itself and for reporting bugs. + + ''' +) + +parser.add_argument( + '--traceback', + action='store_true', + default=False, + help=''' + Prints the exception traceback should one occur. + + ''' +) + +generate_subparsers(parser, parser, COMMANDS) diff --git a/httpie/manager/core.py b/httpie/manager/core.py new file mode 100644 index 0000000000..e2134b5527 --- /dev/null +++ b/httpie/manager/core.py @@ -0,0 +1,33 @@ +import argparse + +from httpie.context import Environment +from httpie.manager.plugins import PluginInstaller +from httpie.status import ExitStatus +from httpie.manager.cli import missing_subcommand, parser + +MSG_COMMAND_CONFUSION = '''\ +This command is only for managing HTTPie plugins. +To send a request, please use the http/https commands: + + $ http {args} + + $ https {args} +''' + +# noinspection PyStringFormat +MSG_NAKED_INVOCATION = f'''\ +{missing_subcommand()} + +{MSG_COMMAND_CONFUSION} +'''.rstrip("\n").format(args='POST pie.dev/post hello=world') + + +def program(args: argparse.Namespace, env: Environment) -> ExitStatus: + if args.action is None: + parser.error(MSG_NAKED_INVOCATION) + + if args.action == 'plugins': + plugins = PluginInstaller(env, debug=args.debug) + return plugins.run(args.plugins_action, args) + + return ExitStatus.SUCCESS diff --git a/httpie/manager/plugins.py b/httpie/manager/plugins.py new file mode 100644 index 0000000000..77fc0d1234 --- /dev/null +++ b/httpie/manager/plugins.py @@ -0,0 +1,188 @@ +import argparse +import os +import subprocess +import sys +import textwrap +from collections import defaultdict +from contextlib import suppress +from pathlib import Path +from typing import Optional, List + +import importlib_metadata + +from httpie.manager.cli import parser, missing_subcommand +from httpie.compat import get_dist_name +from httpie.context import Environment +from httpie.status import ExitStatus + + +class PluginInstaller: + + def __init__(self, env: Environment, debug: bool = False) -> None: + self.env = env + self.dir = env.config.plugins_dir + self.debug = debug + + self.setup_plugins_dir() + + def setup_plugins_dir(self) -> None: + try: + self.dir.mkdir( + exist_ok=True, + parents=True + ) + except OSError: + self.env.stderr.write( + f'Couldn\'t create "{self.dir!s}"' + ' directory for plugin installation.' + ' Please re-check the permissions for that directory,' + ' and if needed, allow write-access.' + ) + raise + + def fail( + self, + command: str, + target: Optional[str] = None, + reason: Optional[str] = None + ) -> ExitStatus: + message = f'Can\'t {command}' + if target: + message += f' {target!r}' + if reason: + message += f': {reason}' + + self.env.stderr.write(message + '\n') + return ExitStatus.ERROR + + def pip(self, *args, **kwargs) -> subprocess.CompletedProcess: + options = { + 'check': True, + 'shell': False, + 'stdout': self.env.stdout, + 'stderr': subprocess.PIPE, + } + options.update(kwargs) + + cmd = [sys.executable, '-m', 'pip', *args] + return subprocess.run( + cmd, + **options + ) + + def install(self, targets: List[str]) -> Optional[ExitStatus]: + self.env.stdout.write(f"Installing {', '.join(targets)}...\n") + self.env.stdout.flush() + + try: + self.pip( + 'install', + f'--prefix={self.dir}', + '--no-warn-script-location', + *targets, + ) + except subprocess.CalledProcessError as error: + reason = None + if error.stderr: + stderr = error.stderr.decode() + + if self.debug: + self.env.stderr.write('Command failed: ') + self.env.stderr.write(' '.join(error.cmd) + '\n') + self.env.stderr.write(textwrap.indent(' ', stderr)) + + last_line = stderr.strip().splitlines()[-1] + severity, _, message = last_line.partition(': ') + if severity == 'ERROR': + reason = message + + return self.fail('install', ', '.join(targets), reason) + + def _uninstall(self, target: str) -> Optional[ExitStatus]: + try: + distribution = importlib_metadata.distribution(target) + except importlib_metadata.PackageNotFoundError: + return self.fail('uninstall', target, 'package is not installed') + + base_dir = Path(distribution.locate_file('.')).resolve() + if self.dir not in base_dir.parents: + # If the package is installed somewhere else (e.g on the site packages + # of the real python interpreter), than that means this package is not + # installed through us. + return self.fail('uninstall', target, + 'package is not installed through httpie plugins' + ' interface') + + files = distribution.files + if files is None: + return self.fail('uninstall', target, 'couldn\'t locate the package') + + # TODO: Consider handling failures here (e.g if it fails, + # just rever the operation and leave the site-packages + # in a proper shape). + for file in files: + with suppress(FileNotFoundError): + os.unlink(distribution.locate_file(file)) + + metadata_path = getattr(distribution, '_path', None) + if ( + metadata_path + and metadata_path.exists() + and not any(metadata_path.iterdir()) + ): + metadata_path.rmdir() + + self.env.stdout.write(f'Successfully uninstalled {target}\n') + + def uninstall(self, targets: List[str]) -> ExitStatus: + # Unfortunately uninstall doesn't work with custom pip schemes. See: + # - https://github.com/pypa/pip/issues/5595 + # - https://github.com/pypa/pip/issues/4575 + # so we have to implement our own uninstalling logic. Which works + # on top of the importlib_metadata. + + exit_code = ExitStatus.SUCCESS + for target in targets: + exit_code |= self._uninstall(target) or ExitStatus.SUCCESS + return ExitStatus(exit_code) + + def list(self) -> None: + from httpie.plugins.registry import plugin_manager + + known_plugins = defaultdict(list) + + for entry_point in plugin_manager.iter_entry_points(self.dir): + ep_info = (entry_point.group, entry_point.name) + ep_name = get_dist_name(entry_point) or entry_point.module + known_plugins[ep_name].append(ep_info) + + for plugin, entry_points in known_plugins.items(): + self.env.stdout.write(plugin) + + version = importlib_metadata.version(plugin) + if version is not None: + self.env.stdout.write(f' ({version})') + self.env.stdout.write('\n') + + for group, entry_point in sorted(entry_points): + self.env.stdout.write(f' {entry_point} ({group})\n') + + def run( + self, + action: Optional[str], + args: argparse.Namespace, + ) -> ExitStatus: + from httpie.plugins.manager import enable_plugins + + if action is None: + parser.error(missing_subcommand('plugins')) + + with enable_plugins(self.dir): + if action == 'install': + status = self.install(args.targets) + elif action == 'uninstall': + status = self.uninstall(args.targets) + elif action == 'list': + status = self.list() + + return status or ExitStatus.SUCCESS diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index 420fb36bf2..1b188e5790 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -1,24 +1,55 @@ +import sys +import os + from itertools import groupby from operator import attrgetter -from typing import Dict, List, Type +from typing import Dict, List, Type, Iterator, TypeVar, Optional, ContextManager +from pathlib import Path +from contextlib import contextmanager -from pkg_resources import iter_entry_points +from ..compat import importlib_metadata, find_entry_points, get_dist_name -from ..utils import repr_dict -from . import AuthPlugin, ConverterPlugin, FormatterPlugin -from .base import BasePlugin, TransportPlugin +from ..utils import repr_dict, as_site +from . import AuthPlugin, ConverterPlugin, FormatterPlugin, TransportPlugin +from .base import BasePlugin -ENTRY_POINT_NAMES = [ - 'httpie.plugins.auth.v1', - 'httpie.plugins.formatter.v1', - 'httpie.plugins.converter.v1', - 'httpie.plugins.transport.v1', -] +ENTRY_POINT_CLASSES = { + 'httpie.plugins.auth.v1': AuthPlugin, + 'httpie.plugins.converter.v1': ConverterPlugin, + 'httpie.plugins.formatter.v1': FormatterPlugin, + 'httpie.plugins.transport.v1': TransportPlugin +} +ENTRY_POINT_NAMES = list(ENTRY_POINT_CLASSES.keys()) -class PluginManager(list): +@contextmanager +def _load_directory(plugins_dir: Path) -> Iterator[None]: + plugins_path = os.fspath(plugins_dir) + sys.path.insert(0, plugins_path) + try: + yield + finally: + sys.path.remove(plugins_path) + + +T = TypeVar("T") + + +@contextmanager +def nullcontext(obj: Optional[T] = None) -> Iterator[Optional[T]]: + # A naive replacement of the nullcontext() for 3.6 + yield obj + +def enable_plugins(plugins_dir: Optional[Path]) -> ContextManager[None]: + if plugins_dir is None: + return nullcontext() + else: + return _load_directory(as_site(plugins_dir)) + + +class PluginManager(list): def register(self, *plugins: Type[BasePlugin]): for plugin in plugins: self.append(plugin) @@ -29,12 +60,18 @@ def unregister(self, plugin: Type[BasePlugin]): def filter(self, by_type=Type[BasePlugin]): return [plugin for plugin in self if issubclass(plugin, by_type)] - def load_installed_plugins(self): - for entry_point_name in ENTRY_POINT_NAMES: - for entry_point in iter_entry_points(entry_point_name): - plugin = entry_point.load() - plugin.package_name = entry_point.dist.key - self.register(entry_point.load()) + def iter_entry_points(self, directory: Optional[Path] = None): + with enable_plugins(directory): + eps = importlib_metadata.entry_points() + + for entry_point_name in ENTRY_POINT_NAMES: + yield from find_entry_points(eps, group=entry_point_name) + + def load_installed_plugins(self, directory: Optional[Path] = None): + for entry_point in self.iter_entry_points(directory): + plugin = entry_point.load() + plugin.package_name = get_dist_name(entry_point) + self.register(entry_point.load()) # Auth def get_auth_plugins(self) -> List[Type[AuthPlugin]]: diff --git a/httpie/ssl.py b/httpie/ssl_.py similarity index 100% rename from httpie/ssl.py rename to httpie/ssl_.py diff --git a/httpie/utils.py b/httpie/utils.py index f40625ad94..66f6e21d1e 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -3,8 +3,11 @@ import re import sys import time +import sysconfig + from collections import OrderedDict from http.cookiejar import parse_ns_headers +from pathlib import Path from pprint import pformat from typing import Any, List, Optional, Tuple @@ -207,3 +210,11 @@ def parse_content_type_header(header): value = param[index_of_equals + 1:].strip(items_to_strip) params_dict[key.lower()] = value return content_type, params_dict + + +def as_site(path: Path) -> Path: + site_packages_path = sysconfig.get_path( + 'purelib', + vars={'base': str(path)} + ) + return Path(site_packages_path) diff --git a/setup.py b/setup.py index 1238bfd31b..0269d5cedc 100644 --- a/setup.py +++ b/setup.py @@ -35,6 +35,7 @@ 'requests-toolbelt>=0.9.1', 'multidict>=4.7.0', 'setuptools', + 'importlib-metadata>=1.4.0', ] install_requires_win_only = [ 'colorama>=0.2.4', @@ -80,6 +81,7 @@ def long_description(): 'console_scripts': [ 'http = httpie.__main__:main', 'https = httpie.__main__:main', + 'httpie = httpie.manager.__main__:main', ], }, python_requires='>=3.6', diff --git a/tests/conftest.py b/tests/conftest.py index fe5f21165a..fa0b367a69 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,13 @@ from pytest_httpbin import certs from .utils import HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN, HTTPBIN_WITH_CHUNKED_SUPPORT +from .utils.plugins_cli import ( # noqa + dummy_plugin, + dummy_plugins, + httpie_plugins, + httpie_plugins_success, + interface, +) from .utils.http_server import http_server # noqa diff --git a/tests/test_plugins_cli.py b/tests/test_plugins_cli.py new file mode 100644 index 0000000000..39ee9c088f --- /dev/null +++ b/tests/test_plugins_cli.py @@ -0,0 +1,132 @@ +import pytest + +from httpie.status import ExitStatus +from tests.utils import httpie +from tests.utils.plugins_cli import parse_listing + + +def test_plugins_installation(httpie_plugins_success, interface, dummy_plugin): + lines = httpie_plugins_success('install', dummy_plugin.path) + assert lines[0].startswith( + f'Installing {dummy_plugin.path}' + ) + assert f'Successfully installed {dummy_plugin.name}-{dummy_plugin.version}' in lines + assert interface.is_installed(dummy_plugin.name) + + +def test_plugins_listing(httpie_plugins_success, interface, dummy_plugin): + httpie_plugins_success('install', dummy_plugin.path) + data = parse_listing(httpie_plugins_success('list')) + + assert data == { + dummy_plugin.name: dummy_plugin.dump() + } + + +def test_plugins_listing_multiple(interface, httpie_plugins_success, dummy_plugins): + paths = [plugin.path for plugin in dummy_plugins] + httpie_plugins_success('install', *paths) + data = parse_listing(httpie_plugins_success('list')) + + assert data == { + plugin.name: plugin.dump() + for plugin in dummy_plugins + } + + +def test_plugins_uninstall(interface, httpie_plugins_success, dummy_plugin): + httpie_plugins_success('install', dummy_plugin.path) + httpie_plugins_success('uninstall', dummy_plugin.name) + assert not interface.is_installed(dummy_plugin.name) + + +def test_plugins_listing_after_uninstall(interface, httpie_plugins_success, dummy_plugin): + httpie_plugins_success('install', dummy_plugin.path) + httpie_plugins_success('uninstall', dummy_plugin.name) + + data = parse_listing(httpie_plugins_success('list')) + assert len(data) == 0 + + +def test_plugins_uninstall_specific(interface, httpie_plugins_success): + new_plugin_1 = interface.make_dummy_plugin() + new_plugin_2 = interface.make_dummy_plugin() + target_plugin = interface.make_dummy_plugin() + + httpie_plugins_success('install', new_plugin_1.path, new_plugin_2.path, target_plugin.path) + httpie_plugins_success('uninstall', target_plugin.name) + + assert interface.is_installed(new_plugin_1.name) + assert interface.is_installed(new_plugin_2.name) + assert not interface.is_installed(target_plugin.name) + + +def test_plugins_installation_failed(httpie_plugins, interface): + plugin = interface.make_dummy_plugin(build=False) + result = httpie_plugins('install', plugin.path) + + assert result.exit_status == ExitStatus.ERROR + assert result.stderr.splitlines()[-1].strip().startswith("Can't install") + + +def test_plugins_uninstall_non_existent(httpie_plugins, interface): + plugin = interface.make_dummy_plugin(build=False) + result = httpie_plugins('uninstall', plugin.name) + + assert result.exit_status == ExitStatus.ERROR + assert ( + result.stderr.splitlines()[-1].strip() + == f"Can't uninstall '{plugin.name}': package is not installed" + ) + + +def test_plugins_double_uninstall(httpie_plugins, httpie_plugins_success, dummy_plugin): + httpie_plugins_success("install", dummy_plugin.path) + httpie_plugins_success("uninstall", dummy_plugin.name) + + result = httpie_plugins("uninstall", dummy_plugin.name) + + assert result.exit_status == ExitStatus.ERROR + assert ( + result.stderr.splitlines()[-1].strip() + == f"Can't uninstall '{dummy_plugin.name}': package is not installed" + ) + + +def test_plugins_cli_error_message_without_args(): + # No arguments + result = httpie(no_debug=True) + assert result.exit_status == ExitStatus.ERROR + assert 'usage: ' in result.stderr + assert 'specify one of these' in result.stderr + assert 'please use the http/https commands:' in result.stderr + + +@pytest.mark.parametrize( + 'example', [ + 'pie.dev/get', + 'DELETE localhost:8000/delete', + 'POST pie.dev/post header:value a=b header_2:value x:=1' + ] +) +def test_plugins_cli_error_messages_with_example(example): + result = httpie(*example.split(), no_debug=True) + assert result.exit_status == ExitStatus.ERROR + assert 'usage: ' in result.stderr + assert f'http {example}' in result.stderr + assert f'https {example}' in result.stderr + + +@pytest.mark.parametrize( + 'example', [ + 'plugins unknown', + 'plugins unknown.com A:B c=d', + 'unknown.com UNPARSABLE????SYNTAX', + ] +) +def test_plugins_cli_error_messages_invalid_example(example): + result = httpie(*example.split(), no_debug=True) + assert result.exit_status == ExitStatus.ERROR + assert 'usage: ' in result.stderr + assert f'http {example}' not in result.stderr + assert f'https {example}' not in result.stderr diff --git a/tests/test_ssl.py b/tests/test_ssl.py index e71924488a..f930bf2826 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -6,7 +6,7 @@ import requests.exceptions import urllib3 -from httpie.ssl import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS +from httpie.ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS from httpie.status import ExitStatus from .utils import HTTP_OK, TESTS_ROOT, http diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index 0877b9cad7..6f05b258a4 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -7,12 +7,14 @@ import tempfile from io import BytesIO from pathlib import Path -from typing import Optional, Union, List +from typing import Any, Optional, Union, List, Iterable + +import httpie.core as core +import httpie.manager.__main__ as manager from httpie.status import ExitStatus from httpie.config import Config from httpie.context import Environment -from httpie.core import main # pytest-httpbin currently does not support chunked requests: @@ -58,10 +60,10 @@ class MockEnvironment(Environment): stdout_isatty = True is_windows = False - def __init__(self, create_temp_config_dir=True, **kwargs): + def __init__(self, create_temp_config_dir=True, *, stdout_mode='b', **kwargs): if 'stdout' not in kwargs: kwargs['stdout'] = tempfile.TemporaryFile( - mode='w+b', + mode=f'w+{stdout_mode}', prefix='httpie_stdout' ) if 'stderr' not in kwargs: @@ -177,6 +179,46 @@ class ExitStatusError(Exception): pass +def normalize_args(args: Iterable[Any]) -> List[str]: + return [str(arg) for arg in args] + + +def httpie( + *args, + **kwargs +) -> StrCLIResponse: + """ + Run HTTPie manager command with the given + args/kwargs, and capture stderr/out and exit + status. + """ + + env = kwargs.setdefault('env', MockEnvironment()) + cli_args = ['httpie'] + if not kwargs.pop('no_debug', False): + cli_args.append('--debug') + cli_args += normalize_args(args) + exit_status = manager.main( + args=cli_args, + **kwargs + ) + + env.stdout.seek(0) + env.stderr.seek(0) + try: + response = StrCLIResponse(env.stdout.read()) + response.stderr = env.stderr.read() + response.exit_status = exit_status + response.args = cli_args + finally: + env.stdout.truncate(0) + env.stderr.truncate(0) + env.stdout.seek(0) + env.stderr.seek(0) + + return response + + def http( *args, program_name='http', @@ -254,7 +296,7 @@ def dump_stderr(): try: try: - exit_status = main(args=complete_args, **kwargs) + exit_status = core.main(args=complete_args, **kwargs) if '--download' in args: # Let the progress reporter thread finish. time.sleep(.5) diff --git a/tests/utils/plugins_cli.py b/tests/utils/plugins_cli.py new file mode 100644 index 0000000000..4e4d8a0764 --- /dev/null +++ b/tests/utils/plugins_cli.py @@ -0,0 +1,222 @@ +import secrets +import site +import sys +import textwrap + +import pytest + +from collections import defaultdict +from dataclasses import dataclass, field, asdict +from pathlib import Path +from typing import Any, List, Dict, Tuple +from unittest.mock import patch + +from httpie.context import Environment +from httpie.compat import importlib_metadata +from httpie.status import ExitStatus +from httpie.plugins.manager import ( + enable_plugins, + ENTRY_POINT_CLASSES as CLASSES, +) + + +def make_name() -> str: + return 'httpie-' + secrets.token_hex(4) + + +@dataclass +class EntryPoint: + name: str + group: str + + def dump(self) -> Dict[str, str]: + return asdict(self) + + +@dataclass +class Plugin: + interface: 'Interface' + + name: str = field(default_factory=make_name) + version: str = '1.0.0' + entry_points: List[EntryPoint] = field(default_factory=list) + + def build(self) -> None: + ''' + Create an installable dummy plugin at the given path. + + It will create a setup.py with the specified entry points, + as well as dummy classes in a python module to imitate + real plugins. + ''' + + groups = defaultdict(list) + for entry_point in self.entry_points: + groups[entry_point.group].append(entry_point.name) + + setup_eps = { + group: [ + f'{name} = {self.import_name}:{name.title()}' + for name in names + ] + for group, names in groups.items() + } + + self.path.mkdir(parents=True, exist_ok=True) + with open(self.path / 'setup.py', 'w') as stream: + stream.write(textwrap.dedent(f''' + from setuptools import setup + + setup( + name='{self.name}', + version='{self.version}', + py_modules=['{self.import_name}'], + entry_points={setup_eps!r}, + install_requires=['httpie'] + ) + ''')) + + with open(self.path / (self.import_name + '.py'), 'w') as stream: + stream.write('from httpie.plugins import *\n') + stream.writelines( + f'class {name.title()}({CLASSES[group].__name__}): ...\n' + for group, names in groups.items() + for name in names + ) + + def dump(self) -> Dict[str, Any]: + return { + 'version': self.version, + 'entry_points': [ + entry_point.dump() + for entry_point in self.entry_points + ] + } + + @property + def path(self) -> Path: + return self.interface.path / self.name + + @property + def import_name(self) -> str: + return self.name.replace('-', '_') + + +@dataclass +class Interface: + path: Path + environment: Environment + + def get_plugin(self, target: str) -> importlib_metadata.Distribution: + with enable_plugins(self.environment.config.plugins_dir): + return importlib_metadata.distribution(target) + + def is_installed(self, target: str) -> bool: + try: + self.get_plugin(target) + except ModuleNotFoundError: + return False + else: + return True + + def make_dummy_plugin(self, build=True, **kwargs) -> Plugin: + kwargs.setdefault('entry_points', [EntryPoint('test', 'httpie.plugins.auth.v1')]) + + plugin = Plugin(self, **kwargs) + if build: + plugin.build() + return plugin + + +def parse_listing(lines: List[str]) -> Dict[str, Any]: + plugins = {} + current_plugin = None + + def parse_entry_point(line: str) -> Tuple[str, str]: + entry_point, raw_group = line.strip().split() + return entry_point, raw_group[1:-1] + + def parse_plugin(line: str) -> Tuple[str, str]: + plugin, raw_version = line.strip().split() + return plugin, raw_version[1:-1] + + for line in lines: + if not line.strip(): + continue + + if line[0].isspace(): + # $entry_point ($group) + assert current_plugin is not None + entry_point, group = parse_entry_point(line) + plugins[current_plugin]['entry_points'].append({ + 'name': entry_point, + 'group': group + }) + else: + # $plugin ($version) + current_plugin, version = parse_plugin(line) + plugins[current_plugin] = { + 'version': version, + 'entry_points': [] + } + + return plugins + + +@pytest.fixture(scope='function') +def interface(tmp_path): + from tests.utils import MockEnvironment + + return Interface( + path=tmp_path / 'interface', + environment=MockEnvironment(stdout_mode='t') + ) + + +@pytest.fixture(scope='function') +def dummy_plugin(interface): + return interface.make_dummy_plugin() + + +@pytest.fixture(scope='function') +def dummy_plugins(interface): + # Multiple plugins with different configurations + return [ + interface.make_dummy_plugin(), + interface.make_dummy_plugin( + version='3.2.0' + ), + interface.make_dummy_plugin( + entry_points=[ + EntryPoint('test_1', 'httpie.plugins.converter.v1'), + EntryPoint('test_2', 'httpie.plugins.formatter.v1') + ] + ), + ] + + +@pytest.fixture +def httpie_plugins(interface): + from tests.utils import httpie + from httpie.plugins.registry import plugin_manager + + def runner(*args): + # Prevent installed plugins from showing up. + original_plugins = plugin_manager.copy() + clean_sys_path = set(sys.path).difference(site.getsitepackages()) + with patch('sys.path', list(clean_sys_path)): + response = httpie('plugins', *args, env=interface.environment) + plugin_manager.clear() + plugin_manager.extend(original_plugins) + return response + + return runner + + +@pytest.fixture +def httpie_plugins_success(httpie_plugins): + def runner(*args): + response = httpie_plugins(*args) + assert response.exit_status == ExitStatus.SUCCESS + return response.splitlines() + return runner From 3081fc1a3ce26bce3287a9ed23da6c50209546d2 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 30 Nov 2021 13:18:37 +0300 Subject: [PATCH 0915/1182] Add httpie --version (#1220) --- httpie/manager/cli.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/httpie/manager/cli.py b/httpie/manager/cli.py index 52a6764a13..eeeb24659b 100644 --- a/httpie/manager/cli.py +++ b/httpie/manager/cli.py @@ -1,5 +1,6 @@ from textwrap import dedent from httpie.cli.argparser import HTTPieManagerArgumentParser +from httpie import __version__ COMMANDS = { 'plugins': { @@ -90,4 +91,14 @@ def generate_subparsers(root, parent_parser, definitions): ''' ) +parser.add_argument( + '--version', + action='version', + version=__version__, + help=''' + Show version and exit. + + ''' +) + generate_subparsers(parser, parser, COMMANDS) From 5bf696d1137ed98acf3a31c69c726e090a07833b Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 30 Nov 2021 13:49:38 +0300 Subject: [PATCH 0916/1182] Fix packit CI (#1219) --- .packit.yaml | 3 ++- docs/packaging/linux-fedora/httpie.spec.txt | 3 +++ httpie/manager/plugins.py | 4 +--- setup.py | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.packit.yaml b/.packit.yaml index 4dfdb1a5a0..8fc33379d6 100644 --- a/.packit.yaml +++ b/.packit.yaml @@ -3,7 +3,8 @@ specfile_path: httpie.spec actions: # get the current Fedora Rawhide specfile: - post-upstream-clone: "wget https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec -O httpie.spec" + # post-upstream-clone: "wget https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec -O httpie.spec" + post-upstream-clone: "cp docs/packaging/linux-fedora/httpie.spec.txt httpie.spec" jobs: - job: copr_build trigger: pull_request diff --git a/docs/packaging/linux-fedora/httpie.spec.txt b/docs/packaging/linux-fedora/httpie.spec.txt index 8dc4e6b3df..b0ab5b7b3a 100644 --- a/docs/packaging/linux-fedora/httpie.spec.txt +++ b/docs/packaging/linux-fedora/httpie.spec.txt @@ -56,6 +56,7 @@ export PYTHONPATH=%{buildroot}%{python3_sitelib} mkdir -p %{buildroot}%{_mandir}/man1 help2man %{buildroot}%{_bindir}/http > %{buildroot}%{_mandir}/man1/http.1 help2man %{buildroot}%{_bindir}/https > %{buildroot}%{_mandir}/man1/https.1 +help2man %{buildroot}%{_bindir}/httpie > %{buildroot}%{_mandir}/man1/httpie.1 %check @@ -67,8 +68,10 @@ help2man %{buildroot}%{_bindir}/https > %{buildroot}%{_mandir}/man1/https.1 %license LICENSE %{_bindir}/http %{_bindir}/https +%{_bindir}/httpie %{_mandir}/man1/http.1* %{_mandir}/man1/https.1* +%{_mandir}/man1/httpie.1* # we co-own the entire directory structures for bash/fish completion to avoid a dependency %{_datadir}/bash-completion/ %{_datadir}/fish/ diff --git a/httpie/manager/plugins.py b/httpie/manager/plugins.py index 77fc0d1234..7760ce2357 100644 --- a/httpie/manager/plugins.py +++ b/httpie/manager/plugins.py @@ -8,10 +8,8 @@ from pathlib import Path from typing import Optional, List -import importlib_metadata - from httpie.manager.cli import parser, missing_subcommand -from httpie.compat import get_dist_name +from httpie.compat import importlib_metadata, get_dist_name from httpie.context import Environment from httpie.status import ExitStatus diff --git a/setup.py b/setup.py index 0269d5cedc..acec43b3b2 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ 'requests-toolbelt>=0.9.1', 'multidict>=4.7.0', 'setuptools', - 'importlib-metadata>=1.4.0', + 'importlib-metadata>=1.4.0; python_version < "3.8"', ] install_requires_win_only = [ 'colorama>=0.2.4', From 00b366a81f1a803bf2c769e3d41a6a7168f0d525 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 1 Dec 2021 20:37:57 +0300 Subject: [PATCH 0917/1182] Implement Bearer Auth (#1216) --- CHANGELOG.md | 1 + docs/README.md | 14 ++++++++++---- httpie/cli/definition.py | 7 ++++--- httpie/plugins/builtin.py | 21 +++++++++++++++++++++ httpie/plugins/registry.py | 3 ++- tests/test_auth.py | 13 +++++++++++++ 6 files changed, 51 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a48efcbd7a..0f2eed5b6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for receving multiple HTTP headers with the same name, individually. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for keeping `://` in the URL argument to allow quick conversions of pasted URLs into HTTPie calls just by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) +- Added support for `bearer` authentication method ([#1215](https://github.com/httpie/httpie/issues/1215)). ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) diff --git a/docs/README.md b/docs/README.md index de5d28e169..4db350093f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1003,10 +1003,10 @@ the [sessions](#sessions) feature. The currently supported authentication schemes are Basic and Digest (see [auth plugins](#auth-plugins) for more). There are two flags that control authentication: -| Flag | Arguments | -| ----------------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--auth, -a` | Pass a `username:password` pair as the argument. Or, if you only specify a username (`-a username`), you’ll be prompted for the password before the request is sent. To send an empty password, pass `username:`. The `username:password@hostname` URL syntax is supported as well (but credentials passed via `-a` have higher priority) | -| `--auth-type, -A` | Specify the auth mechanism. Possible values are `basic`, `digest`, or the name of any [auth plugins](#auth-plugins) you have installed. The default value is `basic` so it can often be omitted | +| Flag | Arguments | +| ----------------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--auth, -a` | Pass either a `username:password` pair or a `token` as the argument. If the selected authenticated method requires username/password combination and if you only specify a username (`-a username`), you’ll be prompted for the password before the request is sent. To send an empty password, pass `username:`. The `username:password@hostname` URL syntax is supported as well (but credentials passed via `-a` have higher priority) | +| `--auth-type, -A` | Specify the auth mechanism. Possible values are `basic`, `digest`, `bearer` or the name of any [auth plugins](#auth-plugins) you have installed. The default value is `basic` so it can often be omitted | ### Basic auth @@ -1020,6 +1020,12 @@ $ http -a username:password pie.dev/basic-auth/username/password $ http -A digest -a username:password pie.dev/digest-auth/httpie/username/password ``` +### Bearer auth + +```bash +https -A bearer -a token pie.dev/bearer +``` + ### Password prompt ```bash diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 98c45987d9..ca824918e0 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -554,10 +554,11 @@ auth.add_argument( '--auth', '-a', default=None, - metavar='USER[:PASS]', + metavar='USER[:PASS] | TOKEN', help=''' - If only the username is provided (-a username), HTTPie will prompt - for the password. + For username/password based authentication mechanisms (e.g + basic auth or digest auth) if only the username is provided + (-a username), HTTPie will prompt for the password. ''', ) diff --git a/httpie/plugins/builtin.py b/httpie/plugins/builtin.py index e93638224a..8a2dae615c 100644 --- a/httpie/plugins/builtin.py +++ b/httpie/plugins/builtin.py @@ -34,6 +34,16 @@ def make_header(username: str, password: str) -> str: return f'Basic {token}' +class HTTPBearerAuth(requests.auth.AuthBase): + + def __init__(self, token: str) -> None: + self.token = token + + def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + request.headers['Authorization'] = f'Bearer {self.token}' + return request + + class BasicAuthPlugin(BuiltinAuthPlugin): name = 'Basic HTTP auth' auth_type = 'basic' @@ -56,3 +66,14 @@ def get_auth( password: str ) -> requests.auth.HTTPDigestAuth: return requests.auth.HTTPDigestAuth(username, password) + + +class BearerAuthPlugin(BuiltinAuthPlugin): + name = 'Bearer HTTP Auth' + auth_type = 'bearer' + netrc_parse = False + auth_parse = False + + # noinspection PyMethodOverriding + def get_auth(self, **kwargs) -> requests.auth.HTTPDigestAuth: + return HTTPBearerAuth(self.raw_auth) diff --git a/httpie/plugins/registry.py b/httpie/plugins/registry.py index e03c70aaaa..de4fd0d8f5 100644 --- a/httpie/plugins/registry.py +++ b/httpie/plugins/registry.py @@ -1,5 +1,5 @@ from .manager import PluginManager -from .builtin import BasicAuthPlugin, DigestAuthPlugin +from .builtin import BasicAuthPlugin, DigestAuthPlugin, BearerAuthPlugin from ..output.formatters.headers import HeadersFormatter from ..output.formatters.json import JSONFormatter from ..output.formatters.xml import XMLFormatter @@ -13,6 +13,7 @@ plugin_manager.register( BasicAuthPlugin, DigestAuthPlugin, + BearerAuthPlugin, HeadersFormatter, JSONFormatter, XMLFormatter, diff --git a/tests/test_auth.py b/tests/test_auth.py index d3581a5f8b..219576a327 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -25,6 +25,19 @@ def test_digest_auth(httpbin_both, argument_name): assert r.json == {'authenticated': True, 'user': 'user'} +@pytest.mark.parametrize('token', [ + 'token_1', + 'long_token' * 5, + 'user:style', +]) +def test_bearer_auth(httpbin_both, token): + r = http('--auth-type', 'bearer', '--auth', token, + httpbin_both + '/bearer') + + assert HTTP_OK in r + assert r.json == {'authenticated': True, 'token': token} + + @mock.patch('httpie.cli.argtypes.AuthCredentials._getpass', new=lambda self, prompt: 'password') def test_password_prompt(httpbin): From ba8e4097e8fe357ccf37e5dde1cde16e3f76c911 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 1 Dec 2021 21:09:39 +0300 Subject: [PATCH 0918/1182] Support ==@ syntax for query parameter values from file (#1218) Co-authored-by: Vladimir Berkutov Co-authored-by: Vladimir Berkutov --- docs/README.md | 4 ++-- httpie/cli/constants.py | 3 +++ httpie/cli/requestitems.py | 10 +++++++++- tests/test_cli.py | 6 ++++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/docs/README.md b/docs/README.md index 4db350093f..18719c268e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -598,12 +598,12 @@ GET /../../etc/password HTTP/1.1 There are a few different *request item* types that provide a convenient mechanism for specifying HTTP headers, simple JSON and form data, files, and URL parameters. -They are key/value pairs specified after the URL. All have in common that they become part of the actual request that is sent and that their type is distinguished only by the separator used: `:`, `=`, `:=`, `==`, `@`, `=@`, and `:=@`. The ones with an `@` expect a file path as value. +They are key/value pairs specified after the URL. All have in common that they become part of the actual request that is sent and that their type is distinguished only by the separator used: `:`, `=`, `:=`, `==`, `@`, `=@`, `:=@` and `==@`. The ones with an `@` expect a file path as value. | Item Type | Description | | -----------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | HTTP Headers `Name:Value` | Arbitrary HTTP header, e.g. `X-API-Token:123` | -| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. | +| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. For reading the value from a file, use `==@`. | | Data Fields `field=value`, `field=@file.txt` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) | | Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:=[1,2,3]` (note the quotes) | | File upload fields `field@/dir/file`, `field@file;type=mime` | Only available with `--form`, `-f` and `--multipart`. For example `screenshot@~/Pictures/img.png`, or `'cv@cv.txt;type=text/markdown'`. With `--form`, the presence of a file field results in a `--multipart` request | diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index a1b78d33b2..42e4566c91 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -22,6 +22,7 @@ SEPARATOR_DATA_EMBED_FILE_CONTENTS = '=@' SEPARATOR_DATA_EMBED_RAW_JSON_FILE = ':=@' SEPARATOR_QUERY_PARAM = '==' +SEPARATOR_QUERY_EMBED_FILE = '==@' # Separators that become request data SEPARATOR_GROUP_DATA_ITEMS = frozenset({ @@ -40,6 +41,7 @@ # Separators for items whose value is a filename to be embedded SEPARATOR_GROUP_DATA_EMBED_ITEMS = frozenset({ + SEPARATOR_QUERY_EMBED_FILE, SEPARATOR_DATA_EMBED_FILE_CONTENTS, SEPARATOR_DATA_EMBED_RAW_JSON_FILE, }) @@ -55,6 +57,7 @@ SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY, SEPARATOR_QUERY_PARAM, + SEPARATOR_QUERY_EMBED_FILE, SEPARATOR_DATA_STRING, SEPARATOR_DATA_RAW_JSON, SEPARATOR_FILE_UPLOAD, diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index c91019439a..1c1f3b7d64 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -8,7 +8,7 @@ SEPARATOR_DATA_EMBED_RAW_JSON_FILE, SEPARATOR_DATA_RAW_JSON, SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD, SEPARATOR_FILE_UPLOAD_TYPE, SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY, - SEPARATOR_QUERY_PARAM, RequestType + SEPARATOR_QUERY_PARAM, SEPARATOR_QUERY_EMBED_FILE, RequestType ) from .dicts import ( BaseMultiDict, MultipartRequestDataDict, RequestDataDict, @@ -51,6 +51,10 @@ def from_args( process_query_param_arg, instance.params, ), + SEPARATOR_QUERY_EMBED_FILE: ( + process_embed_query_param_arg, + instance.params, + ), SEPARATOR_FILE_UPLOAD: ( process_file_upload_arg, instance.files, @@ -107,6 +111,10 @@ def process_query_param_arg(arg: KeyValueArg) -> str: return arg.value +def process_embed_query_param_arg(arg: KeyValueArg) -> str: + return load_text_file(arg).rstrip('\n') + + def process_file_upload_arg(arg: KeyValueArg) -> Tuple[str, IO, str]: parts = arg.value.split(SEPARATOR_FILE_UPLOAD_TYPE) filename = parts[0] diff --git a/tests/test_cli.py b/tests/test_cli.py index fd3f0dd0c1..a94ad85268 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -84,6 +84,7 @@ def test_valid_items(self): self.key_value_arg('file@' + FILE_PATH_ARG), self.key_value_arg('query==value'), self.key_value_arg('string-embed=@' + FILE_PATH_ARG), + self.key_value_arg('param-embed==@' + FILE_PATH_ARG), self.key_value_arg('raw-json-embed:=@' + JSON_FILE_PATH_ARG), ]) @@ -106,12 +107,13 @@ def test_valid_items(self): 'bool': True, 'list': ['a', 1, {}, False], 'obj': load_json_preserve_order_and_dupe_keys('{"a": "b"}'), - 'string-embed': FILE_CONTENT, + 'string-embed': FILE_CONTENT } # Parsed query string parameters assert items.params == { - 'query': 'value' + 'query': 'value', + 'param-embed': FILE_CONTENT.rstrip('\n') } # Parsed file fields From 151becec2bfbd6670c17db818300be35350c9be2 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 1 Dec 2021 21:15:59 +0300 Subject: [PATCH 0919/1182] Improve startup time with lazy loading some args (#1221) * Improve startup time with lazy loading some args * add some tests * Add changelog entry * Update CHANGELOG.md Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 1 + httpie/cli/definition.py | 67 ++++++++++++----------- httpie/cli/utils.py | 53 ++++++++++++++++++ httpie/output/formatters/colors.py | 11 ++-- tests/test_cli_utils.py | 86 ++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 34 deletions(-) create mode 100644 httpie/cli/utils.py create mode 100644 tests/test_cli_utils.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f2eed5b6b..e667bc2327 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for receving multiple HTTP headers with the same name, individually. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for keeping `://` in the URL argument to allow quick conversions of pasted URLs into HTTPie calls just by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) +- Improved startup time by 40% with lazily loading pygments plugins. ([#1211](https://github.com/httpie/httpie/pull/1211)) - Added support for `bearer` authentication method ([#1215](https://github.com/httpie/httpie/issues/1215)). ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index ca824918e0..abb44eeac1 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -19,8 +19,9 @@ SORTED_FORMAT_OPTIONS_STRING, UNSORTED_FORMAT_OPTIONS_STRING, ) +from .utils import LazyChoices from ..output.formatters.colors import ( - AUTO_STYLE, AVAILABLE_STYLES, DEFAULT_STYLE, + AUTO_STYLE, DEFAULT_STYLE, get_available_styles ) from ..plugins.builtin import BuiltinAuthPlugin from ..plugins.registry import plugin_manager @@ -41,6 +42,7 @@ '''), ) +parser.register('action', 'lazy_choices', LazyChoices) ####################################################################### # Positional arguments. @@ -247,32 +249,38 @@ ''' ) -output_processing.add_argument( - '--style', '-s', - dest='style', - metavar='STYLE', - default=DEFAULT_STYLE, - choices=sorted(AVAILABLE_STYLES), - help=''' - Output coloring style (default is "{default}"). It can be One of: + + +def format_style_help(available_styles): + return ''' + Output coloring style (default is "{default}"). It can be one of: {available_styles} 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_styles='\n'.join( f' {line.strip()}' - for line in wrap(', '.join(sorted(AVAILABLE_STYLES)), 60) + for line in wrap(', '.join(available_styles), 60) ).strip(), auto_style=AUTO_STYLE, ) + + +output_processing.add_argument( + '--style', '-s', + dest='style', + metavar='STYLE', + default=DEFAULT_STYLE, + action='lazy_choices', + getter=get_available_styles, + help_formatter=format_style_help ) + _sorted_kwargs = { 'action': 'append_const', 'const': SORTED_FORMAT_OPTIONS_STRING, @@ -564,27 +572,14 @@ ) -class _AuthTypeLazyChoices: - # Needed for plugin testing - - def __contains__(self, item): - return item in plugin_manager.get_auth_plugin_mapping() - - def __iter__(self): - return iter(sorted(plugin_manager.get_auth_plugin_mapping().keys())) - - -_auth_plugins = plugin_manager.get_auth_plugins() -auth.add_argument( - '--auth-type', '-A', - choices=_AuthTypeLazyChoices(), - default=None, - help=''' +def format_auth_help(auth_plugins_mapping): + auth_plugins = list(auth_plugins_mapping.values()) + return ''' The authentication mechanism to be used. Defaults to "{default}". {types} - '''.format(default=_auth_plugins[0].auth_type, types='\n '.join( + '''.format(default=auth_plugins[0].auth_type, types='\n '.join( '"{type}": {name}{package}{description}'.format( type=plugin.auth_type, name=plugin.name, @@ -597,8 +592,18 @@ def __iter__(self): '\n ' + ('\n '.join(wrap(plugin.description))) ) ) - for plugin in _auth_plugins - )), + for plugin in auth_plugins + )) + + +auth.add_argument( + '--auth-type', '-A', + action='lazy_choices', + default=None, + getter=plugin_manager.get_auth_plugin_mapping, + sort=True, + cache=False, + help_formatter=format_auth_help, ) auth.add_argument( '--ignore-netrc', diff --git a/httpie/cli/utils.py b/httpie/cli/utils.py new file mode 100644 index 0000000000..b2ffabdcaa --- /dev/null +++ b/httpie/cli/utils.py @@ -0,0 +1,53 @@ +import argparse +from typing import Any, Callable, Generic, Iterator, Iterable, Optional, TypeVar + +T = TypeVar('T') + + +class LazyChoices(argparse.Action, Generic[T]): + def __init__( + self, + *args, + getter: Callable[[], Iterable[T]], + help_formatter: Optional[Callable[[T], str]] = None, + sort: bool = False, + cache: bool = True, + **kwargs + ) -> None: + self.getter = getter + self.help_formatter = help_formatter + self.sort = sort + self.cache = cache + self._help: Optional[str] = None + self._obj: Optional[Iterable[T]] = None + super().__init__(*args, **kwargs) + self.choices = self + + def load(self) -> T: + if self._obj is None or not self.cache: + self._obj = self.getter() + + assert self._obj is not None + return self._obj + + @property + def help(self) -> str: + if self._help is None and self.help_formatter is not None: + self._help = self.help_formatter(self.load()) + return self._help + + @help.setter + def help(self, value: Any) -> None: + self._help = value + + def __contains__(self, item: Any) -> bool: + return item in self.load() + + def __iter__(self) -> Iterator[T]: + if self.sort: + return iter(sorted(self.load())) + else: + return iter(self.load()) + + def __call__(self, parser, namespace, values, option_string=None): + setattr(namespace, self.dest, values) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index d0187337b0..b2db70ff37 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -28,9 +28,14 @@ # great and fruity seems to give the best result there. DEFAULT_STYLE = 'fruity' -AVAILABLE_STYLES = set(pygments.styles.get_all_styles()) -AVAILABLE_STYLES.add(SOLARIZED_STYLE) -AVAILABLE_STYLES.add(AUTO_STYLE) +BUNDLED_STYLES = { + SOLARIZED_STYLE, + AUTO_STYLE +} + + +def get_available_styles(): + return BUNDLED_STYLES | set(pygments.styles.get_all_styles()) class ColorFormatter(FormatterPlugin): diff --git a/tests/test_cli_utils.py b/tests/test_cli_utils.py new file mode 100644 index 0000000000..2bc4d0a28e --- /dev/null +++ b/tests/test_cli_utils.py @@ -0,0 +1,86 @@ +import pytest +from argparse import ArgumentParser +from unittest.mock import Mock +from httpie.cli.utils import LazyChoices + + +def test_lazy_choices(): + mock = Mock() + getter = mock.getter + getter.return_value = ['a', 'b', 'c'] + + parser = ArgumentParser() + parser.register('action', 'lazy_choices', LazyChoices) + parser.add_argument( + '--option', + help="the regular option", + default='a', + metavar='SYMBOL', + choices=['a', 'b'], + ) + parser.add_argument( + '--lazy-option', + help="the lazy option", + default='a', + metavar='SYMBOL', + action='lazy_choices', + getter=getter, + cache=False # for test purposes + ) + + # Parser initalization doesn't call it. + getter.assert_not_called() + + # If we don't use --lazy-option, we don't retrieve it. + parser.parse_args([]) + getter.assert_not_called() + + parser.parse_args(['--option', 'b']) + getter.assert_not_called() + + # If we pass a value, it will retrieve to verify. + parser.parse_args(['--lazy-option', 'c']) + getter.assert_called() + getter.reset_mock() + + with pytest.raises(SystemExit): + parser.parse_args(['--lazy-option', 'z']) + getter.assert_called() + getter.reset_mock() + + +def test_lazy_choices_help(): + mock = Mock() + getter = mock.getter + getter.return_value = ['a', 'b', 'c'] + + help_formatter = mock.help_formatter + help_formatter.return_value = '' + + parser = ArgumentParser() + parser.register('action', 'lazy_choices', LazyChoices) + parser.add_argument( + '--lazy-option', + default='a', + metavar='SYMBOL', + action='lazy_choices', + getter=getter, + help_formatter=help_formatter, + cache=False # for test purposes + ) + + # Parser initalization doesn't call it. + getter.assert_not_called() + + # If we don't use `--help`, we don't use it. + parser.parse_args([]) + getter.assert_not_called() + help_formatter.assert_not_called() + + parser.parse_args(['--lazy-option', 'b']) + help_formatter.assert_not_called() + + # If we use --help, then we call it with styles + with pytest.raises(SystemExit): + parser.parse_args(['--help']) + help_formatter.assert_called_once_with(['a', 'b', 'c']) From f927065416d70cfc417eb3f6804b38b046b5b7a7 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 1 Dec 2021 21:19:38 +0300 Subject: [PATCH 0920/1182] brew: add multidict (#1222) --- docs/packaging/brew/brew-deps.py | 1 + docs/packaging/brew/httpie.rb | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/docs/packaging/brew/brew-deps.py b/docs/packaging/brew/brew-deps.py index 5a7b711ff2..3e45683942 100755 --- a/docs/packaging/brew/brew-deps.py +++ b/docs/packaging/brew/brew-deps.py @@ -31,6 +31,7 @@ 'requests', 'requests-toolbelt', 'urllib3', + 'multidict', ] diff --git a/docs/packaging/brew/httpie.rb b/docs/packaging/brew/httpie.rb index 6a01ca2300..a2a15d9371 100644 --- a/docs/packaging/brew/httpie.rb +++ b/docs/packaging/brew/httpie.rb @@ -63,6 +63,11 @@ class Httpie < Formula sha256 "4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece" end + resource "multidict" do + url "https://files.pythonhosted.org/packages/8e/7c/e12a69795b7b7d5071614af2c691c97fbf16a2a513c66ec52dd7d0a115bb/multidict-5.2.0.tar.gz" + sha256 "0dd1c93edb444b33ba2274b66f63def8a327d607c6c790772f448a53b6ea59ce" + end + def install virtualenv_install_with_resources end From 6522ce06d0de0281758d7b697460f1497346a9aa Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 1 Dec 2021 21:20:16 +0300 Subject: [PATCH 0921/1182] Add plugin management changelog entry (#1223) * Add plugin management changelog entry * Update CHANGELOG.md Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e667bc2327..adaa11f1a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.7.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) +- Add `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/httpie/issues/566)) - Added support for sending multiple HTTP headers with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) - Added support for receving multiple HTTP headers with the same name, individually. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for keeping `://` in the URL argument to allow quick conversions of pasted URLs into HTTPie calls just by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) From 840f77d2a8077571f7b4561df0df62e865f5740f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 1 Dec 2021 20:44:04 +0100 Subject: [PATCH 0922/1182] Tweak changelog & `3.0.0.dev0` --- CHANGELOG.md | 6 +++--- httpie/__init__.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adaa11f1a9..9609489380 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,15 +3,15 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). -## [2.7.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) +## [3.0.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) -- Add `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/httpie/issues/566)) +- Added `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/httpie/issues/566)) - Added support for sending multiple HTTP headers with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) - Added support for receving multiple HTTP headers with the same name, individually. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for keeping `://` in the URL argument to allow quick conversions of pasted URLs into HTTPie calls just by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) -- Improved startup time by 40% with lazily loading pygments plugins. ([#1211](https://github.com/httpie/httpie/pull/1211)) - Added support for `bearer` authentication method ([#1215](https://github.com/httpie/httpie/issues/1215)). +- Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) diff --git a/httpie/__init__.py b/httpie/__init__.py index a9e24edf40..0fdea0c474 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '2.7.0.dev0' +__version__ = '3.0.0.dev0' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 3457806df1ae583fe77f73f11cf3c1d45055f7a9 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 1 Dec 2021 20:45:54 +0100 Subject: [PATCH 0923/1182] CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9609489380..8624e16fc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,13 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [3.0.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) +- Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) - Added `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/httpie/issues/566)) - Added support for sending multiple HTTP headers with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) - Added support for receving multiple HTTP headers with the same name, individually. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for keeping `://` in the URL argument to allow quick conversions of pasted URLs into HTTPie calls just by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) - Added support for `bearer` authentication method ([#1215](https://github.com/httpie/httpie/issues/1215)). -- Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) From 521ddde4c5a0ae98dfe85035cf297105b43146df Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 1 Dec 2021 20:49:03 +0100 Subject: [PATCH 0924/1182] CHANGELOG.md --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8624e16fc5..11b8698b3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,11 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) - Added `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/httpie/issues/566)) -- Added support for sending multiple HTTP headers with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) -- Added support for receving multiple HTTP headers with the same name, individually. ([#1207](https://github.com/httpie/httpie/issues/1207)) -- Added support for keeping `://` in the URL argument to allow quick conversions of pasted URLs into HTTPie calls just by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) +- Added support for Bearer authentication via `--auth-type=bearer` ([#1215](https://github.com/httpie/httpie/issues/1215)). +- Added support for keeping `://` in the URL argument for quick conversions of pasted URLs into HTTPie calls by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) +- Added support for _sending_ multiple HTTP header lines with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) +- Added support for _receiving_ multiple HTTP headers lines with the same name. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) -- Added support for `bearer` authentication method ([#1215](https://github.com/httpie/httpie/issues/1215)). ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) From 8fe1f08a37e6ae164af68c9fc5c53c76fc7640af Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 1 Dec 2021 20:51:00 +0100 Subject: [PATCH 0925/1182] Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11b8698b3b..e29fc049a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) - Added `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/httpie/issues/566)) - Added support for Bearer authentication via `--auth-type=bearer` ([#1215](https://github.com/httpie/httpie/issues/1215)). -- Added support for keeping `://` in the URL argument for quick conversions of pasted URLs into HTTPie calls by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) +- Added support for quick conversions of pasted URLs into HTTPie calls by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) - Added support for _sending_ multiple HTTP header lines with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) - Added support for _receiving_ multiple HTTP headers lines with the same name. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) From df58ec683e4f574507ea944d95ed1749941aee95 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 3 Dec 2021 13:17:45 +0300 Subject: [PATCH 0926/1182] Add nested JSON syntax to the HTTPie DSL (#1224) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add support for nested JSON syntax (#1169) Co-authored-by: Batuhan Taskaya Co-authored-by: Jakub Roztocil * minor improvements * unpack top level lists * Write more docs * doc style changes * fix double quotes Co-authored-by: Mickaël Schoentgen Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 1 + docs/README.md | 243 ++++++++++++++++++++++++++++++++++++- httpie/cli/constants.py | 6 +- httpie/cli/definition.py | 2 +- httpie/cli/json_form.py | 150 +++++++++++++++++++++++ httpie/cli/requestitems.py | 28 ++++- httpie/client.py | 7 ++ httpie/utils.py | 13 +- tests/test_cli.py | 6 +- tests/test_json.py | 57 +++++++++ tests/utils/__init__.py | 2 +- 11 files changed, 503 insertions(+), 12 deletions(-) create mode 100644 httpie/cli/json_form.py diff --git a/CHANGELOG.md b/CHANGELOG.md index e29fc049a1..b35073a867 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [3.0.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) - Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) +- Added support for nested JSON syntax. ([#1169](https://github.com/httpie/httpie/issues/1169)) - Added `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/httpie/issues/566)) - Added support for Bearer authentication via `--auth-type=bearer` ([#1215](https://github.com/httpie/httpie/issues/1215)). - Added support for quick conversions of pasted URLs into HTTPie calls by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) diff --git a/docs/README.md b/docs/README.md index 18719c268e..5fd320db97 100644 --- a/docs/README.md +++ b/docs/README.md @@ -714,6 +714,246 @@ The `:=`/`:=@` syntax is JSON-specific. You can switch your request to `--form` and string, float, and number values will continue to be serialized (as string form values). Other JSON types, however, are not allowed with `--form` or `--multipart`. +### Nested JSON fields + +For creating nested JSON structures, you can simply declare the path for the object's new destination +and HTTPie will interpret it according to the [JSON form](https://www.w3.org/TR/html-json-forms/) +notation and create your object. It works directly with the existing data field (`=`) and raw JSON +field (`:=`) operators. + +#### Path Declaration + +A simple path can be a shallow key; + +```bash +$ http --offline --print=B pie.dev/post \ + type=success +``` + +```json +{ + "type": "success" +} +``` + +As well as a nested one, + +```bash +$ http --offline --print=B pie.dev/post \ + result[type]=success +``` + +```json +{ + "result": {"type": "success"} +} +``` + +Or even multiple levels of nesting. + +```bash +$ http --offline --print=B pie.dev/post \ + result[status][type]=ok +``` + +```json +{ + "result": { + "status": { + "type": "ok" + } + } +} +``` + +The declaration also supports creating arrays; which can be either done by simply +assigning the same path multiple times + +```bash +$ http --offline --print=B pie.dev/post \ + ids:=1 ids:=2 +``` + +```json +{ + "ids": [ + 1, + 2 + ] +} +``` + +Or using the append suffix `[]`, which would create an array and append the items to the +end of it. + +```bash +$ http --offline --print=B pie.dev/post \ + ids[]:=1 +``` + +```json +{ + "ids": [ + 1, + 2 + ] +} +``` + +You can also use indexes to set items on an array, + +```bash +$ http --offline --print=B pie.dev/post \ + items[0]=terminal items[1]=desktop +``` + +```json +{ + "items": [ + "terminal", + "desktop" + ] +} +``` + +If you don't set value for the indexes between, then those will be nullified. + +```bash +$ http --offline --print=B pie.dev/post \ + items[1]=terminal items[3]=desktop +``` + +```json +{ + "items": [ + null, + "terminal", + null, + "desktop" + ] +} +``` + +It is permitted to mix index-access with append actions (`[]`), but be aware that appends will not fill +the voids but instead they will append after the last item. + +```bash +$ http --offline --print=B pie.dev/post \ + items[1]=terminal items[3]=desktop items[]=web +``` + +```json +{ + "items": [ + null, + "terminal", + null, + "desktop", + "web" + ] +} +``` + +If you need to send a top-level list (without any object that is encapsulating it), use the append operator (`[]`) without +any keys. + +```bash +$ http --offline --print=B pie.dev/post \ + []:=1 []:=2 []:=3 +``` + +```json +[ + 1, + 2, + 3 +] +``` + +Here is a slightly unified example + +```bash +$ http --offline --print=B pie.dev/post name=python version:=3 \ + date[year]:=2021 date[month]=December \ + systems=Linux systems=Mac systems=Windows \ + people[known_ids][1]=1000 people[known_ids][5]=5000 +``` + +```json +{ + "date": { + "month": "December", + "year": 2021 + }, + "name": "python", + "people": { + "known_ids": [ + null, + "1000", + null, + null, + null, + "5000" + ] + }, + "systems": [ + "Linux", + "Mac", + "Windows" + ], + "version": 3 +} +``` + +And here is an even more comprehensive example to show all the features. + +```bash +$ http PUT pie.dev/put \ + 'object=scalar' \ # Object — blank key + 'object[0]=array 1' \ # Object — "0" key + 'object[key]=key key' \ # Object — "key" key + 'array:=1' \ # Array — first item + 'array:=2' \ # Array — second item + 'array[]:=3' \ # Array — append (third item) + 'wow[such][deep][3][much][power][!]=Amaze' # Nested object +``` + +```http +PUT /person/1 HTTP/1.1 +Accept: application/json, */*;q=0.5 +Content-Type: application/json +Host: pie.dev + +{ + "array": [ + 1, + 2, + 3 + ], + "object": { + "": "scalar", + "0": "array 1", + "key": "key key" + }, + "wow": { + "such": { + "deep": [ + null, + null, + null, + { + "much": { + "power": { + "!": "Amaze" + } + } + } + ] + } + } +} +``` + ### Raw and complex JSON Please note that with the [request items](#request-items) data field syntax, commands can quickly become unwieldy when sending complex structures. @@ -731,9 +971,6 @@ $ http --raw '{"hello": "world"}' POST pie.dev/post $ http POST pie.dev/post < files/data.json ``` -Furthermore, the structure syntax only allows you to send an object as the JSON document, but not an array, etc. -Here, again, the solution is to use [redirected input](#redirected-input). - ## Forms Submitting forms is very similar to sending [JSON](#json) requests. diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index 42e4566c91..577b7ba38f 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -46,10 +46,10 @@ SEPARATOR_DATA_EMBED_RAW_JSON_FILE, }) -# Separators for raw JSON items -SEPARATOR_GROUP_RAW_JSON_ITEMS = frozenset([ +# Separators for nested JSON items +SEPARATOR_GROUP_NESTED_JSON_ITEMS = frozenset([ + SEPARATOR_DATA_STRING, SEPARATOR_DATA_RAW_JSON, - SEPARATOR_DATA_EMBED_RAW_JSON_FILE, ]) # Separators allowed in ITEM arguments diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index abb44eeac1..e95e5d43c5 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -120,7 +120,7 @@ '=@' A data field like '=', but takes a file path and embeds its content: - essay=@Documents/essay.txt + essay=@Documents/essay.txt ':=@' A raw JSON field like ':=', but takes a file path and embeds its content: diff --git a/httpie/cli/json_form.py b/httpie/cli/json_form.py new file mode 100644 index 0000000000..9263e5cb12 --- /dev/null +++ b/httpie/cli/json_form.py @@ -0,0 +1,150 @@ +""" +Routines for JSON form syntax, used to support nested JSON request items. + +Highly inspired from the great jarg project . +""" +import re +import operator +from typing import Optional + + +def step(value: str, is_escaped: bool) -> str: + if is_escaped: + value = value.replace(r'\[', '[').replace(r'\]', ']') + return value + + +def find_opening_bracket( + value: str, + search=re.compile(r'(? Optional[int]: + match = search(value) + if not match: + return None + return match.start() + + +def find_closing_bracket( + value: str, + search=re.compile(r'(? Optional[int]: + match = search(value) + if not match: + return None + return match.start() + + +def parse_path(path): + """ + Parse a string as a JSON path. + + An implementation of 'steps to parse a JSON encoding path'. + + + """ + original = path + is_escaped = r'\[' in original + + opening_bracket = find_opening_bracket(original) + last_step = [(step(path, is_escaped), {'last': True, 'type': 'object'})] + if opening_bracket is None: + return last_step + + steps = [(step(original[:opening_bracket], is_escaped), {'type': 'object'})] + path = original[opening_bracket:] + while path: + if path.startswith('[]'): + steps[-1][1]['append'] = True + path = path[2:] + if path: + return last_step + elif path[0] == '[': + path = path[1:] + closing_bracket = find_closing_bracket(path) + if closing_bracket is None: + return last_step + key = path[:closing_bracket] + path = path[closing_bracket + 1:] + try: + steps.append((int(key), {'type': 'array'})) + except ValueError: + steps.append((key, {'type': 'object'})) + elif path[:2] == r'\[': + key = step(path[1:path.index(r'\]') + 2], is_escaped) + path = path[path.index(r'\]') + 2:] + steps.append((key, {'type': 'object'})) + else: + return last_step + + for i in range(len(steps) - 1): + steps[i][1]['type'] = steps[i + 1][1]['type'] + steps[-1][1]['last'] = True + return steps + + +def set_value(context, step, current_value, entry_value): + """Apply a JSON value to a context object. + + An implementation of 'steps to set a JSON encoding value'. + + + """ + key, flags = step + if flags.get('last', False): + if current_value is None: + if flags.get('append', False): + context[key] = [entry_value] + else: + if isinstance(context, list) and len(context) <= key: + context.extend([None] * (key - len(context) + 1)) + context[key] = entry_value + elif isinstance(current_value, list): + context[key].append(entry_value) + else: + context[key] = [current_value, entry_value] + return context + + if current_value is None: + if flags.get('type') == 'array': + context[key] = [] + else: + if isinstance(context, list) and len(context) <= key: + context.extend([None] * (key - len(context) + 1)) + context[key] = {} + return context[key] + elif isinstance(current_value, dict): + return context[key] + elif isinstance(current_value, list): + if flags.get('type') == 'array': + return current_value + + obj = {} + for i, item in enumerate(current_value): + if item is not None: + obj[i] = item + else: + context[key] = obj + return obj + else: + obj = {'': current_value} + context[key] = obj + return obj + + +def interpret_json_form(pairs): + """The application/json form encoding algorithm. + + + + """ + result = {} + for key, value in pairs: + steps = parse_path(key) + context = result + for step in steps: + try: + current_value = operator.getitem(context, step[0]) + except LookupError: + current_value = None + context = set_value(context, step, current_value, value) + return result diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index 1c1f3b7d64..a275e7c67e 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -5,7 +5,7 @@ from .argtypes import KeyValueArg from .constants import ( SEPARATORS_GROUP_MULTIPART, SEPARATOR_DATA_EMBED_FILE_CONTENTS, - SEPARATOR_DATA_EMBED_RAW_JSON_FILE, + SEPARATOR_DATA_EMBED_RAW_JSON_FILE, SEPARATOR_GROUP_NESTED_JSON_ITEMS, SEPARATOR_DATA_RAW_JSON, SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD, SEPARATOR_FILE_UPLOAD_TYPE, SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY, SEPARATOR_QUERY_PARAM, SEPARATOR_QUERY_EMBED_FILE, RequestType @@ -16,7 +16,8 @@ RequestQueryParamsDict, ) from .exceptions import ParseError -from ..utils import get_content_type, load_json_preserve_order_and_dupe_keys +from .json_form import interpret_json_form +from ..utils import get_content_type, load_json_preserve_order_and_dupe_keys, split class RequestItems: @@ -67,6 +68,10 @@ def from_args( process_data_embed_file_contents_arg, instance.data, ), + SEPARATOR_GROUP_NESTED_JSON_ITEMS: ( + process_data_nested_json_embed_args, + instance.data, + ), SEPARATOR_DATA_RAW_JSON: ( json_only(instance, process_data_raw_json_embed_arg), instance.data, @@ -77,6 +82,21 @@ def from_args( ), } + if instance.is_json: + json_item_args, request_item_args = split( + request_item_args, + lambda arg: arg.sep in SEPARATOR_GROUP_NESTED_JSON_ITEMS + ) + if json_item_args: + pairs = [ + (arg.key, rules[arg.sep][0](arg)) + for arg in json_item_args + ] + processor_func, target_dict = rules[SEPARATOR_GROUP_NESTED_JSON_ITEMS] + value = processor_func(pairs) + target_dict.update(value) + + # Then handle all other items. for arg in request_item_args: processor_func, target_dict = rules[arg.sep] value = processor_func(arg) @@ -172,6 +192,10 @@ def process_data_raw_json_embed_arg(arg: KeyValueArg) -> JSONType: return value +def process_data_nested_json_embed_args(pairs) -> Dict[str, JSONType]: + return interpret_json_form(pairs) + + def load_text_file(item: KeyValueArg) -> str: path = item.value try: diff --git a/httpie/client.py b/httpie/client.py index 374e14fd23..ba0cc77332 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -287,6 +287,13 @@ def make_request_kwargs( data = args.data auto_json = data and not args.form if (args.json or auto_json) and isinstance(data, dict): + # Propagate the top-level list if there is only one + # item in the object, with an en empty key. + if len(data) == 1: + [(key, value)] = data.items() + if key == '' and isinstance(value, list): + data = value + if data: data = json.dumps(data) else: diff --git a/httpie/utils.py b/httpie/utils.py index 66f6e21d1e..8669de8caf 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -9,13 +9,14 @@ from http.cookiejar import parse_ns_headers from pathlib import Path from pprint import pformat -from typing import Any, List, Optional, Tuple +from typing import Any, List, Optional, Tuple, Callable, Iterable, TypeVar import requests.auth RE_COOKIE_SPLIT = re.compile(r', (?=[^ ;]+=)') Item = Tuple[str, Any] Items = List[Item] +T = TypeVar("T") class JsonDictPreservingDuplicateKeys(OrderedDict): @@ -218,3 +219,13 @@ def as_site(path: Path) -> Path: vars={'base': str(path)} ) return Path(site_packages_path) + + +def split(iterable: Iterable[T], key: Callable[[T], bool]) -> Tuple[List[T], List[T]]: + left, right = [], [] + for item in iterable: + if key(item): + left.append(item) + else: + right.append(item) + return left, right diff --git a/tests/test_cli.py b/tests/test_cli.py index a94ad85268..4bb627e916 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -79,6 +79,8 @@ def test_valid_items(self): self.key_value_arg('Empty-Header;'), self.key_value_arg('list:=["a", 1, {}, false]'), self.key_value_arg('obj:={"a": "b"}'), + self.key_value_arg(r'nested\[2\][a][]=1'), + self.key_value_arg('nested[2][a][]:=1'), self.key_value_arg('ed='), self.key_value_arg('bool:=true'), self.key_value_arg('file@' + FILE_PATH_ARG), @@ -105,7 +107,9 @@ def test_valid_items(self): 'ed': '', 'string': 'value', 'bool': True, - 'list': ['a', 1, {}, False], + 'list': ['a', 1, load_json_preserve_order_and_dupe_keys('{}'), False], + 'nested[2]': {'a': ['1']}, + 'nested': [None, None, {'a': [1]}], 'obj': load_json_preserve_order_and_dupe_keys('{"a": "b"}'), 'string-embed': FILE_CONTENT } diff --git a/tests/test_json.py b/tests/test_json.py index f19aa7e158..945bf4dcd6 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -152,3 +152,60 @@ def test_complex_json_arguments_with_non_json(httpbin, request_type, value): ) cm.match('Can\'t use complex JSON value types') + + +@pytest.mark.parametrize('input_json, expected_json', [ + # Examples taken from https://www.w3.org/TR/html-json-forms/ + ( + ['bottle-on-wall:=1', 'bottle-on-wall:=2', 'bottle-on-wall:=3'], + {'bottle-on-wall': [1, 2, 3]}, + ), + ( + ['pet[species]=Dahut', 'pet[name]:="Hypatia"', 'kids[1]=Thelma', 'kids[0]:="Ashley"'], + {'pet': {'species': 'Dahut', 'name': 'Hypatia'}, 'kids': ['Ashley', 'Thelma']}, + ), + ( + ['pet[0][species]=Dahut', 'pet[0][name]=Hypatia', 'pet[1][species]=Felis Stultus', 'pet[1][name]:="Billie"'], + {'pet': [{'species': 'Dahut', 'name': 'Hypatia'}, {'species': 'Felis Stultus', 'name': 'Billie'}]}, + ), + ( + ['wow[such][deep][3][much][power][!]=Amaze'], + {'wow': {'such': {'deep': [None, None, None, {'much': {'power': {'!': 'Amaze'}}}]}}}, + ), + ( + ['mix=scalar', 'mix[0]=array 1', 'mix[2]:="array 2"', 'mix[key]:="key key"', 'mix[car]=car key'], + {'mix': {'': 'scalar', '0': 'array 1', '2': 'array 2', 'key': 'key key', 'car': 'car key'}}, + ), + ( + ['highlander[]=one'], + {'highlander': ['one']}, + ), + ( + ['error[good]=BOOM!', 'error[bad:="BOOM BOOM!"'], + {'error': {'good': 'BOOM!'}, 'error[bad': 'BOOM BOOM!'}, + ), + ( + ['special[]:=true', 'special[]:=false', 'special[]:="true"', 'special[]:=null'], + {'special': [True, False, 'true', None]}, + ), + ( + [r'\[\]:=1', r'escape\[d\]:=1', r'escaped\[\]:=1', r'e\[s\][c][a][p]\[ed\][]:=1'], + {'[]': 1, 'escape[d]': 1, 'escaped[]': 1, 'e[s]': {'c': {'a': {'p': {'[ed]': [1]}}}}}, + ), + ( + ['[]:=1', '[]=foo'], + [1, 'foo'], + ), + ( + [']:=1', '[]1:=1', '[1]]:=1'], + {']': 1, '[]1': 1, '[1]]': 1}, + ), +]) +def test_nested_json_syntax(input_json, expected_json, httpbin_both): + r = http(httpbin_both + '/post', *input_json) + assert r.json['json'] == expected_json + + +def test_nested_json_sparse_array(httpbin_both): + r = http(httpbin_both + '/post', 'test[0]:=1', 'test[100]:=1') + assert len(r.json['json']['test']) == 101 diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index 6f05b258a4..f8954565c5 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -228,7 +228,7 @@ def http( # noinspection PyUnresolvedReferences """ Run HTTPie and capture stderr/out and exit status. - Content writtent to devnull will be captured only if + Content written to devnull will be captured only if env.devnull is set manually. Invoke `httpie.core.main()` with `args` and `kwargs`, From ea8e22677a321c230157e0e901210401c2040dc9 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 8 Dec 2021 12:20:58 +0300 Subject: [PATCH 0927/1182] Fix snapcraft packaging (#1235) --- snapcraft.yaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/snapcraft.yaml b/snapcraft.yaml index ce4fe79bbb..eb620c0e16 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -64,18 +64,13 @@ parts: python -m pip install httpie-unixsocket python -m pip install httpie-snapdsocket - echo "Removing no more needed modules ..." - python -m pip uninstall -y pip wheel - override-prime: | snapcraftctl prime echo "Removing useless files ..." packages=$SNAPCRAFT_PRIME/lib/python3.8/site-packages - rm -rfv $packages/_distutils_hack rm -rfv $packages/pkg_resources/tests rm -rfv $packages/requests_unixsocket/test* - rm -rfv $packages/setuptools echo "Compiling pyc files ..." python -m compileall -f $packages @@ -112,3 +107,9 @@ apps: completer: httpie-completion.bash environment: LC_ALL: C.UTF-8 + + httpie: + command: bin/httpie + plugs: *plugs + environment: + LC_ALL: C.UTF-8 From 62e43abc866ca164deed8bbf449b483fbdf66f52 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 8 Dec 2021 18:45:07 +0300 Subject: [PATCH 0928/1182] Ignore crashes that happen on the 3rd party plugins (#1228) * Ignore crashes that happen on the 3rd party plugins * Give a suggestion about how to uninstall --- CHANGELOG.md | 1 + httpie/plugins/manager.py | 17 ++++++++++++++--- tests/conftest.py | 1 + tests/test_plugins_cli.py | 22 ++++++++++++++++++++++ tests/utils/plugins_cli.py | 8 ++++++++ 5 files changed, 46 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b35073a867..7cdcbb195e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for _sending_ multiple HTTP header lines with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) - Added support for _receiving_ multiple HTTP headers lines with the same name. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) +- Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index 1b188e5790..6d78653fc7 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -1,5 +1,6 @@ import sys import os +import warnings from itertools import groupby from operator import attrgetter @@ -69,9 +70,19 @@ def iter_entry_points(self, directory: Optional[Path] = None): def load_installed_plugins(self, directory: Optional[Path] = None): for entry_point in self.iter_entry_points(directory): - plugin = entry_point.load() - plugin.package_name = get_dist_name(entry_point) - self.register(entry_point.load()) + plugin_name = get_dist_name(entry_point) + try: + plugin = entry_point.load() + except BaseException as exc: + warnings.warn( + f'While loading "{plugin_name}", an error ocurred: {exc}\n' + f'For uninstallations, please use either "httpie plugins uninstall {plugin_name}" ' + f'or "pip uninstall {plugin_name}" (depending on how you installed it in the first ' + 'place).' + ) + continue + plugin.package_name = plugin_name + self.register(plugin) # Auth def get_auth_plugins(self) -> List[Type[AuthPlugin]]: diff --git a/tests/conftest.py b/tests/conftest.py index fa0b367a69..5e8c511072 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,6 +6,7 @@ from .utils import HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN, HTTPBIN_WITH_CHUNKED_SUPPORT from .utils.plugins_cli import ( # noqa + broken_plugin, dummy_plugin, dummy_plugins, httpie_plugins, diff --git a/tests/test_plugins_cli.py b/tests/test_plugins_cli.py index 39ee9c088f..d644aba73d 100644 --- a/tests/test_plugins_cli.py +++ b/tests/test_plugins_cli.py @@ -93,6 +93,28 @@ def test_plugins_double_uninstall(httpie_plugins, httpie_plugins_success, dummy_ ) +def test_broken_plugins(httpie_plugins, httpie_plugins_success, dummy_plugin, broken_plugin): + httpie_plugins_success("install", dummy_plugin.path, broken_plugin.path) + + with pytest.warns( + UserWarning, + match=( + f'While loading "{broken_plugin.name}", an error' + ' ocurred: broken plugin' + ) + ): + data = parse_listing(httpie_plugins_success('list')) + assert len(data) == 2 + + # We load before the uninstallation, so it will warn again. + with pytest.warns(UserWarning): + httpie_plugins_success("uninstall", broken_plugin.name) + + # No warning now, since it is uninstalled. + data = parse_listing(httpie_plugins_success('list')) + assert len(data) == 1 + + def test_plugins_cli_error_message_without_args(): # No arguments result = httpie(no_debug=True) diff --git a/tests/utils/plugins_cli.py b/tests/utils/plugins_cli.py index 4e4d8a0764..a750e664b1 100644 --- a/tests/utils/plugins_cli.py +++ b/tests/utils/plugins_cli.py @@ -178,6 +178,14 @@ def dummy_plugin(interface): return interface.make_dummy_plugin() +@pytest.fixture(scope='function') +def broken_plugin(interface): + base_plugin = interface.make_dummy_plugin() + with open(base_plugin.path / (base_plugin.import_name + '.py'), 'a') as stream: + stream.write('raise ValueError("broken plugin")\n') + return base_plugin + + @pytest.fixture(scope='function') def dummy_plugins(interface): # Multiple plugins with different configurations From 207b970d9412f60b67328ffb4f0a8b23643d50ae Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 8 Dec 2021 18:49:12 +0300 Subject: [PATCH 0929/1182] Automatically enable --stream on server sent events (#1226) * Automatically enable --stream when used chunked encoding * try fix 3.6 mock issue * Only enable on text/event-stream Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 2 ++ httpie/output/writer.py | 13 +++++++++++-- tests/test_stream.py | 26 ++++++++++++++++++++++++++ tests/utils/http_server.py | 16 ++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cdcbb195e..5f040ab15d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for _sending_ multiple HTTP header lines with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) - Added support for _receiving_ multiple HTTP headers lines with the same name. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) +- Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376)) - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) + ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) [What’s new in HTTPie 2.6.0 →](https://httpie.io/blog/httpie-2.6.0) diff --git a/httpie/output/writer.py b/httpie/output/writer.py index 4650264db6..cd3eec979b 100644 --- a/httpie/output/writer.py +++ b/httpie/output/writer.py @@ -2,6 +2,7 @@ import errno from typing import IO, TextIO, Tuple, Type, Union +from ..cli.dicts import HTTPHeadersDict from ..context import Environment from ..models import ( HTTPRequest, @@ -110,6 +111,7 @@ def build_output_stream_for_message( env=env, args=args, message_type=message_type, + headers=requests_message.headers ) yield from stream_class( msg=message_type(requests_message), @@ -128,16 +130,23 @@ def get_stream_type_and_kwargs( env: Environment, args: argparse.Namespace, message_type: Type[HTTPMessage], + headers: HTTPHeadersDict, ) -> Tuple[Type['BaseStream'], dict]: """Pick the right stream type and kwargs for it based on `env` and `args`. """ + is_stream = args.stream + if not is_stream and message_type is HTTPResponse: + # If this is a response, then check the headers for determining + # auto-streaming. + is_stream = headers.get('Content-Type') == 'text/event-stream' + if not env.stdout_isatty and not args.prettify: stream_class = RawStream stream_kwargs = { 'chunk_size': ( RawStream.CHUNK_SIZE_BY_LINE - if args.stream + if is_stream else RawStream.CHUNK_SIZE ) } @@ -152,7 +161,7 @@ def get_stream_type_and_kwargs( 'encoding_overwrite': args.response_charset, }) if args.prettify: - stream_class = PrettyStream if args.stream else BufferedPrettyStream + stream_class = PrettyStream if is_stream else BufferedPrettyStream stream_kwargs.update({ 'conversion': Conversion(), 'formatting': Formatting( diff --git a/tests/test_stream.py b/tests/test_stream.py index 002b245af0..55e000a6dd 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -2,6 +2,7 @@ import pytest import responses +from unittest.mock import Mock from httpie.compat import is_windows from httpie.cli.constants import PRETTY_MAP @@ -107,3 +108,28 @@ def test_redirected_stream(httpbin): r = http('--pretty=none', '--stream', '--verbose', 'GET', httpbin.url + '/get', env=env) assert BIN_FILE_CONTENT in r + + +# /drip endpoint produces 3 individual lines, +# if we set text/event-stream HTTPie should stream +# it by default. Otherwise, it will buffer and then +# print. +@pytest.mark.parametrize('extras, expected', [ + ( + ['Accept:text/event-stream'], + 3 + ), + ( + ['Accept:text/plain'], + 1 + ) +]) +def test_auto_streaming(http_server, extras, expected): + env = MockEnvironment() + env.stdout.write = Mock() + http(http_server + '/drip', *extras, env=env) + assert len([ + call_arg + for call_arg in env.stdout.write.call_args_list + if b'test' in call_arg[0][0] + ]) == expected diff --git a/tests/utils/http_server.py b/tests/utils/http_server.py index 42be768b46..f09e06c2c2 100644 --- a/tests/utils/http_server.py +++ b/tests/utils/http_server.py @@ -36,6 +36,22 @@ def get_headers(handler): handler.end_headers() +@TestHandler.handler('GET', '/drip') +def chunked_drip(handler): + handler.send_response(200) + accept = handler.headers.get('Accept') + if accept is not None: + handler.send_header('Content-Type', accept) + handler.send_header('Transfer-Encoding', 'chunked') + handler.end_headers() + + for _ in range(3): + body = 'test\n' + handler.wfile.write(f'{len(body):X}\r\n{body}\r\n'.encode('utf-8')) + + handler.wfile.write('0\r\n\r\n'.encode('utf-8')) + + @pytest.fixture(scope="function") def http_server(): """A custom HTTP server implementation for our tests, that is From e30ec6be420e64bead86f7dfc9342801d8f921e8 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 9 Dec 2021 12:46:19 +0300 Subject: [PATCH 0930/1182] Remove unnecessary empty line in CHANGELOG --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f040ab15d..8e3b9a5f4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376)) - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) - ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) [What’s new in HTTPie 2.6.0 →](https://httpie.io/blog/httpie-2.6.0) From 4f7f59b990bbdf8edfdd7e357031c097678251c8 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 14 Dec 2021 18:05:25 +0300 Subject: [PATCH 0931/1182] Add initial benchmarking infrastructure (#1232) * Add initial benchmarking infrastructure * Add CI file * Try to comment on commits * Implement file download benchmarks! * drop commit comments (they dont work) * Allow running local binary * Better action * More docs! * Better look? * even better look * add pretty=all, none benchmarks --- .github/workflows/benchmark.yml | 52 ++++++ CONTRIBUTING.md | 14 ++ Makefile | 2 +- extras/profiling/benchmarks.py | 203 ++++++++++++++++++++++ extras/profiling/run.py | 287 ++++++++++++++++++++++++++++++++ 5 files changed, 557 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/benchmark.yml create mode 100644 extras/profiling/benchmarks.py create mode 100644 extras/profiling/run.py diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 0000000000..560835dab2 --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,52 @@ +name: Benchmark + +on: + pull_request: + types: [ labeled ] + +permissions: + issues: write + pull-requests: write + +jobs: + test: + if: github.event.label.name == 'benchmark' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: "3.9" + + - id: benchmarks + name: Run Benchmarks + run: | + python -m pip install pyperf>=2.3.0 + python extras/profiling/run.py --fresh --complex --min-speed=6 --file output.txt + body=$(cat output.txt) + body="${body//'%'/'%25'}" + body="${body//$'\n'/'%0A'}" + body="${body//$'\r'/'%0D'}" + echo "::set-output name=body::$body" + + - name: Find Comment + uses: peter-evans/find-comment@v1 + id: fc + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: '# Benchmarks' + + - name: Create or update comment + uses: peter-evans/create-or-update-comment@v1 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body: | + # Benchmarks + ${{ steps.benchmarks.outputs.body }} + edit-mode: replace + + - uses: actions-ecosystem/action-remove-labels@v1 + with: + labels: benchmark diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b015ca6fd..2eeac05d43 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -144,6 +144,20 @@ $ python -m pytest tests/test_uploads.py::TestMultipartFormDataFileUpload::test_ See [Makefile](https://github.com/httpie/httpie/blob/master/Makefile) for additional development utilities. +#### Running benchmarks + +If you are trying to work on speeding up HTTPie and want to verify your results, you +can run the benchmark suite. The suite will compare the last commit of your branch +with the master branch of your repository (or a fresh checkout of HTTPie master, through +`--fresh`) and report the results back. + +```bash +$ python extras/benchmarks/run.py +``` + +The benchmarks can also be run on the CI. Since it is a long process, it requires manual +oversight. Ping one of the maintainers to get a `benchmark` label on your branch. + #### Windows If you are on a Windows machine and not able to run `make`, diff --git a/Makefile b/Makefile index 2bcc269792..ed9ea9b982 100644 --- a/Makefile +++ b/Makefile @@ -130,7 +130,7 @@ pycodestyle: codestyle codestyle: @echo $(H1)Running flake8$(H1END) @[ -f $(VENV_BIN)/flake8 ] || $(VENV_PIP) install --upgrade --editable '.[dev]' - $(VENV_BIN)/flake8 httpie/ tests/ docs/packaging/brew/ *.py + $(VENV_BIN)/flake8 httpie/ tests/ extras/profiling/ docs/packaging/brew/ *.py @echo diff --git a/extras/profiling/benchmarks.py b/extras/profiling/benchmarks.py new file mode 100644 index 0000000000..50a53a5a9e --- /dev/null +++ b/extras/profiling/benchmarks.py @@ -0,0 +1,203 @@ +""" +This file is the declaration of benchmarks for HTTPie. It +is also used to run them with the current environment. + +Each instance of BaseRunner class will be an individual +benchmark. And if run without any arguments, this file +will execute every benchmark instance and report the +timings. + +The benchmarks are run through 'pyperf', which allows to +do get very precise results. For micro-benchmarks like startup, +please run `pyperf system tune` to get even more acurrate results. + +Examples: + + # Run everything as usual, the default is that we do 3 warmup runs + # and 5 actual runs. + $ python extras/profiling/benchmarks.py + + # For retrieving results faster, pass --fast + $ python extras/profiling/benchmarks.py --fast + + # For verify everything works as expected, pass --debug-single-value. + # It will only run everything once, so the resuls are not realiable. But + # very useful when iterating on a benchmark + $ python extras/profiling/benchmarks.py --debug-single-value + + # If you want to run with a custom HTTPie command (for example with + # and HTTPie instance installed in another virtual environment), + # pass HTTPIE_COMMAND variable. + $ HTTPIE_COMMAND="/my/python /my/httpie" python extras/profiling/benchmarks.py +""" + +from __future__ import annotations + +import os +import shlex +import subprocess +import sys +import threading +from contextlib import ExitStack, contextmanager +from dataclasses import dataclass, field +from functools import cached_property, partial +from http.server import HTTPServer, SimpleHTTPRequestHandler +from tempfile import TemporaryDirectory +from typing import ClassVar, Final, List + +import pyperf + +# For download benchmarks, define a set of files. +# file: (block_size, count) => total_size = block_size * count +PREDEFINED_FILES: Final = {'3G': (3 * 1024 ** 2, 1024)} + + +class QuietSimpleHTTPServer(SimpleHTTPRequestHandler): + def log_message(self, *args, **kwargs): + pass + + +@contextmanager +def start_server(): + """Create a server to serve local files. It will create the + PREDEFINED_FILES through dd.""" + with TemporaryDirectory() as directory: + for file_name, (block_size, count) in PREDEFINED_FILES.items(): + subprocess.check_call( + [ + 'dd', + 'if=/dev/zero', + f'of={file_name}', + f'bs={block_size}', + f'count={count}', + ], + cwd=directory, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + handler = partial(QuietSimpleHTTPServer, directory=directory) + server = HTTPServer(('localhost', 0), handler) + + thread = threading.Thread(target=server.serve_forever) + thread.start() + yield '{}:{}'.format(*server.socket.getsockname()) + server.shutdown() + thread.join(timeout=0.5) + + +@dataclass +class Context: + benchmarks: ClassVar[List[BaseRunner]] = [] + stack: ExitStack = field(default_factory=ExitStack) + runner: pyperf.Runner = field(default_factory=pyperf.Runner) + + def run(self) -> pyperf.BenchmarkSuite: + results = [benchmark.run(self) for benchmark in self.benchmarks] + return pyperf.BenchmarkSuite(results) + + @property + def cmd(self) -> List[str]: + if cmd := os.getenv('HTTPIE_COMMAND'): + return shlex.split(cmd) + + http = os.path.join(os.path.dirname(sys.executable), 'http') + assert os.path.exists(http) + return [sys.executable, http] + + @cached_property + def server(self) -> str: + return self.stack.enter_context(start_server()) + + def __enter__(self): + return self + + def __exit__(self, *exc_info): + self.stack.close() + + +@dataclass +class BaseRunner: + """ + An individual benchmark case. By default it has the category + (e.g like startup or download) and a name. + """ + + category: str + title: str + + def __post_init__(self): + Context.benchmarks.append(self) + + def run(self, context: Context) -> pyperf.Benchmark: + raise NotImplementedError + + @property + def name(self) -> str: + return f'{self.title} ({self.category})' + + +@dataclass +class CommandRunner(BaseRunner): + """ + Run a single command, and benchmark it. + """ + + args: List[str] + + def run(self, context: Context) -> pyperf.Benchmark: + return context.runner.bench_command(self.name, [*context.cmd, *self.args]) + + +@dataclass +class DownloadRunner(BaseRunner): + """ + Benchmark downloading a single file from the + remote server. + """ + + file_name: str + + def run(self, context: Context) -> pyperf.Benchmark: + return context.runner.bench_command( + self.name, + [ + *context.cmd, + '--download', + 'GET', + f'{context.server}/{self.file_name}', + ], + ) + + +CommandRunner('startup', '`http --version`', ['--version']) +CommandRunner('startup', '`http --offline pie.dev/get`', ['--offline', 'pie.dev/get']) +for pretty in ['all', 'none']: + CommandRunner( + 'startup', + f'`http --pretty={pretty} pie.dev/stream/1000`', + [ + '--print=HBhb', + '--stream', + f'--pretty={pretty}', + 'httpbin.org/stream/100' + ] + ) +DownloadRunner('download', '`http --download :/big_file.txt` (3GB)', '3G') + + +def main() -> None: + # PyPerf will bring it's own argument parser, so configure the script. + # The somewhat fast and also precise enough configuration is this. We run + # benchmarks 3 times to warmup (e.g especially for download benchmark, this + # is important). And then 5 actual runs where we record. + sys.argv.extend( + ['--worker', '--loops=1', '--warmup=3', '--values=5', '--processes=2'] + ) + + with Context() as context: + context.run() + + +if __name__ == '__main__': + main() diff --git a/extras/profiling/run.py b/extras/profiling/run.py new file mode 100644 index 0000000000..8691367316 --- /dev/null +++ b/extras/profiling/run.py @@ -0,0 +1,287 @@ +""" +Run the HTTPie benchmark suite with multiple environments. + +This script is configured in a way that, it will create +two (or more) isolated environments and compare the *last +commit* of this repository with it's master. + +> If you didn't commit yet, it won't be showing results. + +You can also pass --fresh, which would test the *last +commit* of this repository with a fresh copy of HTTPie +itself. This way even if you don't have an up-to-date +master branch, you can still compare it with the upstream's +master. + +You can also pass --complex to add 2 additional environments, +which would include additional dependencies like pyOpenSSL. + +Examples: + + # Run everything as usual, and compare last commit with master + $ python extras/benchmarks/run.py + + # Include complex environments + $ python extras/benchmarks/run.py --complex + + # Compare against a fresh copy + $ python extras/benchmarks/run.py --fresh + + # Compare against a custom branch of a custom repo + $ python extras/benchmarks/run.py --target-repo my_repo --target-branch my_branch + + # Debug changes made on this script (only run benchmarks once) + $ python extras/benchmarks/run.py --debug +""" + +import dataclasses +import shlex +import subprocess +import sys +import tempfile +import venv +from argparse import ArgumentParser, FileType +from contextlib import contextmanager +from dataclasses import dataclass +from pathlib import Path +from typing import (IO, Dict, Generator, Iterable, List, Optional, + Tuple) + +BENCHMARK_SCRIPT = Path(__file__).parent / 'benchmarks.py' +CURRENT_REPO = Path(__file__).parent.parent.parent + +GITHUB_URL = 'https://github.com/httpie/httpie.git' +TARGET_BRANCH = 'master' + +# Additional dependencies for --complex +ADDITIONAL_DEPS = ('pyOpenSSL',) + + +def call(*args, **kwargs): + kwargs.setdefault('stdout', subprocess.DEVNULL) + return subprocess.check_call(*args, **kwargs) + + +class Environment: + """ + Each environment defines how to create an isolated instance + where we could install HTTPie and run benchmarks without any + environmental factors. + """ + + @contextmanager + def on_repo(self) -> Generator[Tuple[Path, Dict[str, str]], None, None]: + """ + Return the path to the python interpreter and the + environment variables (e.g HTTPIE_COMMAND) to be + used on the benchmarks. + """ + raise NotImplementedError + + +@dataclass +class HTTPieEnvironment(Environment): + repo_url: str + branch: Optional[str] = None + dependencies: Iterable[str] = () + + @contextmanager + def on_repo(self) -> Generator[Path, None, None]: + with tempfile.TemporaryDirectory() as directory_path: + directory = Path(directory_path) + + # Clone the repo + repo_path = directory / 'httpie' + call( + ['git', 'clone', self.repo_url, repo_path], + stderr=subprocess.DEVNULL, + ) + + if self.branch is not None: + call( + ['git', 'checkout', self.branch], + cwd=repo_path, + stderr=subprocess.DEVNULL, + ) + + # Prepare the environment + venv_path = directory / '.venv' + venv.create(venv_path, with_pip=True) + + # Install basic dependencies + python = venv_path / 'bin' / 'python' + call( + [ + python, + '-m', + 'pip', + 'install', + 'wheel', + 'pyperf==2.3.0', + *self.dependencies, + ] + ) + + # Create a wheel distribution of HTTPie + call([python, 'setup.py', 'bdist_wheel'], cwd=repo_path) + + # Install httpie + distribution_path = next((repo_path / 'dist').iterdir()) + call( + [python, '-m', 'pip', 'install', distribution_path], + cwd=repo_path, + ) + + http = venv_path / 'bin' / 'http' + yield python, {'HTTPIE_COMMAND': shlex.join([str(python), str(http)])} + + +@dataclass +class LocalCommandEnvironment(Environment): + local_command: str + + @contextmanager + def on_repo(self) -> Generator[Path, None, None]: + yield sys.executable, {'HTTPIE_COMMAND': self.local_command} + + +def dump_results( + results: List[str], + file: IO[str], + min_speed: Optional[str] = None +) -> None: + for result in results: + lines = result.strip().splitlines() + if min_speed is not None and "hidden" in lines[-1]: + lines[-1] = ( + 'Some benchmarks were hidden from this list ' + 'because their timings did not change in a ' + 'significant way (change was within the error ' + 'margin ±{margin}%).' + ).format(margin=min_speed) + result = '\n'.join(lines) + + print(result, file=file) + print("\n---\n", file=file) + + +def compare(*args, directory: Path, min_speed: Optional[str] = None): + compare_args = ['pyperf', 'compare_to', '--table', '--table-format=md', *args] + if min_speed: + compare_args.extend(['--min-speed', min_speed]) + return subprocess.check_output( + compare_args, + cwd=directory, + text=True, + ) + + +def run( + configs: List[Dict[str, Environment]], + file: IO[str], + debug: bool = False, + min_speed: Optional[str] = None, +) -> None: + result_directory = Path(tempfile.mkdtemp()) + results = [] + + current = 1 + total = sum(1 for config in configs for _ in config.items()) + + def iterate(env_name, status): + print( + f'Iteration: {env_name} ({current}/{total}) ({status})' + ' ' * 10, + end='\r', + flush=True, + ) + + for config in configs: + for env_name, env in config.items(): + iterate(env_name, 'setting up') + with env.on_repo() as (python, env_vars): + iterate(env_name, 'running benchmarks') + args = [python, BENCHMARK_SCRIPT, '-o', env_name] + if debug: + args.append('--debug-single-value') + call( + args, + cwd=result_directory, + env=env_vars, + ) + current += 1 + + results.append(compare( + *config.keys(), + directory=result_directory, + min_speed=min_speed + )) + + dump_results(results, file=file, min_speed=min_speed) + print('Results are available at:', result_directory) + + +def main() -> None: + parser = ArgumentParser() + parser.add_argument('--local-repo', default=CURRENT_REPO) + parser.add_argument('--local-branch', default=None) + parser.add_argument('--target-repo', default=CURRENT_REPO) + parser.add_argument('--target-branch', default=TARGET_BRANCH) + parser.add_argument( + '--fresh', + action='store_const', + const=GITHUB_URL, + dest='target_repo', + help='Clone the target repo from upstream GitHub URL', + ) + parser.add_argument( + '--complex', + action='store_true', + help='Add a second run, with a complex python environment.', + ) + parser.add_argument( + '--local-bin', + help='Run the suite with the given local binary in addition to' + ' existing runners. (E.g --local-bin $(command -v xh))', + ) + parser.add_argument( + '--file', + type=FileType('w'), + default=sys.stdout, + help='File to print the actual results', + ) + parser.add_argument( + '--min-speed', + help='Minimum of speed in percent to consider that a ' + 'benchmark is significant' + ) + parser.add_argument( + '--debug', + action='store_true', + ) + + options = parser.parse_args() + + configs = [] + + base_config = { + options.target_branch: HTTPieEnvironment(options.target_repo, options.target_branch), + 'this_branch': HTTPieEnvironment(options.local_repo, options.local_branch), + } + configs.append(base_config) + + if options.complex: + complex_config = { + env_name + + '-complex': dataclasses.replace(env, dependencies=ADDITIONAL_DEPS) + for env_name, env in base_config.items() + } + configs.append(complex_config) + + if options.local_bin: + base_config['binary'] = LocalCommandEnvironment(options.local_bin) + + run(configs, file=options.file, debug=options.debug, min_speed=options.min_speed) + + +if __name__ == '__main__': + main() From 3db1cdba4c379189d838c7f7ff7bbb675116c0ef Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 14 Dec 2021 18:15:19 +0300 Subject: [PATCH 0932/1182] Don't inconsistently add XML declarations (#1227) --- CHANGELOG.md | 1 + docs/README.md | 4 ++- httpie/output/formatters/xml.py | 34 +++++++++++++++---- .../fixtures/xmldata/valid/custom-header.xml | 3 ++ .../xmldata/valid/custom-header_formatted.xml | 9 +++++ .../xmldata/valid/simple-ns_formatted.xml | 1 - .../valid/simple-single-tag_formatted.xml | 1 + .../xmldata/valid/simple-single-tag_raw.xml | 1 + .../xmldata/valid/simple_formatted.xml | 1 - 9 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 tests/fixtures/xmldata/valid/custom-header.xml create mode 100644 tests/fixtures/xmldata/valid/custom-header_formatted.xml create mode 100644 tests/fixtures/xmldata/valid/simple-single-tag_formatted.xml create mode 100644 tests/fixtures/xmldata/valid/simple-single-tag_raw.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e3b9a5f4f..ff3773394f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) - Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376)) - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) +- Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156)) ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) diff --git a/docs/README.md b/docs/README.md index 5fd320db97..e515304c08 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1747,7 +1747,9 @@ Formatting has the following effects: to the characters they represent. - XML and XHTML data is indented. -You can further control the applied formatting via the more granular [format options](#format-options). +Please note that sometimes there might be changes made by formatters on the actual response body (e.g +collapsing empty tags on XML) but the end result will always be semantically indistinguishable. Some of +these formatting changes can be configured more granularly through [format options](#format-options). ### Format options diff --git a/httpie/output/formatters/xml.py b/httpie/output/formatters/xml.py index 3d63fbd574..6752ab0f57 100644 --- a/httpie/output/formatters/xml.py +++ b/httpie/output/formatters/xml.py @@ -1,4 +1,3 @@ -import sys from typing import TYPE_CHECKING, Optional from ...encoding import UTF8 @@ -8,27 +7,47 @@ from xml.dom.minidom import Document +XML_DECLARATION_OPEN = '' + + def parse_xml(data: str) -> 'Document': """Parse given XML `data` string into an appropriate :class:`~xml.dom.minidom.Document` object.""" from defusedxml.minidom import parseString return parseString(data) +def parse_declaration(raw_body: str) -> Optional[str]: + body = raw_body.strip() + # XMLDecl ::= '' + if body.startswith(XML_DECLARATION_OPEN): + end = body.find(XML_DECLARATION_CLOSE) + if end != -1: + return body[:end + len(XML_DECLARATION_CLOSE)] + + def pretty_xml(document: 'Document', + declaration: Optional[str] = None, encoding: Optional[str] = UTF8, - indent: int = 2, - standalone: Optional[bool] = None) -> str: + indent: int = 2) -> str: """Render the given :class:`~xml.dom.minidom.Document` `document` into a prettified string.""" kwargs = { 'encoding': encoding or UTF8, 'indent': ' ' * indent, } - if standalone is not None and sys.version_info >= (3, 9): - kwargs['standalone'] = standalone body = document.toprettyxml(**kwargs).decode(kwargs['encoding']) # Remove blank lines automatically added by `toprettyxml()`. - return '\n'.join(line for line in body.splitlines() if line.strip()) + lines = [line for line in body.splitlines() if line.strip()] + + # xml.dom automatically adds the declaration, even if + # it is not present in the actual body. Remove it. + if len(lines) >= 1 and parse_declaration(lines[0]): + lines.pop(0) + if declaration: + lines.insert(0, declaration) + + return '\n'.join(lines) class XMLFormatter(FormatterPlugin): @@ -44,6 +63,7 @@ def format_body(self, body: str, mime: str): from xml.parsers.expat import ExpatError from defusedxml.common import DefusedXmlException + declaration = parse_declaration(body) try: parsed_body = parse_xml(body) except ExpatError: @@ -54,6 +74,6 @@ def format_body(self, body: str, mime: str): body = pretty_xml(parsed_body, encoding=parsed_body.encoding, indent=self.format_options['xml']['indent'], - standalone=parsed_body.standalone) + declaration=declaration) return body diff --git a/tests/fixtures/xmldata/valid/custom-header.xml b/tests/fixtures/xmldata/valid/custom-header.xml new file mode 100644 index 0000000000..9bc0570920 --- /dev/null +++ b/tests/fixtures/xmldata/valid/custom-header.xml @@ -0,0 +1,3 @@ + +texttexttail + diff --git a/tests/fixtures/xmldata/valid/custom-header_formatted.xml b/tests/fixtures/xmldata/valid/custom-header_formatted.xml new file mode 100644 index 0000000000..4c75e11a3c --- /dev/null +++ b/tests/fixtures/xmldata/valid/custom-header_formatted.xml @@ -0,0 +1,9 @@ + + + + text + text + tail + + + diff --git a/tests/fixtures/xmldata/valid/simple-ns_formatted.xml b/tests/fixtures/xmldata/valid/simple-ns_formatted.xml index 8273afca19..43b49c6203 100644 --- a/tests/fixtures/xmldata/valid/simple-ns_formatted.xml +++ b/tests/fixtures/xmldata/valid/simple-ns_formatted.xml @@ -1,4 +1,3 @@ - diff --git a/tests/fixtures/xmldata/valid/simple-single-tag_formatted.xml b/tests/fixtures/xmldata/valid/simple-single-tag_formatted.xml new file mode 100644 index 0000000000..d80a5e273c --- /dev/null +++ b/tests/fixtures/xmldata/valid/simple-single-tag_formatted.xml @@ -0,0 +1 @@ +
      diff --git a/tests/fixtures/xmldata/valid/simple-single-tag_raw.xml b/tests/fixtures/xmldata/valid/simple-single-tag_raw.xml new file mode 100644 index 0000000000..41ab602321 --- /dev/null +++ b/tests/fixtures/xmldata/valid/simple-single-tag_raw.xml @@ -0,0 +1 @@ + diff --git a/tests/fixtures/xmldata/valid/simple_formatted.xml b/tests/fixtures/xmldata/valid/simple_formatted.xml index 1638b5b6a7..9db0eba2ae 100644 --- a/tests/fixtures/xmldata/valid/simple_formatted.xml +++ b/tests/fixtures/xmldata/valid/simple_formatted.xml @@ -1,4 +1,3 @@ - text From f94c12d8caa1ff544d228b75466e308a421923b0 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 16 Dec 2021 12:06:00 +0300 Subject: [PATCH 0933/1182] Close all stale PRs (#1245) --- .github/workflows/stale.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000..48451501bf --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,28 @@ +name: Mark stale pull requests + +on: + schedule: + - cron: "0 0 * * *" + +permissions: + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-latest + + steps: + - uses: actions/stale@v4 + with: + stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.' + close-pr-message: 'Thanks for the pull reuqest, but since it was stale for more than a month we are closing it. If you want to work back on it, feel free to open it back or create a new one.' + stale-pr-label: 'stale' + + days-before-stale: -1 + days-before-issue-stale: -1 + days-before-pr-stale: 30 + + days-before-close: -1 + days-before-issue-close: -1 + days-before-pr-close: 7 + debug-only: true From e4b2751a523f5bd7c125cdb8786bbc4861fb5c33 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 16 Dec 2021 12:09:31 +0300 Subject: [PATCH 0934/1182] Set stale action to run on workflow dispatch --- .github/workflows/stale.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 48451501bf..c26b4785aa 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -2,7 +2,8 @@ name: Mark stale pull requests on: schedule: - - cron: "0 0 * * *" + - cron: "0 0 * * *" + workflow_dispatch permissions: pull-requests: write From 43462f8af01a0b0e6bb7568ab3e8b34280a0ecb0 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 16 Dec 2021 12:11:12 +0300 Subject: [PATCH 0935/1182] Only configure with workflow_dispatch --- .github/workflows/stale.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index c26b4785aa..ed8477461f 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,9 +1,6 @@ name: Mark stale pull requests -on: - schedule: - - cron: "0 0 * * *" - workflow_dispatch +on: workflow_dispatch permissions: pull-requests: write @@ -21,9 +18,9 @@ jobs: days-before-stale: -1 days-before-issue-stale: -1 - days-before-pr-stale: 30 + days-before-pr-stale: 21 days-before-close: -1 days-before-issue-close: -1 - days-before-pr-close: 7 + days-before-pr-close: 0 debug-only: true From 088b6cdb0c5f0eac6c9ef517855b2ca8835c2797 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 16 Dec 2021 12:14:50 +0300 Subject: [PATCH 0936/1182] Move stale action from debug to actual run --- .github/workflows/stale.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index ed8477461f..ce4ab50c9d 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -23,4 +23,3 @@ jobs: days-before-close: -1 days-before-issue-close: -1 days-before-pr-close: 0 - debug-only: true From 340fef6278238e43a8ec197f4586147cc06575a3 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 16 Dec 2021 12:17:55 +0300 Subject: [PATCH 0937/1182] (stale action) Fix typo in closing message --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index ce4ab50c9d..5a940f23a8 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/stale@v4 with: stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.' - close-pr-message: 'Thanks for the pull reuqest, but since it was stale for more than a month we are closing it. If you want to work back on it, feel free to open it back or create a new one.' + close-pr-message: 'Thanks for the pull request, but since it was stale for more than a 21 days we are closing it. If you want to work back on it, feel free to re-open it or create a new one.' stale-pr-label: 'stale' days-before-stale: -1 From 28e874535a86147321f4fb8e21b81a49b9354e48 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 16 Dec 2021 12:18:09 +0300 Subject: [PATCH 0938/1182] (stale action) bump days to 30 --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 5a940f23a8..824644080c 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -18,7 +18,7 @@ jobs: days-before-stale: -1 days-before-issue-stale: -1 - days-before-pr-stale: 21 + days-before-pr-stale: 30 days-before-close: -1 days-before-issue-close: -1 From 7ae44aefe2d1fff4071d28341ae6e5a441ee2980 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 16 Dec 2021 12:19:25 +0300 Subject: [PATCH 0939/1182] (stale action) get rid of stale message, only comment on closing --- .github/workflows/stale.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 824644080c..71a4ace7be 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -12,8 +12,7 @@ jobs: steps: - uses: actions/stale@v4 with: - stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.' - close-pr-message: 'Thanks for the pull request, but since it was stale for more than a 21 days we are closing it. If you want to work back on it, feel free to re-open it or create a new one.' + close-pr-message: 'Thanks for the pull request, but since it was stale for more than a 30 days we are closing it. If you want to work back on it, feel free to re-open it or create a new one.' stale-pr-label: 'stale' days-before-stale: -1 From 7bd7aa20d2d14c342975b0c4d765acde4e1f2e65 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 16 Dec 2021 12:24:52 +0300 Subject: [PATCH 0940/1182] (stale action) bump operations per run to 300 --- .github/workflows/stale.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 71a4ace7be..a3aae58de5 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -22,3 +22,5 @@ jobs: days-before-close: -1 days-before-issue-close: -1 days-before-pr-close: 0 + + operations-per-run: 300 From 2b78d044101e44513b8726737435c2f9f1a394f6 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 16 Dec 2021 18:04:34 +0300 Subject: [PATCH 0941/1182] Strip out extra variables from the actual mime type (#1244) * Strip out extra variables from the actual mime type * mention in changelog * Update CHANGELOG.md Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 1 + httpie/output/streams.py | 6 +++++- tests/test_output.py | 12 ++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff3773394f..acb2d58368 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376)) - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) - Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156)) +- Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/httpie/issues/1242)) ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 24a1ba23c9..f9492a2167 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -6,6 +6,7 @@ from ..context import Environment from ..encoding import smart_decode, smart_encode, UTF8 from ..models import HTTPMessage +from ..utils import parse_content_type_header BINARY_SUPPRESSED_NOTICE = ( @@ -106,7 +107,10 @@ def __init__( **kwargs ): super().__init__(**kwargs) - self.mime = mime_overwrite or self.msg.content_type + if mime_overwrite: + self.mime = mime_overwrite + else: + self.mime, _ = parse_content_type_header(self.msg.content_type) self.encoding = encoding_overwrite or self.msg.encoding if env.stdout_isatty: # Use the encoding supported by the terminal. diff --git a/tests/test_output.py b/tests/test_output.py index 36072b6fcb..f310b24e15 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -215,6 +215,18 @@ def test_get_lexer_not_found(self): assert get_lexer('xxx/yyy') is None +@pytest.mark.parametrize("endpoint", [ + "/encoding/utf8", + "/html", + "/json", + "/xml", +]) +def test_ensure_contents_colored(httpbin, endpoint): + env = MockEnvironment(colors=256) + r = http('--body', 'GET', httpbin + endpoint, env=env) + assert COLOR in r + + class TestPrettyOptions: """Test the --pretty handling.""" From a5d8b51e472e8db741469cbfdfe0cf4f19c652f1 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 17 Dec 2021 10:59:39 +0300 Subject: [PATCH 0942/1182] Implement `httpie upgrade` for upgrading plugins (#1241) * Implement `httpie upgrade` for upgrading plugins * Support upgrades for every installation type * Fix decoding problems --- docs/README.md | 8 ++++ httpie/manager/cli.py | 8 ++++ httpie/manager/plugins.py | 82 ++++++++++++++++++++++++++++++++++----- tests/test_plugins_cli.py | 12 ++++++ 4 files changed, 101 insertions(+), 9 deletions(-) diff --git a/docs/README.md b/docs/README.md index e515304c08..59b42ff7e0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2224,6 +2224,14 @@ httpie_converter (1.0.0) httpie_konsole_konverter (httpie.plugins.converter.v1) ``` +#### `httpie plugins upgrade` + +For upgrading already installed plugins, use `httpie plugins upgrade`. + +```bash +$ httpie plugins upgrade httpie-plugin +``` + #### `httpie plugins uninstall` Uninstall plugins from the isolated plugins directory. If the plugin is not installed diff --git a/httpie/manager/cli.py b/httpie/manager/cli.py index eeeb24659b..11c63d0a31 100644 --- a/httpie/manager/cli.py +++ b/httpie/manager/cli.py @@ -14,6 +14,14 @@ 'help': 'targets to install' } ], + 'upgrade': [ + 'Upgrade the given plugins', + { + 'dest': 'targets', + 'nargs': '+', + 'help': 'targets to upgrade' + } + ], 'uninstall': [ 'Uninstall the given HTTPie plugins.', { diff --git a/httpie/manager/plugins.py b/httpie/manager/plugins.py index 7760ce2357..899e992563 100644 --- a/httpie/manager/plugins.py +++ b/httpie/manager/plugins.py @@ -3,15 +3,20 @@ import subprocess import sys import textwrap +import re +import shutil from collections import defaultdict from contextlib import suppress from pathlib import Path -from typing import Optional, List +from typing import Tuple, Optional, List from httpie.manager.cli import parser, missing_subcommand from httpie.compat import importlib_metadata, get_dist_name from httpie.context import Environment from httpie.status import ExitStatus +from httpie.utils import as_site + +PEP_503 = re.compile(r"[-_.]+") class PluginInstaller: @@ -68,16 +73,22 @@ def pip(self, *args, **kwargs) -> subprocess.CompletedProcess: **options ) - def install(self, targets: List[str]) -> Optional[ExitStatus]: - self.env.stdout.write(f"Installing {', '.join(targets)}...\n") - self.env.stdout.flush() + def _install(self, targets: List[str], mode='install', **process_options) -> Tuple[ + Optional[bytes], ExitStatus + ]: + pip_args = [ + 'install', + f'--prefix={self.dir}', + '--no-warn-script-location', + ] + if mode == 'upgrade': + pip_args.append('--upgrade') try: - self.pip( - 'install', - f'--prefix={self.dir}', - '--no-warn-script-location', + process = self.pip( + *pip_args, *targets, + **process_options, ) except subprocess.CalledProcessError as error: reason = None @@ -94,7 +105,58 @@ def install(self, targets: List[str]) -> Optional[ExitStatus]: if severity == 'ERROR': reason = message - return self.fail('install', ', '.join(targets), reason) + stdout = error.stdout + exit_status = self.fail(mode, ', '.join(targets), reason) + else: + stdout = process.stdout + exit_status = ExitStatus.SUCCESS + + return stdout, exit_status + + def install(self, targets: List[str]) -> ExitStatus: + self.env.stdout.write(f"Installing {', '.join(targets)}...\n") + self.env.stdout.flush() + _, exit_status = self._install(targets) + return exit_status + + def _clear_metadata(self, targets: List[str]) -> None: + # Due to an outstanding pip problem[0], we have to get rid of + # existing metadata for old versions manually. + # [0]: https://github.com/pypa/pip/issues/10727 + result_deps = defaultdict(list) + for child in as_site(self.dir).iterdir(): + if child.suffix in {'.dist-info', '.egg-info'}: + name, _, version = child.stem.rpartition('-') + result_deps[name].append((version, child)) + + for target in targets: + name, _, version = target.rpartition('-') + name = PEP_503.sub("-", name).lower().replace('-', '_') + if name not in result_deps: + continue + + for result_version, meta_path in result_deps[name]: + if version != result_version: + shutil.rmtree(meta_path) + + def upgrade(self, targets: List[str]) -> ExitStatus: + self.env.stdout.write(f"Upgrading {', '.join(targets)}...\n") + self.env.stdout.flush() + + raw_stdout, exit_status = self._install( + targets, + mode='upgrade', + stdout=subprocess.PIPE + ) + if not raw_stdout: + return exit_status + + stdout = raw_stdout.decode() + self.env.stdout.write(stdout) + + installation_line = stdout.splitlines()[-1] + if installation_line.startswith('Successfully installed'): + self._clear_metadata(installation_line.split()[2:]) def _uninstall(self, target: str) -> Optional[ExitStatus]: try: @@ -178,6 +240,8 @@ def run( with enable_plugins(self.dir): if action == 'install': status = self.install(args.targets) + elif action == 'upgrade': + status = self.upgrade(args.targets) elif action == 'uninstall': status = self.uninstall(args.targets) elif action == 'list': diff --git a/tests/test_plugins_cli.py b/tests/test_plugins_cli.py index d644aba73d..af4a77469b 100644 --- a/tests/test_plugins_cli.py +++ b/tests/test_plugins_cli.py @@ -93,6 +93,18 @@ def test_plugins_double_uninstall(httpie_plugins, httpie_plugins_success, dummy_ ) +def test_plugins_upgrade(httpie_plugins, httpie_plugins_success, dummy_plugin): + httpie_plugins_success("install", dummy_plugin.path) + + # Make a new version of the plugin + dummy_plugin.version = '2.0.0' + dummy_plugin.build() + + httpie_plugins_success("upgrade", dummy_plugin.path) + data = parse_listing(httpie_plugins_success('list')) + assert data[dummy_plugin.name]['version'] == '2.0.0' + + def test_broken_plugins(httpie_plugins, httpie_plugins_success, dummy_plugin, broken_plugin): httpie_plugins_success("install", dummy_plugin.path, broken_plugin.path) From c237e1510845dcffc6fe361353486d45f897bc11 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 17 Dec 2021 11:00:03 +0300 Subject: [PATCH 0943/1182] Faster downloads through bigger chunks / less buffering (#1236) --- httpie/downloads.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/httpie/downloads.py b/httpie/downloads.py index 6de9628cc9..d8a5dd04cc 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -271,7 +271,6 @@ def start( with_headers=False, with_body=True, on_body_chunk_downloaded=self.chunk_downloaded, - chunk_size=1024 * 8 ) self._progress_reporter.output.write( @@ -324,7 +323,7 @@ def _get_output_file_from_response( content_type=final_response.headers.get('Content-Type'), ) unique_filename = get_unique_filename(filename) - return open(unique_filename, mode='a+b') + return open(unique_filename, buffering=0, mode='a+b') class DownloadStatus: From 1bd8422fb5cee0fb21a00703b2f7272e3fc898d4 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 17 Dec 2021 11:00:22 +0300 Subject: [PATCH 0944/1182] Improve startup time when pyOpenSSL is available on the environment (#1233) --- httpie/uploads.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/httpie/uploads.py b/httpie/uploads.py index 9e2fe7edb1..c3c4e766db 100644 --- a/httpie/uploads.py +++ b/httpie/uploads.py @@ -1,10 +1,12 @@ import zlib -from typing import Callable, IO, Iterable, Tuple, Union +from typing import Callable, IO, Iterable, Tuple, Union, TYPE_CHECKING from urllib.parse import urlencode import requests from requests.utils import super_len -from requests_toolbelt import MultipartEncoder + +if TYPE_CHECKING: + from requests_toolbelt import MultipartEncoder from .cli.dicts import MultipartRequestDataDict, RequestDataDict @@ -23,7 +25,7 @@ def __iter__(self) -> Iterable[Union[str, bytes]]: class ChunkedMultipartUploadStream: chunk_size = 100 * 1024 - def __init__(self, encoder: MultipartEncoder): + def __init__(self, encoder: 'MultipartEncoder'): self.encoder = encoder def __iter__(self) -> Iterable[Union[str, bytes]]: @@ -35,12 +37,12 @@ def __iter__(self) -> Iterable[Union[str, bytes]]: def prepare_request_body( - body: Union[str, bytes, IO, MultipartEncoder, RequestDataDict], + body: Union[str, bytes, IO, 'MultipartEncoder', RequestDataDict], body_read_callback: Callable[[bytes], bytes], content_length_header_value: int = None, chunked=False, offline=False, -) -> Union[str, bytes, IO, MultipartEncoder, ChunkedUploadStream]: +) -> Union[str, bytes, IO, 'MultipartEncoder', ChunkedUploadStream]: is_file_like = hasattr(body, 'read') @@ -85,6 +87,7 @@ def new_read(*args): body.read = new_read if chunked: + from requests_toolbelt import MultipartEncoder if isinstance(body, MultipartEncoder): body = ChunkedMultipartUploadStream( encoder=body, @@ -102,7 +105,9 @@ def get_multipart_data_and_content_type( data: MultipartRequestDataDict, boundary: str = None, content_type: str = None, -) -> Tuple[MultipartEncoder, str]: +) -> Tuple['MultipartEncoder', str]: + from requests_toolbelt import MultipartEncoder + encoder = MultipartEncoder( fields=data.items(), boundary=boundary, From 8dc6c0df7709890be3460c6179dc5bdc0809802e Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Sun, 19 Dec 2021 13:41:42 +0300 Subject: [PATCH 0945/1182] Implement new `pie` and `pie-light` styles (#1238) * Implement new `pie` and `pie-light` styles * Change some pallete * Integrate the color palette * some docs * some docs * Rework on code generation * Apply suggestions from code review Co-authored-by: Jakub Roztocil Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 1 + docs/README.md | 17 +-- httpie/output/formatters/colors.py | 153 +++++++++++++++++++++++++-- httpie/output/lexers/http.py | 72 ++++++++++++- httpie/output/ui/__init__.py | 0 httpie/output/ui/palette.py | 161 +++++++++++++++++++++++++++++ 6 files changed, 384 insertions(+), 20 deletions(-) create mode 100644 httpie/output/ui/__init__.py create mode 100644 httpie/output/ui/palette.py diff --git a/CHANGELOG.md b/CHANGELOG.md index acb2d58368..b5778b4a78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for _receiving_ multiple HTTP headers lines with the same name. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) - Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376)) +- Added new `pie-dark`/`pie-light` (and `pie`) styles that match with [HTTPie for Web and Desktop](https://httpie.io/product). ([#1237](https://github.com/httpie/httpie/issues/1237)) - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) - Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156)) - Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/httpie/issues/1242)) diff --git a/docs/README.md b/docs/README.md index 59b42ff7e0..5d1a2c11a1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1717,13 +1717,16 @@ Syntax highlighting is applied to HTTP headers and bodies (where it makes sense) You can choose your preferred color scheme via the `--style` option if you don’t like the default one. There are dozens of styles available, here are just a few notable ones: -| Style | Description | -| --------: | ----------------------------------------------------------------------------------------------------------------------------------- | -| `auto` | Follows your terminal ANSI color styles. This is the default style used by HTTPie | -| `default` | Default styles of the underlying Pygments library. Not actually used by default by HTTPie. You can enable it with `--style=default` | -| `monokai` | A popular color scheme. Enable with `--style=monokai` | -| `fruity` | A bold, colorful scheme. Enable with `--style=fruity` | -| … | See `$ http --help` for all the possible `--style` values | +| Style | Description | +| ---------: | ------------------------------------------------------------------------------------------------------------------------------------ | +| `auto` | Follows your terminal ANSI color styles. This is the default style used by HTTPie | +| `default` | Default styles of the underlying Pygments library. Not actually used by default by HTTPie. You can enable it with `--style=default` | +| `pie-dark` | HTTPie’s original brand style. Also used in [HTTPie for Web and Desktop](https://httpie.io/product). | +|`pie-light` | Like `pie-dark`, but for terminals with light background colors. | +| `pie` | A generic version of `pie-dark` and `pie-light` themes that can work with any terminal background. Its universality requires compromises in terms of legibility, but it’s useful if you frequently switch your terminal between dark and light backgrounds. | +| `monokai` | A popular color scheme. Enable with `--style=monokai` | +| `fruity` | A bold, colorful scheme. Enable with `--style=fruity` | +| … | See `$ http --help` for all the possible `--style` values | Use one of these options to control output processing: diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index b2db70ff37..757163f84b 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -1,6 +1,7 @@ import json -from typing import Optional, Type +from typing import Optional, Type, Tuple +import pygments.formatters import pygments.lexer import pygments.lexers import pygments.style @@ -15,6 +16,7 @@ from pygments.util import ClassNotFound from ..lexers.json import EnhancedJsonLexer +from ..ui.palette import SHADE_NAMES, get_color from ...compat import is_windows from ...context import Environment from ...plugins import FormatterPlugin @@ -23,6 +25,7 @@ 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. @@ -66,22 +69,23 @@ def __init__( if use_auto_style or not has_256_colors: http_lexer = PygmentsHttpLexer() formatter = TerminalFormatter() + body_formatter = formatter + header_formatter = formatter else: from ..lexers.http import SimplifiedHTTPLexer - http_lexer = SimplifiedHTTPLexer() - formatter = Terminal256Formatter( - style=self.get_style_class(color_scheme) - ) + header_formatter, body_formatter, precise = self.get_formatters(color_scheme) + http_lexer = SimplifiedHTTPLexer(precise=precise) self.explicit_json = explicit_json # --json - self.formatter = formatter + self.header_formatter = header_formatter + self.body_formatter = body_formatter self.http_lexer = http_lexer def format_headers(self, headers: str) -> str: return pygments.highlight( code=headers, lexer=self.http_lexer, - formatter=self.formatter, + formatter=self.header_formatter, ).strip() def format_body(self, body: str, mime: str) -> str: @@ -90,7 +94,7 @@ def format_body(self, body: str, mime: str) -> str: body = pygments.highlight( code=body, lexer=lexer, - formatter=self.formatter, + formatter=self.body_formatter, ) return body @@ -104,6 +108,25 @@ def get_lexer_for_body( body=body, ) + def get_formatters(self, color_scheme: str) -> Tuple[ + pygments.formatter.Formatter, + pygments.formatter.Formatter, + bool + ]: + if color_scheme in PIE_STYLES: + header_style, body_style = PIE_STYLES[color_scheme] + precise = True + else: + header_style = self.get_style_class(color_scheme) + body_style = header_style + precise = False + + return ( + Terminal256Formatter(style=header_style), + Terminal256Formatter(style=body_style), + precise + ) + @staticmethod def get_style_class(color_scheme: str) -> Type[pygments.style.Style]: try: @@ -237,3 +260,117 @@ class Solarized256Style(pygments.style.Style): pygments.token.Token: BASE1, pygments.token.Token.Other: ORANGE, } + + +PIE_HEADER_STYLE = { + # HTTP line / Headers / Etc. + pygments.token.Name.Namespace: 'bold primary', + pygments.token.Keyword.Reserved: 'bold grey', + pygments.token.Operator: 'bold grey', + pygments.token.Number: 'bold grey', + pygments.token.Name.Function.Magic: 'bold green', + pygments.token.Name.Exception: 'bold green', + pygments.token.Name.Attribute: 'blue', + pygments.token.String: 'primary', + + # HTTP Methods + pygments.token.Name.Function: 'bold grey', + pygments.token.Name.Function.HTTP.GET: 'bold green', + pygments.token.Name.Function.HTTP.HEAD: 'bold green', + pygments.token.Name.Function.HTTP.POST: 'bold yellow', + pygments.token.Name.Function.HTTP.PUT: 'bold orange', + pygments.token.Name.Function.HTTP.PATCH: 'bold orange', + pygments.token.Name.Function.HTTP.DELETE: 'bold red', + + # HTTP status codes + pygments.token.Number.HTTP.INFO: 'bold aqua', + pygments.token.Number.HTTP.OK: 'bold green', + pygments.token.Number.HTTP.REDIRECT: 'bold yellow', + pygments.token.Number.HTTP.CLIENT_ERR: 'bold orange', + pygments.token.Number.HTTP.SERVER_ERR: 'bold red', +} + +PIE_BODY_STYLE = { + # {}[]: + pygments.token.Punctuation: 'grey', + + # Keys + pygments.token.Name.Tag: 'pink', + + # Values + pygments.token.Literal.String: 'green', + pygments.token.Literal.String.Double: 'green', + pygments.token.Literal.Number: 'aqua', + pygments.token.Keyword: 'orange', + + # Other stuff + pygments.token.Text: 'primary', + pygments.token.Name.Attribute: 'primary', + pygments.token.Name.Builtin: 'blue', + pygments.token.Name.Builtin.Pseudo: 'blue', + pygments.token.Name.Class: 'blue', + pygments.token.Name.Constant: 'orange', + pygments.token.Name.Decorator: 'blue', + pygments.token.Name.Entity: 'orange', + pygments.token.Name.Exception: 'yellow', + pygments.token.Name.Function: 'blue', + pygments.token.Name.Variable: 'blue', + pygments.token.String: 'aqua', + pygments.token.String.Backtick: 'secondary', + pygments.token.String.Char: 'aqua', + pygments.token.String.Doc: 'aqua', + pygments.token.String.Escape: 'red', + pygments.token.String.Heredoc: 'aqua', + pygments.token.String.Regex: 'red', + pygments.token.Number: 'aqua', + pygments.token.Operator: 'primary', + pygments.token.Operator.Word: 'green', + pygments.token.Comment: 'secondary', + pygments.token.Comment.Preproc: 'green', + pygments.token.Comment.Special: 'green', + pygments.token.Generic.Deleted: 'aqua', + pygments.token.Generic.Emph: 'italic', + pygments.token.Generic.Error: 'red', + pygments.token.Generic.Heading: 'orange', + pygments.token.Generic.Inserted: 'green', + pygments.token.Generic.Strong: 'bold', + pygments.token.Generic.Subheading: 'orange', + pygments.token.Token: 'primary', + pygments.token.Token.Other: 'orange', +} + + +def make_style(name, raw_styles, shade): + def format_value(value): + return ' '.join( + get_color(part, shade) or part + for part in value.split() + ) + + bases = (pygments.style.Style,) + data = { + 'styles': { + key: format_value(value) + for key, value in raw_styles.items() + } + } + return type(name, bases, data) + + +def make_styles(): + styles = {} + + for shade, name in SHADE_NAMES.items(): + styles[name] = [ + make_style(name, style_map, shade) + for style_name, style_map in [ + (f'Pie{name}HeaderStyle', PIE_HEADER_STYLE), + (f'Pie{name}BodyStyle', PIE_BODY_STYLE), + ] + ] + + return styles + + +PIE_STYLES = make_styles() +BUNDLED_STYLES |= PIE_STYLES.keys() diff --git a/httpie/output/lexers/http.py b/httpie/output/lexers/http.py index 4c2b00d252..0b8b612a0e 100644 --- a/httpie/output/lexers/http.py +++ b/httpie/output/lexers/http.py @@ -1,6 +1,70 @@ +import re import pygments +RE_STATUS_LINE = re.compile(r'(\d{3})( +)(.+)') + +STATUS_TYPES = { + '1': pygments.token.Number.HTTP.INFO, + '2': pygments.token.Number.HTTP.OK, + '3': pygments.token.Number.HTTP.REDIRECT, + '4': pygments.token.Number.HTTP.CLIENT_ERR, + '5': pygments.token.Number.HTTP.SERVER_ERR, +} + +RESPONSE_TYPES = { + 'GET': pygments.token.Name.Function.HTTP.GET, + 'HEAD': pygments.token.Name.Function.HTTP.HEAD, + 'POST': pygments.token.Name.Function.HTTP.POST, + 'PUT': pygments.token.Name.Function.HTTP.PUT, + 'PATCH': pygments.token.Name.Function.HTTP.PATCH, + 'DELETE': pygments.token.Name.Function.HTTP.DELETE, +} + + +def precise(lexer, precise_token, parent_token): + # Due to a pygments bug*, custom tokens will look bad + # on outside styles. Until it is fixed on upstream, we'll + # convey whether the client is using pie style or not + # through precise option and return more precise tokens + # depending on it's value. + # + # [0]: https://github.com/pygments/pygments/issues/1986 + if precise_token is None or not lexer.options.get("precise"): + return parent_token + else: + return precise_token + + +def http_response_type(lexer, match, ctx): + status_match = RE_STATUS_LINE.match(match.group()) + if status_match is None: + return None + + status_code, text, reason = status_match.groups() + status_type = precise( + lexer, + STATUS_TYPES.get(status_code[0]), + pygments.token.Number + ) + + groups = pygments.lexer.bygroups( + status_type, + pygments.token.Text, + status_type + ) + yield from groups(lexer, status_match, ctx) + + +def request_method(lexer, match, ctx): + response_type = precise( + lexer, + RESPONSE_TYPES.get(match.group()), + pygments.token.Name.Function + ) + yield match.start(), response_type, match.group() + + class SimplifiedHTTPLexer(pygments.lexer.RegexLexer): """Simplified HTTP lexer for Pygments. @@ -18,7 +82,7 @@ class SimplifiedHTTPLexer(pygments.lexer.RegexLexer): # Request-Line (r'([A-Z]+)( +)([^ ]+)( +)(HTTP)(/)(\d+\.\d+)', pygments.lexer.bygroups( - pygments.token.Name.Function, + request_method, pygments.token.Text, pygments.token.Name.Namespace, pygments.token.Text, @@ -27,15 +91,13 @@ class SimplifiedHTTPLexer(pygments.lexer.RegexLexer): pygments.token.Number )), # Response Status-Line - (r'(HTTP)(/)(\d+\.\d+)( +)(\d{3})( +)(.+)', + (r'(HTTP)(/)(\d+\.\d+)( +)(.+)', pygments.lexer.bygroups( pygments.token.Keyword.Reserved, # 'HTTP' pygments.token.Operator, # '/' pygments.token.Number, # Version pygments.token.Text, - pygments.token.Number, # Status code - pygments.token.Text, - pygments.token.Name.Exception, # Reason + http_response_type, # Status code and Reason )), # Header (r'(.*?)( *)(:)( *)(.+)', pygments.lexer.bygroups( diff --git a/httpie/output/ui/__init__.py b/httpie/output/ui/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/httpie/output/ui/palette.py b/httpie/output/ui/palette.py new file mode 100644 index 0000000000..a13aef058c --- /dev/null +++ b/httpie/output/ui/palette.py @@ -0,0 +1,161 @@ +# Copy the brand palette +from typing import Optional + +COLOR_PALETTE = { + 'transparent': 'transparent', + 'current': 'currentColor', + 'white': '#F5F5F0', + 'black': '#1C1818', + 'grey': { + '50': '#F5F5F0', + '100': '#EDEDEB', + '200': '#D1D1CF', + '300': '#B5B5B2', + '400': '#999999', + '500': '#7D7D7D', + '600': '#666663', + '700': '#4F4D4D', + '800': '#363636', + '900': '#1C1818', + 'DEFAULT': '#7D7D7D', + }, + 'aqua': { + '50': '#E8F0F5', + '100': '#D6E3ED', + '200': '#C4D9E5', + '300': '#B0CCDE', + '400': '#9EBFD6', + '500': '#8CB4CD', + '600': '#7A9EB5', + '700': '#698799', + '800': '#597082', + '900': '#455966', + 'DEFAULT': '#8CB4CD', + }, + 'purple': { + '50': '#F0E0FC', + '100': '#E3C7FA', + '200': '#D9ADF7', + '300': '#CC96F5', + '400': '#BF7DF2', + '500': '#B464F0', + '600': '#9E54D6', + '700': '#8745BA', + '800': '#70389E', + '900': '#5C2982', + 'DEFAULT': '#B464F0', + }, + 'orange': { + '50': '#FFEDDB', + '100': '#FFDEBF', + '200': '#FFCFA3', + '300': '#FFBF87', + '400': '#FFB06B', + '500': '#FFA24E', + '600': '#F2913D', + '700': '#E3822B', + '800': '#D6701C', + '900': '#C75E0A', + 'DEFAULT': '#FFA24E', + }, + 'red': { + '50': '#FFE0DE', + '100': '#FFC7C4', + '200': '#FFB0AB', + '300': '#FF968F', + '400': '#FF8075', + '500': '#FF665B', + '600': '#E34F45', + '700': '#C7382E', + '800': '#AD2117', + '900': '#910A00', + 'DEFAULT': '#FF665B', + }, + 'blue': { + '50': '#DBE3FA', + '100': '#BFCFF5', + '200': '#A1B8F2', + '300': '#85A3ED', + '400': '#698FEB', + '500': '#4B78E6', + '600': '#426BD1', + '700': '#3B5EBA', + '800': '#3354A6', + '900': '#2B478F', + 'DEFAULT': '#4B78E6', + }, + 'pink': { + '50': '#FFEBFF', + '100': '#FCDBFC', + '200': '#FCCCFC', + '300': '#FCBAFC', + '400': '#FAABFA', + '500': '#FA9BFA', + '600': '#DE85DE', + '700': '#C26EC2', + '800': '#A854A6', + '900': '#8C3D8A', + 'DEFAULT': '#FA9BFA', + }, + 'green': { + '50': '#E3F7E8', + '100': '#CCF2D6', + '200': '#B5EDC4', + '300': '#A1E8B0', + '400': '#8AE09E', + '500': '#73DC8C', + '600': '#63C27A', + '700': '#52AB66', + '800': '#429154', + '900': '#307842', + 'DEFAULT': '#73DC8C', + }, + 'yellow': { + '50': '#F7F7DB', + '100': '#F2F2BF', + '200': '#EDEDA6', + '300': '#E5E88A', + '400': '#E0E36E', + '500': '#DBDE52', + '600': '#CCCC3D', + '700': '#BABA29', + '800': '#ABA614', + '900': '#999400', + 'DEFAULT': '#DBDE52', + }, +} + +# Grey is the same no matter shade for the colors +COLOR_PALETTE['grey'] = { + shade: COLOR_PALETTE['grey']['500'] for shade in COLOR_PALETTE['grey'].keys() +} + +COLOR_PALETTE['primary'] = { + '700': COLOR_PALETTE['black'], + '600': 'ansibrightblack', + '500': COLOR_PALETTE['white'], +} + +COLOR_PALETTE['secondary'] = {'700': '#37523C', '600': '#6c6969', '500': '#6c6969'} + +SHADE_NAMES = { + '500': 'pie-dark', + '600': 'pie', + '700': 'pie-light' +} + +SHADES = [ + '50', + *map(str, range(100, 1000, 100)) +] + + +def get_color(color: str, shade: str) -> Optional[str]: + if color not in COLOR_PALETTE: + return None + + color_code = COLOR_PALETTE[color] + if isinstance(color_code, dict) and shade in color_code: + return color_code[shade] + else: + return color_code From 021b41c9e5a795686bf25f9a1dc92f71704db2aa Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 21 Dec 2021 20:28:23 +0300 Subject: [PATCH 0946/1182] Make snap action triggerable --- .github/workflows/test-package-linux-snap.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-package-linux-snap.yml b/.github/workflows/test-package-linux-snap.yml index 2f717e2a0c..316b3ac268 100644 --- a/.github/workflows/test-package-linux-snap.yml +++ b/.github/workflows/test-package-linux-snap.yml @@ -3,6 +3,7 @@ on: paths: - .github/workflows/test-package-linux-snap.yml - snapcraft.yaml + workflow_dispatch: jobs: snap: From 2d15659b168185452446be5831c9beceb5ed2ce0 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 21 Dec 2021 20:28:42 +0300 Subject: [PATCH 0947/1182] Make brew action triggerable --- .github/workflows/test-package-mac-brew.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-package-mac-brew.yml b/.github/workflows/test-package-mac-brew.yml index fbaf52c1c3..064bafb0fa 100644 --- a/.github/workflows/test-package-mac-brew.yml +++ b/.github/workflows/test-package-mac-brew.yml @@ -3,6 +3,7 @@ on: paths: - .github/workflows/test-package-mac-brew.yml - docs/packaging/brew/httpie.rb + workflow_dispatch: jobs: brew: From c97ec93a19d7c443f1db8b1cca42ba11035c5c13 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 21 Dec 2021 20:33:09 +0300 Subject: [PATCH 0948/1182] Test httpie --- docs/packaging/brew/httpie.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/packaging/brew/httpie.rb b/docs/packaging/brew/httpie.rb index a2a15d9371..573e4b2db2 100644 --- a/docs/packaging/brew/httpie.rb +++ b/docs/packaging/brew/httpie.rb @@ -73,6 +73,9 @@ def install end test do + # shell_output() already checks the status code + shell_output("#{bin}/httpie -v") + raw_url = "https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/httpie.rb" assert_match "PYTHONPATH", shell_output("#{bin}/http --ignore-stdin #{raw_url}") end From 5a83a9ebc4887b95559dad6e4c8f280e6819c8c1 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 21 Dec 2021 20:33:23 +0300 Subject: [PATCH 0949/1182] Test `https` as well --- docs/packaging/brew/httpie.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/packaging/brew/httpie.rb b/docs/packaging/brew/httpie.rb index 573e4b2db2..48097e5109 100644 --- a/docs/packaging/brew/httpie.rb +++ b/docs/packaging/brew/httpie.rb @@ -75,6 +75,8 @@ def install test do # shell_output() already checks the status code shell_output("#{bin}/httpie -v") + shell_output("#{bin}/https -v") + shell_output("#{bin}/http -v") raw_url = "https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/httpie.rb" assert_match "PYTHONPATH", shell_output("#{bin}/http --ignore-stdin #{raw_url}") From e09401b81aec7d630b986eb3a4056b2f387dc3e0 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 23 Dec 2021 22:05:58 +0300 Subject: [PATCH 0950/1182] Optimize encoding detection (#1243) * Optimize encoding detection * Use a threshold based system --- extras/profiling/benchmarks.py | 3 +-- httpie/encoding.py | 6 +++--- httpie/output/streams.py | 36 ++++++++++++++++++++++++++++++---- tests/fixtures/__init__.py | 2 ++ tests/test_stream.py | 13 +++++++++++- tests/utils/http_server.py | 21 ++++++++++++++++++++ 6 files changed, 71 insertions(+), 10 deletions(-) diff --git a/extras/profiling/benchmarks.py b/extras/profiling/benchmarks.py index 50a53a5a9e..5d47a3a125 100644 --- a/extras/profiling/benchmarks.py +++ b/extras/profiling/benchmarks.py @@ -178,9 +178,8 @@ def run(self, context: Context) -> pyperf.Benchmark: f'`http --pretty={pretty} pie.dev/stream/1000`', [ '--print=HBhb', - '--stream', f'--pretty={pretty}', - 'httpbin.org/stream/100' + 'httpbin.org/stream/1000' ] ) DownloadRunner('download', '`http --download :/big_file.txt` (3GB)', '3G') diff --git a/httpie/encoding.py b/httpie/encoding.py index 8888743a36..f796dde9f5 100644 --- a/httpie/encoding.py +++ b/httpie/encoding.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Union, Tuple from charset_normalizer import from_bytes from charset_normalizer.constant import TOO_SMALL_SEQUENCE @@ -29,7 +29,7 @@ def detect_encoding(content: ContentBytes) -> str: return encoding -def smart_decode(content: ContentBytes, encoding: str) -> str: +def smart_decode(content: ContentBytes, encoding: str) -> Tuple[str, str]: """Decode `content` using the given `encoding`. If no `encoding` is provided, the best effort is to guess it from `content`. @@ -38,7 +38,7 @@ def smart_decode(content: ContentBytes, encoding: str) -> str: """ if not encoding: encoding = detect_encoding(content) - return content.decode(encoding, 'replace') + return content.decode(encoding, 'replace'), encoding def smart_encode(content: str, encoding: str) -> bytes: diff --git a/httpie/output/streams.py b/httpie/output/streams.py index f9492a2167..8cc17d7b2e 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -1,6 +1,6 @@ from abc import ABCMeta, abstractmethod from itertools import chain -from typing import Callable, Iterable, Union +from typing import Callable, Iterable, Optional, Union from .processing import Conversion, Formatting from ..context import Environment @@ -89,6 +89,9 @@ def iter_body(self) -> Iterable[bytes]: return self.msg.iter_body(self.chunk_size) +ENCODING_GUESS_THRESHOLD = 3 + + class EncodedStream(BaseStream): """Encoded HTTP message stream. @@ -111,7 +114,8 @@ def __init__( self.mime = mime_overwrite else: self.mime, _ = parse_content_type_header(self.msg.content_type) - self.encoding = encoding_overwrite or self.msg.encoding + self._encoding = encoding_overwrite or self.msg.encoding + self._encoding_guesses = [] if env.stdout_isatty: # Use the encoding supported by the terminal. output_encoding = env.stdout_encoding @@ -125,9 +129,33 @@ def iter_body(self) -> Iterable[bytes]: for line, lf in self.msg.iter_lines(self.CHUNK_SIZE): if b'\0' in line: raise BinarySuppressedError() - line = smart_decode(line, self.encoding) + line = self.decode_chunk(line) yield smart_encode(line, self.output_encoding) + lf + def decode_chunk(self, raw_chunk: str) -> str: + chunk, guessed_encoding = smart_decode(raw_chunk, self.encoding) + self._encoding_guesses.append(guessed_encoding) + return chunk + + @property + def encoding(self) -> Optional[str]: + if self._encoding: + return self._encoding + + # If we find a reliable (used consecutively) encoding, than + # use it for the next iterations. + if len(self._encoding_guesses) < ENCODING_GUESS_THRESHOLD: + return None + + guess_1, guess_2 = self._encoding_guesses[-2:] + if guess_1 == guess_2: + self._encoding = guess_1 + return guess_1 + + @encoding.setter + def encoding(self, value) -> None: + self._encoding = value + class PrettyStream(EncodedStream): """In addition to :class:`EncodedStream` behaviour, this stream applies @@ -178,7 +206,7 @@ def process_body(self, chunk: Union[str, bytes]) -> bytes: if not isinstance(chunk, str): # Text when a converter has been used, # otherwise it will always be bytes. - chunk = smart_decode(chunk, self.encoding) + chunk = self.decode_chunk(chunk) chunk = self.formatting.format_body(content=chunk, mime=self.mime) return smart_encode(chunk, self.output_encoding) diff --git a/tests/fixtures/__init__.py b/tests/fixtures/__init__.py index ade4492975..126b13276e 100644 --- a/tests/fixtures/__init__.py +++ b/tests/fixtures/__init__.py @@ -32,6 +32,8 @@ def patharg(path): # line would be escaped). FILE_CONTENT = FILE_PATH.read_text(encoding=UTF8).strip() +ASCII_FILE_CONTENT = "random text" * 10 + JSON_FILE_CONTENT = JSON_FILE_PATH.read_text(encoding=UTF8) BIN_FILE_CONTENT = BIN_FILE_PATH.read_bytes() diff --git a/tests/test_stream.py b/tests/test_stream.py index 55e000a6dd..fb47378bf5 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -11,7 +11,12 @@ from httpie.plugins.registry import plugin_manager from .utils import StdinBytesIO, http, MockEnvironment, DUMMY_URL -from .fixtures import BIN_FILE_CONTENT, BIN_FILE_PATH +from .fixtures import ( + ASCII_FILE_CONTENT, + BIN_FILE_CONTENT, + BIN_FILE_PATH, + FILE_CONTENT as UNICODE_FILE_CONTENT +) PRETTY_OPTIONS = list(PRETTY_MAP.keys()) @@ -133,3 +138,9 @@ def test_auto_streaming(http_server, extras, expected): for call_arg in env.stdout.write.call_args_list if b'test' in call_arg[0][0] ]) == expected + + +def test_streaming_encoding_detection(http_server): + r = http('--stream', http_server + '/stream/encoding/random') + assert ASCII_FILE_CONTENT in r + assert UNICODE_FILE_CONTENT in r diff --git a/tests/utils/http_server.py b/tests/utils/http_server.py index f09e06c2c2..fc8f2b07a2 100644 --- a/tests/utils/http_server.py +++ b/tests/utils/http_server.py @@ -52,6 +52,27 @@ def chunked_drip(handler): handler.wfile.write('0\r\n\r\n'.encode('utf-8')) +@TestHandler.handler('GET', '/stream/encoding/random') +def random_encoding(handler): + from tests.fixtures import ASCII_FILE_CONTENT, FILE_CONTENT as UNICODE_FILE_CONTENT + + handler.send_response(200) + handler.send_header('Transfer-Encoding', 'chunked') + handler.end_headers() + + for body in [ + ASCII_FILE_CONTENT, + ASCII_FILE_CONTENT, + UNICODE_FILE_CONTENT, + UNICODE_FILE_CONTENT, + UNICODE_FILE_CONTENT, + ]: + body += "\n" + handler.wfile.write(f'{len(body.encode()):X}\r\n{body}\r\n'.encode()) + + handler.wfile.write('0\r\n\r\n'.encode('utf-8')) + + @pytest.fixture(scope="function") def http_server(): """A custom HTTP server implementation for our tests, that is From be87da8bbdc1e92882c3534205909c479110a61b Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 23 Dec 2021 22:06:35 +0300 Subject: [PATCH 0951/1182] Formalize @ suffix for all operators (#1225) * Formalize @ suffix for all operators * Separate the section * Address suggestions --- docs/README.md | 49 ++++++++++++++++++++++++++++++++++---- httpie/cli/constants.py | 3 +++ httpie/cli/requestitems.py | 11 ++++++++- tests/test_cli.py | 4 +++- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index 5d1a2c11a1..ccdf53d2ab 100644 --- a/docs/README.md +++ b/docs/README.md @@ -518,6 +518,12 @@ $ http https://api.github.com/search/repositories q==httpie per_page==1 GET /search/repositories?q=httpie&per_page=1 HTTP/1.1 ``` +You can even retrieve the `value` from a file by using the `param==@file` syntax. This would also effectively strip the newlines from the end. See [#file-based-separators] for more examples. + +```bash +$ http pie.dev/get text==@files/text.txt +``` + ### URL shortcuts for `localhost` Additionally, curl-like shorthand for localhost is supported. @@ -596,21 +602,48 @@ GET /../../etc/password HTTP/1.1 ## Request items -There are a few different *request item* types that provide a convenient mechanism for specifying HTTP headers, simple JSON and form data, files, and URL parameters. +There are a few different *request item* types that provide a convenient +mechanism for specifying HTTP headers, JSON and form data, files, +and URL parameters. This is a very practical way of constructing +HTTP requests from scratch on the CLI. -They are key/value pairs specified after the URL. All have in common that they become part of the actual request that is sent and that their type is distinguished only by the separator used: `:`, `=`, `:=`, `==`, `@`, `=@`, `:=@` and `==@`. The ones with an `@` expect a file path as value. +Each *request item* is simply a key/value pair separated with the following +characters: `:` (headers), `=` (data field, e.g JSON, Form), `:=` (raw data field) +`==` (query parameters), `@` (file upload). + +```bash +$ http PUT pie.dev/put \ + X-Date:today \ # Header + token==secret \ # Query parameter + name=John \ # Data field + age:=29 # Raw JSON +``` | Item Type | Description | | -----------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | HTTP Headers `Name:Value` | Arbitrary HTTP header, e.g. `X-API-Token:123` | -| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. For reading the value from a file, use `==@`. | -| Data Fields `field=value`, `field=@file.txt` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) | +| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. | +| Data Fields `field=value` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) | | Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:=[1,2,3]` (note the quotes) | | File upload fields `field@/dir/file`, `field@file;type=mime` | Only available with `--form`, `-f` and `--multipart`. For example `screenshot@~/Pictures/img.png`, or `'cv@cv.txt;type=text/markdown'`. With `--form`, the presence of a file field results in a `--multipart` request | Note that the structured data fields aren’t the only way to specify request data: [raw request body](#raw-request-body) is a mechanism for passing arbitrary request data. +### File based separators + +Using file contents as values for specific fields is a very common use case, which can be achieved through adding the `@` suffix to +the operators above. For example instead of using a static string as the value for some header, you can use `:@` operator +to pass the desired value from a file. + +```bash +$ http POST pie.dev/post \ + X-Data:@files/text.txt # Read a header from a file + token==@files/text.txt # Read a query parameter from a file + name=@files/text.txt # Read a data field's value from a file + bookmarks:=@files/data.json # Embed a JSON object from a file +``` + ### Escaping rules You can use `\` to escape characters that shouldn’t be used as separators (or parts thereof). For instance, `foo\==bar` will become a data key/value pair (`foo=` and `bar`) instead of a URL parameter. @@ -1108,6 +1141,14 @@ Host: Any of these can be overwritten and some of them unset (see below). +### Reading headers from a file + +You can read headers from a file by using the `:@` operator. This would also effectively strip the newlines from the end. See [#file-based-separators] for more examples. + +```bash +$ http pie.dev/headers X-Data:@files/text.txt +``` + ### Empty headers and header un-setting To unset a previously specified header (such a one of the default headers), use `Header:`: diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index 577b7ba38f..ea50ce438c 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -15,6 +15,7 @@ SEPARATOR_HEADER_EMPTY = ';' SEPARATOR_CREDENTIALS = ':' SEPARATOR_PROXY = ':' +SEPARATOR_HEADER_EMBED = ':@' SEPARATOR_DATA_STRING = '=' SEPARATOR_DATA_RAW_JSON = ':=' SEPARATOR_FILE_UPLOAD = '@' @@ -41,6 +42,7 @@ # Separators for items whose value is a filename to be embedded SEPARATOR_GROUP_DATA_EMBED_ITEMS = frozenset({ + SEPARATOR_HEADER_EMBED, SEPARATOR_QUERY_EMBED_FILE, SEPARATOR_DATA_EMBED_FILE_CONTENTS, SEPARATOR_DATA_EMBED_RAW_JSON_FILE, @@ -56,6 +58,7 @@ SEPARATOR_GROUP_ALL_ITEMS = frozenset({ SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY, + SEPARATOR_HEADER_EMBED, SEPARATOR_QUERY_PARAM, SEPARATOR_QUERY_EMBED_FILE, SEPARATOR_DATA_STRING, diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index a275e7c67e..e804911e1f 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -8,7 +8,8 @@ SEPARATOR_DATA_EMBED_RAW_JSON_FILE, SEPARATOR_GROUP_NESTED_JSON_ITEMS, SEPARATOR_DATA_RAW_JSON, SEPARATOR_DATA_STRING, SEPARATOR_FILE_UPLOAD, SEPARATOR_FILE_UPLOAD_TYPE, SEPARATOR_HEADER, SEPARATOR_HEADER_EMPTY, - SEPARATOR_QUERY_PARAM, SEPARATOR_QUERY_EMBED_FILE, RequestType + SEPARATOR_HEADER_EMBED, SEPARATOR_QUERY_PARAM, + SEPARATOR_QUERY_EMBED_FILE, RequestType ) from .dicts import ( BaseMultiDict, MultipartRequestDataDict, RequestDataDict, @@ -48,6 +49,10 @@ def from_args( process_empty_header_arg, instance.headers, ), + SEPARATOR_HEADER_EMBED: ( + process_embed_header_arg, + instance.headers, + ), SEPARATOR_QUERY_PARAM: ( process_query_param_arg, instance.params, @@ -119,6 +124,10 @@ def process_header_arg(arg: KeyValueArg) -> Optional[str]: return arg.value or None +def process_embed_header_arg(arg: KeyValueArg) -> str: + return load_text_file(arg).rstrip('\n') + + def process_empty_header_arg(arg: KeyValueArg) -> str: if not arg.value: return arg.value diff --git a/tests/test_cli.py b/tests/test_cli.py index 4bb627e916..6504c8a980 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -85,6 +85,7 @@ def test_valid_items(self): self.key_value_arg('bool:=true'), self.key_value_arg('file@' + FILE_PATH_ARG), self.key_value_arg('query==value'), + self.key_value_arg('Embedded-Header:@' + FILE_PATH_ARG), self.key_value_arg('string-embed=@' + FILE_PATH_ARG), self.key_value_arg('param-embed==@' + FILE_PATH_ARG), self.key_value_arg('raw-json-embed:=@' + JSON_FILE_PATH_ARG), @@ -96,7 +97,8 @@ def test_valid_items(self): assert headers == { 'Header': 'value', 'Unset-Header': None, - 'Empty-Header': '' + 'Empty-Header': '', + 'Embedded-Header': FILE_CONTENT.rstrip('\n') } # Parsed data From e0e03f3237d625f453261ba66c02bbb1d2ca53b8 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 23 Dec 2021 22:35:30 +0300 Subject: [PATCH 0952/1182] Better DNS error handling (#1249) * Better DNS error handling * Update httpie/core.py Co-authored-by: Batuhan Taskaya Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 1 + httpie/core.py | 43 ++++++++++++++++++++++++++++++++----------- httpie/utils.py | 8 ++++++++ tests/test_errors.py | 17 +++++++++++++++++ 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5778b4a78..c02c9c07e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) - Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376)) - Added new `pie-dark`/`pie-light` (and `pie`) styles that match with [HTTPie for Web and Desktop](https://httpie.io/product). ([#1237](https://github.com/httpie/httpie/issues/1237)) +- Added support for better error handling on DNS failures. ([#1248](https://github.com/httpie/httpie/issues/1248)) - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) - Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156)) - Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/httpie/issues/1242)) diff --git a/httpie/core.py b/httpie/core.py index 48d21bc4f0..bc03686b14 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -2,6 +2,7 @@ import os import platform import sys +import socket from typing import List, Optional, Tuple, Union, Callable import requests @@ -21,6 +22,7 @@ from .output.writer import write_message, write_stream, MESSAGE_SEPARATOR_BYTES from .plugins.registry import plugin_manager from .status import ExitStatus, http_status_to_exit_status +from .utils import unwrap_context # noinspection PyDefaultArgument @@ -41,6 +43,21 @@ def raw_main( include_debug_info = '--debug' in args include_traceback = include_debug_info or '--traceback' in args + def handle_generic_error(e, annotation=None): + msg = str(e) + if hasattr(e, 'request'): + request = e.request + if hasattr(request, 'url'): + msg = ( + f'{msg} while doing a {request.method}' + f' request to URL: {request.url}' + ) + if annotation: + msg += annotation + env.log_error(f'{type(e).__name__}: {msg}') + if include_traceback: + raise + if include_debug_info: print_debug_info(env) if args == ['--debug']: @@ -90,19 +107,23 @@ def raw_main( f'Too many redirects' f' (--max-redirects={parsed_args.max_redirects}).' ) + except requests.exceptions.ConnectionError as exc: + annotation = None + original_exc = unwrap_context(exc) + if isinstance(original_exc, socket.gaierror): + if original_exc.errno == socket.EAI_AGAIN: + annotation = '\nCouldn\'t connect to a DNS server. Perhaps check your connection and try again.' + elif original_exc.errno == socket.EAI_NONAME: + annotation = '\nCouldn\'t resolve the given hostname. Perhaps check it and try again.' + propagated_exc = original_exc + else: + propagated_exc = exc + + handle_generic_error(propagated_exc, annotation=annotation) + exit_status = ExitStatus.ERROR except Exception as e: # TODO: Further distinction between expected and unexpected errors. - msg = str(e) - if hasattr(e, 'request'): - request = e.request - if hasattr(request, 'url'): - msg = ( - f'{msg} while doing a {request.method}' - f' request to URL: {request.url}' - ) - env.log_error(f'{type(e).__name__}: {msg}') - if include_traceback: - raise + handle_generic_error(e) exit_status = ExitStatus.ERROR return exit_status diff --git a/httpie/utils.py b/httpie/utils.py index 8669de8caf..fa19fa7cde 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -229,3 +229,11 @@ def split(iterable: Iterable[T], key: Callable[[T], bool]) -> Tuple[List[T], Lis else: right.append(item) return left, right + + +def unwrap_context(exc: Exception) -> Optional[Exception]: + context = exc.__context__ + if isinstance(context, Exception): + return unwrap_context(context) + else: + return exc diff --git a/tests/test_errors.py b/tests/test_errors.py index 5a1a0f2476..fca48fff15 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -1,3 +1,5 @@ +import pytest +import socket from unittest import mock from pytest import raises from requests import Request @@ -31,6 +33,21 @@ def test_error_traceback(program): http('--traceback', 'www.google.com') +@mock.patch('httpie.core.program') +@pytest.mark.parametrize("error_code, expected_message", [ + (socket.EAI_AGAIN, "check your connection"), + (socket.EAI_NONAME, "check the URL"), +]) +def test_error_custom_dns(program, error_code, expected_message): + exc = ConnectionError('Connection aborted') + exc.__context__ = socket.gaierror(error_code, "") + program.side_effect = exc + + r = http('www.google.com', tolerate_error_exit_status=True) + assert r.exit_status == ExitStatus.ERROR + assert expected_message in r.stderr + + def test_max_headers_limit(httpbin_both): with raises(ConnectionError) as e: http('--max-headers=1', httpbin_both + '/get') From f3b500119c781c16ebb870bb8a2c1c09f6bfdaee Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 23 Dec 2021 23:13:25 +0300 Subject: [PATCH 0953/1182] Implement basic metrics layout & total elapsed time (#1250) * Initial metadata processing * Dynamic coloring and other stuff * Use -vv / --meta * More testing * Cleanup * Tweek message Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 1 + docs/README.md | 26 +++++++--- httpie/cli/argparser.py | 6 ++- httpie/cli/constants.py | 10 +++- httpie/cli/definition.py | 15 +++++- httpie/core.py | 49 +++++++----------- httpie/downloads.py | 6 +-- httpie/models.py | 72 ++++++++++++++++++++++++++- httpie/output/formatters/colors.py | 22 ++++++-- httpie/output/lexers/common.py | 12 +++++ httpie/output/lexers/http.py | 16 +----- httpie/output/lexers/metadata.py | 57 +++++++++++++++++++++ httpie/output/processing.py | 5 ++ httpie/output/streams.py | 39 ++++++++++----- httpie/output/writer.py | 20 +++----- httpie/plugins/base.py | 8 +++ tests/test_downloads.py | 3 +- tests/test_meta.py | 7 +++ tests/test_output.py | 9 +++- tests/test_tokens.py | 15 ++++++ tests/utils/matching/parsing.py | 2 + tests/utils/matching/test_matching.py | 23 +++++++++ tests/utils/matching/tokens.py | 5 ++ 23 files changed, 334 insertions(+), 94 deletions(-) create mode 100644 httpie/output/lexers/common.py create mode 100644 httpie/output/lexers/metadata.py create mode 100644 tests/test_meta.py diff --git a/CHANGELOG.md b/CHANGELOG.md index c02c9c07e4..432886205c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for _receiving_ multiple HTTP headers lines with the same name. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) - Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376)) +- Added support for displaying the total elapsed time throguh `--meta`/`-vv` or `--print=m`. ([#243](https://github.com/httpie/httpie/issues/243)) - Added new `pie-dark`/`pie-light` (and `pie`) styles that match with [HTTPie for Web and Desktop](https://httpie.io/product). ([#1237](https://github.com/httpie/httpie/issues/1237)) - Added support for better error handling on DNS failures. ([#1248](https://github.com/httpie/httpie/issues/1248)) - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) diff --git a/docs/README.md b/docs/README.md index ccdf53d2ab..4befc75d5d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1497,13 +1497,15 @@ By default, HTTPie only outputs the final response and the whole response message is printed (headers as well as the body). You can control what should be printed via several options: -| Option | What is printed | -| --------------: | -------------------------------------------------------------------------------------------------- | -| `--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 below) | -| `--print, -p` | Selects parts of the HTTP exchange | -| `--quiet, -q` | Don't print anything to `stdout` and `stderr` | +| Option | What is printed | +| -------------------------: | -------------------------------------------------------------------------------------------------- | +| `--headers, -h` | Only the response headers are printed | +| `--body, -b` | Only the response body is printed | +| `--meta, -m` | Only the response metadata is printed (various metrics like total elapsed time) | +| `--verbose, -v` | Print the whole HTTP exchange (request and response). This option also enables `--all` (see below) | +| `--verbose --verbose, -vv` | Just like `-v`, but also include the response metadata. | +| `--print, -p` | Selects parts of the HTTP exchange | +| `--quiet, -q` | Don't print anything to `stdout` and `stderr` | ### What parts of the HTTP exchange should be printed @@ -1516,6 +1518,7 @@ It accepts a string of characters each of which represents a specific part of th | `B` | request body | | `h` | response headers | | `b` | response body | +| `m` | response meta | Print request and response headers: @@ -1552,6 +1555,15 @@ Server: gunicorn/0.13.4 } ``` +#### Verbosity Level: 2 + +If you run HTTPie with `-vv` or `--verbose --verbose`, then it would also display the response metadata. + +```bash +# Just like the above, but with additional columns like the total elapsed time +$ http -vv pie.dev/get +``` + ### Quiet output `--quiet` redirects all output that would otherwise go to `stdout` and `stderr` to `/dev/null` (except for errors and warnings). diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 28dcd96c0e..e243fd3c8b 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -15,7 +15,7 @@ parse_format_options, ) from .constants import ( - HTTP_GET, HTTP_POST, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, + HTTP_GET, HTTP_POST, BASE_OUTPUT_OPTIONS, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, OUTPUT_OPTIONS_DEFAULT_OFFLINE, OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED, OUT_RESP_BODY, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, RequestType, SEPARATOR_CREDENTIALS, @@ -456,8 +456,10 @@ def check_options(value, option): self.args.all = True if self.args.output_options is None: - if self.args.verbose: + if self.args.verbose >= 2: self.args.output_options = ''.join(OUTPUT_OPTIONS) + elif self.args.verbose == 1: + self.args.output_options = ''.join(BASE_OUTPUT_OPTIONS) elif self.args.offline: self.args.output_options = OUTPUT_OPTIONS_DEFAULT_OFFLINE elif not self.env.stdout_isatty: diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index ea50ce438c..6d69b9ba95 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -73,12 +73,18 @@ OUT_REQ_BODY = 'B' OUT_RESP_HEAD = 'h' OUT_RESP_BODY = 'b' +OUT_RESP_META = 'm' -OUTPUT_OPTIONS = frozenset({ +BASE_OUTPUT_OPTIONS = frozenset({ OUT_REQ_HEAD, OUT_REQ_BODY, OUT_RESP_HEAD, - OUT_RESP_BODY + OUT_RESP_BODY, +}) + +OUTPUT_OPTIONS = frozenset({ + *BASE_OUTPUT_OPTIONS, + OUT_RESP_META, }) # Pretty diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index e95e5d43c5..dca8cf1a2d 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -14,7 +14,7 @@ from .constants import ( DEFAULT_FORMAT_OPTIONS, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, OUT_REQ_BODY, OUT_REQ_HEAD, - OUT_RESP_BODY, OUT_RESP_HEAD, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, + OUT_RESP_BODY, OUT_RESP_HEAD, OUT_RESP_META, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, RequestType, SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY, SORTED_FORMAT_OPTIONS_STRING, UNSORTED_FORMAT_OPTIONS_STRING, @@ -401,6 +401,16 @@ def format_style_help(available_styles): ''' ) +output_options.add_argument( + '--meta', '-m', + dest='output_options', + action='store_const', + const=OUT_RESP_META, + help=f''' + Print only the response metadata. Shortcut for --print={OUT_RESP_META}. + + ''' +) output_options.add_argument( '--body', '-b', dest='output_options', @@ -415,7 +425,8 @@ def format_style_help(available_styles): output_options.add_argument( '--verbose', '-v', dest='verbose', - action='store_true', + action='count', + default=0, help=f''' Verbose output. Print the whole request as well as the response. Also print any intermediary requests/responses (such as redirects). diff --git a/httpie/core.py b/httpie/core.py index bc03686b14..38f67065d9 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -3,21 +3,20 @@ import platform import sys import socket -from typing import List, Optional, Tuple, Union, Callable +from typing import List, Optional, Union, Callable import requests from pygments import __version__ as pygments_version from requests import __version__ as requests_version from . import __version__ as httpie_version -from .cli.constants import OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_BODY, OUT_RESP_HEAD +from .cli.constants import OUT_REQ_BODY from .client import collect_messages from .context import Environment from .downloads import Downloader from .models import ( - RequestsMessage, RequestsMessageKind, - infer_requests_message_kind + OutputOptions, ) from .output.writer import write_message, write_stream, MESSAGE_SEPARATOR_BYTES from .plugins.registry import plugin_manager @@ -112,9 +111,9 @@ def handle_generic_error(e, annotation=None): original_exc = unwrap_context(exc) if isinstance(original_exc, socket.gaierror): if original_exc.errno == socket.EAI_AGAIN: - annotation = '\nCouldn\'t connect to a DNS server. Perhaps check your connection and try again.' + annotation = '\nCouldn’t connect to a DNS server. Please check your connection and try again.' elif original_exc.errno == socket.EAI_NONAME: - annotation = '\nCouldn\'t resolve the given hostname. Perhaps check it and try again.' + annotation = '\nCouldn’t resolve the given hostname. Please check the URL and try again.' propagated_exc = original_exc else: propagated_exc = exc @@ -153,22 +152,6 @@ def main( ) -def get_output_options( - args: argparse.Namespace, - message: RequestsMessage -) -> Tuple[bool, bool]: - return { - RequestsMessageKind.REQUEST: ( - OUT_REQ_HEAD in args.output_options, - OUT_REQ_BODY in args.output_options, - ), - RequestsMessageKind.RESPONSE: ( - OUT_RESP_HEAD in args.output_options, - OUT_RESP_BODY in args.output_options, - ), - }[infer_requests_message_kind(message)] - - def program(args: argparse.Namespace, env: Environment) -> ExitStatus: """ The main program without error handling. @@ -197,7 +180,8 @@ def request_body_read_callback(chunk: bytes): msg.is_body_upload_chunk = True msg.body = chunk msg.headers = initial_request.headers - write_message(requests_message=msg, env=env, args=args, with_body=True, with_headers=False) + msg_output_options = OutputOptions.from_message(msg, body=True, headers=False) + write_message(requests_message=msg, env=env, args=args, output_options=msg_output_options) try: if args.download: @@ -211,17 +195,17 @@ def request_body_read_callback(chunk: bytes): # Process messages as they’re generated for message in messages: - is_request = isinstance(message, requests.PreparedRequest) - with_headers, with_body = get_output_options(args=args, message=message) - do_write_body = with_body - if prev_with_body and (with_headers or with_body) and (force_separator or not env.stdout_isatty): + output_options = OutputOptions.from_message(message, args.output_options) + + do_write_body = output_options.body + if prev_with_body and output_options.any() and (force_separator or not env.stdout_isatty): # Separate after a previous message with body, if needed. See test_tokens.py. separate() force_separator = False - if is_request: + if output_options.kind is RequestsMessageKind.REQUEST: if not initial_request: initial_request = message - if with_body: + if output_options.body: is_streamed_upload = not isinstance(message.body, (str, bytes)) do_write_body = not is_streamed_upload force_separator = is_streamed_upload and env.stdout_isatty @@ -231,9 +215,10 @@ def request_body_read_callback(chunk: bytes): exit_status = http_status_to_exit_status(http_status=message.status_code, follow=args.follow) if exit_status != ExitStatus.SUCCESS and (not env.stdout_isatty or args.quiet == 1): env.log_error(f'HTTP {message.raw.status} {message.raw.reason}', level='warning') - write_message(requests_message=message, env=env, args=args, with_headers=with_headers, - with_body=do_write_body) - prev_with_body = with_body + write_message(requests_message=message, env=env, args=args, output_options=output_options._replace( + body=do_write_body + )) + prev_with_body = output_options.body # Cleanup if force_separator: diff --git a/httpie/downloads.py b/httpie/downloads.py index d8a5dd04cc..40c5271b03 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -14,7 +14,7 @@ import requests -from .models import HTTPResponse +from .models import HTTPResponse, OutputOptions from .output.streams import RawStream from .utils import humanize_bytes @@ -266,10 +266,10 @@ def start( total_size=total_size ) + output_options = OutputOptions.from_message(final_response, headers=False, body=True) stream = RawStream( msg=HTTPResponse(final_response), - with_headers=False, - with_body=True, + output_options=output_options, on_body_chunk_downloaded=self.chunk_downloaded, ) diff --git a/httpie/models.py b/httpie/models.py index af3e5a9831..e0fde8e0d4 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -1,11 +1,18 @@ import requests from enum import Enum, auto -from typing import Iterable, Union +from typing import Iterable, Union, NamedTuple from urllib.parse import urlsplit -from .utils import split_cookies, parse_content_type_header +from .cli.constants import ( + OUT_REQ_BODY, + OUT_REQ_HEAD, + OUT_RESP_BODY, + OUT_RESP_HEAD, + OUT_RESP_META +) from .compat import cached_property +from .utils import split_cookies, parse_content_type_header class HTTPMessage: @@ -27,6 +34,11 @@ def headers(self) -> str: """Return a `str` with the message's headers.""" raise NotImplementedError + @property + def metadata(self) -> str: + """Return metadata about the current message.""" + raise NotImplementedError + @cached_property def encoding(self) -> str: ct, params = parse_content_type_header(self.content_type) @@ -81,6 +93,15 @@ def headers(self): ) return '\r\n'.join(headers) + @property + def metadata(self) -> str: + data = {} + data['Elapsed time'] = str(self._orig.elapsed.total_seconds()) + 's' + return '\n'.join( + f'{key}: {value}' + for key, value in data.items() + ) + class HTTPRequest(HTTPMessage): """A :class:`requests.models.Request` wrapper.""" @@ -138,3 +159,50 @@ def infer_requests_message_kind(message: RequestsMessage) -> RequestsMessageKind return RequestsMessageKind.RESPONSE else: raise TypeError(f"Unexpected message type: {type(message).__name__}") + + +OPTION_TO_PARAM = { + RequestsMessageKind.REQUEST: { + 'headers': OUT_REQ_HEAD, + 'body': OUT_REQ_BODY, + }, + RequestsMessageKind.RESPONSE: { + 'headers': OUT_RESP_HEAD, + 'body': OUT_RESP_BODY, + 'meta': OUT_RESP_META + } +} + + +class OutputOptions(NamedTuple): + kind: RequestsMessageKind + headers: bool + body: bool + meta: bool = False + + def any(self): + return ( + self.headers + or self.body + or self.meta + ) + + @classmethod + def from_message( + cls, + message: RequestsMessage, + raw_args: str = '', + **kwargs + ): + kind = infer_requests_message_kind(message) + + options = { + option: param in raw_args + for option, param in OPTION_TO_PARAM[kind].items() + } + options.update(kwargs) + + return cls( + kind=kind, + **options + ) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 757163f84b..454dc1154d 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -16,6 +16,7 @@ from pygments.util import ClassNotFound from ..lexers.json import EnhancedJsonLexer +from ..lexers.metadata import MetadataLexer from ..ui.palette import SHADE_NAMES, get_color from ...compat import is_windows from ...context import Environment @@ -50,6 +51,7 @@ class ColorFormatter(FormatterPlugin): """ group_name = 'colors' + metadata_lexer = MetadataLexer() def __init__( self, @@ -68,9 +70,8 @@ def __init__( has_256_colors = env.colors == 256 if use_auto_style or not has_256_colors: http_lexer = PygmentsHttpLexer() - formatter = TerminalFormatter() - body_formatter = formatter - header_formatter = formatter + body_formatter = header_formatter = TerminalFormatter() + precise = False else: from ..lexers.http import SimplifiedHTTPLexer header_formatter, body_formatter, precise = self.get_formatters(color_scheme) @@ -80,6 +81,7 @@ def __init__( self.header_formatter = header_formatter self.body_formatter = body_formatter self.http_lexer = http_lexer + self.metadata_lexer = MetadataLexer(precise=precise) def format_headers(self, headers: str) -> str: return pygments.highlight( @@ -98,6 +100,13 @@ def format_body(self, body: str, mime: str) -> str: ) return body + def format_metadata(self, metadata: str) -> str: + return pygments.highlight( + code=metadata, + lexer=self.metadata_lexer, + formatter=self.header_formatter, + ).strip() + def get_lexer_for_body( self, mime: str, body: str @@ -288,6 +297,13 @@ class Solarized256Style(pygments.style.Style): pygments.token.Number.HTTP.REDIRECT: 'bold yellow', pygments.token.Number.HTTP.CLIENT_ERR: 'bold orange', pygments.token.Number.HTTP.SERVER_ERR: 'bold red', + + # Metadata + pygments.token.Name.Decorator: 'grey', + pygments.token.Number.SPEED.FAST: 'bold green', + pygments.token.Number.SPEED.AVG: 'bold yellow', + pygments.token.Number.SPEED.SLOW: 'bold orange', + pygments.token.Number.SPEED.VERY_SLOW: 'bold red', } PIE_BODY_STYLE = { diff --git a/httpie/output/lexers/common.py b/httpie/output/lexers/common.py new file mode 100644 index 0000000000..e2cdc3cc1a --- /dev/null +++ b/httpie/output/lexers/common.py @@ -0,0 +1,12 @@ +def precise(lexer, precise_token, parent_token): + # Due to a pygments bug*, custom tokens will look bad + # on outside styles. Until it is fixed on upstream, we'll + # convey whether the client is using pie style or not + # through precise option and return more precise tokens + # depending on it's value. + # + # [0]: https://github.com/pygments/pygments/issues/1986 + if precise_token is None or not lexer.options.get("precise"): + return parent_token + else: + return precise_token diff --git a/httpie/output/lexers/http.py b/httpie/output/lexers/http.py index 0b8b612a0e..f06a685380 100644 --- a/httpie/output/lexers/http.py +++ b/httpie/output/lexers/http.py @@ -1,6 +1,6 @@ import re import pygments - +from httpie.output.lexers.common import precise RE_STATUS_LINE = re.compile(r'(\d{3})( +)(.+)') @@ -22,20 +22,6 @@ } -def precise(lexer, precise_token, parent_token): - # Due to a pygments bug*, custom tokens will look bad - # on outside styles. Until it is fixed on upstream, we'll - # convey whether the client is using pie style or not - # through precise option and return more precise tokens - # depending on it's value. - # - # [0]: https://github.com/pygments/pygments/issues/1986 - if precise_token is None or not lexer.options.get("precise"): - return parent_token - else: - return precise_token - - def http_response_type(lexer, match, ctx): status_match = RE_STATUS_LINE.match(match.group()) if status_match is None: diff --git a/httpie/output/lexers/metadata.py b/httpie/output/lexers/metadata.py new file mode 100644 index 0000000000..d0216d5eea --- /dev/null +++ b/httpie/output/lexers/metadata.py @@ -0,0 +1,57 @@ +import pygments +from httpie.output.lexers.common import precise + +SPEED_TOKENS = { + 0.45: pygments.token.Number.SPEED.FAST, + 1.00: pygments.token.Number.SPEED.AVG, + 2.50: pygments.token.Number.SPEED.SLOW, +} + + +def speed_based_token(lexer, match, ctx): + try: + value = float(match.group()) + except ValueError: + return pygments.token.Number + + for limit, token in SPEED_TOKENS.items(): + if value <= limit: + break + else: + token = pygments.token.Number.SPEED.VERY_SLOW + + response_type = precise( + lexer, + token, + pygments.token.Number + ) + yield match.start(), response_type, match.group() + + +class MetadataLexer(pygments.lexer.RegexLexer): + """Simple HTTPie metadata lexer.""" + + tokens = { + 'root': [ + ( + r'(Elapsed time)( *)(:)( *)(\d+\.\d+)(s)', pygments.lexer.bygroups( + pygments.token.Name.Decorator, # Name + pygments.token.Text, + pygments.token.Operator, # Colon + pygments.token.Text, + speed_based_token, + pygments.token.Name.Builtin # Value + ) + ), + # Generic item + ( + r'(.*?)( *)(:)( *)(.+)', pygments.lexer.bygroups( + pygments.token.Name.Decorator, # Name + pygments.token.Text, + pygments.token.Operator, # Colon + pygments.token.Text, + pygments.token.Text # Value + ) + ), + ] + } diff --git a/httpie/output/processing.py b/httpie/output/processing.py index ddee9ca9c3..54a8f379e9 100644 --- a/httpie/output/processing.py +++ b/httpie/output/processing.py @@ -51,3 +51,8 @@ def format_body(self, content: str, mime: str) -> str: for p in self.enabled_plugins: content = p.format_body(content, mime) return content + + def format_metadata(self, metadata: str) -> str: + for p in self.enabled_plugins: + metadata = p.format_metadata(metadata) + return metadata diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 8cc17d7b2e..4371af39f9 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -5,7 +5,7 @@ from .processing import Conversion, Formatting from ..context import Environment from ..encoding import smart_decode, smart_encode, UTF8 -from ..models import HTTPMessage +from ..models import HTTPMessage, OutputOptions from ..utils import parse_content_type_header @@ -33,47 +33,58 @@ class BaseStream(metaclass=ABCMeta): def __init__( self, msg: HTTPMessage, - with_headers=True, - with_body=True, + output_options: OutputOptions, on_body_chunk_downloaded: Callable[[bytes], None] = None ): """ :param msg: a :class:`models.HTTPMessage` subclass - :param with_headers: if `True`, headers will be included - :param with_body: if `True`, body will be included - + :param output_options: a :class:`OutputOptions` instance to represent + which parts of the message is printed. """ - assert with_headers or with_body + assert output_options.any() self.msg = msg - self.with_headers = with_headers - self.with_body = with_body + self.output_options = output_options self.on_body_chunk_downloaded = on_body_chunk_downloaded def get_headers(self) -> bytes: """Return the headers' bytes.""" return self.msg.headers.encode() + def get_metadata(self) -> bytes: + """Return the message metadata.""" + return self.msg.metadata.encode() + @abstractmethod def iter_body(self) -> Iterable[bytes]: """Return an iterator over the message body.""" def __iter__(self) -> Iterable[bytes]: """Return an iterator over `self.msg`.""" - if self.with_headers: + if self.output_options.headers: yield self.get_headers() yield b'\r\n\r\n' - if self.with_body: + if self.output_options.body: try: for chunk in self.iter_body(): yield chunk if self.on_body_chunk_downloaded: self.on_body_chunk_downloaded(chunk) except DataSuppressedError as e: - if self.with_headers: + if self.output_options.headers: yield b'\n' yield e.message + if self.output_options.meta: + mixed = self.output_options.headers or self.output_options.body + + if mixed: + yield b'\n\n' + + yield self.get_metadata() + if not mixed: + yield b'\n' + class RawStream(BaseStream): """The message is streamed in chunks with no processing.""" @@ -181,6 +192,10 @@ def get_headers(self) -> bytes: return self.formatting.format_headers( self.msg.headers).encode(self.output_encoding) + def get_metadata(self) -> bytes: + return self.formatting.format_metadata( + self.msg.metadata).encode(self.output_encoding) + def iter_body(self) -> Iterable[bytes]: first_chunk = True iter_lines = self.msg.iter_lines(self.CHUNK_SIZE) diff --git a/httpie/output/writer.py b/httpie/output/writer.py index cd3eec979b..0a911560ca 100644 --- a/httpie/output/writer.py +++ b/httpie/output/writer.py @@ -10,7 +10,7 @@ HTTPMessage, RequestsMessage, RequestsMessageKind, - infer_requests_message_kind + OutputOptions ) from .processing import Conversion, Formatting from .streams import ( @@ -26,18 +26,16 @@ def write_message( requests_message: RequestsMessage, env: Environment, args: argparse.Namespace, - with_headers=False, - with_body=False, + output_options: OutputOptions, ): - if not (with_body or with_headers): + if not output_options.any(): return write_stream_kwargs = { 'stream': build_output_stream_for_message( args=args, env=env, requests_message=requests_message, - with_body=with_body, - with_headers=with_headers, + output_options=output_options, ), # NOTE: `env.stdout` will in fact be `stderr` with `--download` 'outfile': env.stdout, @@ -100,13 +98,12 @@ def build_output_stream_for_message( args: argparse.Namespace, env: Environment, requests_message: RequestsMessage, - with_headers: bool, - with_body: bool, + output_options: OutputOptions, ): message_type = { RequestsMessageKind.REQUEST: HTTPRequest, RequestsMessageKind.RESPONSE: HTTPResponse, - }[infer_requests_message_kind(requests_message)] + }[output_options.kind] stream_class, stream_kwargs = get_stream_type_and_kwargs( env=env, args=args, @@ -115,11 +112,10 @@ def build_output_stream_for_message( ) yield from stream_class( msg=message_type(requests_message), - with_headers=with_headers, - with_body=with_body, + output_options=output_options, **stream_kwargs, ) - if (env.stdout_isatty and with_body + if (env.stdout_isatty and output_options.body and not getattr(requests_message, 'is_body_upload_chunk', False)): # Ensure a blank line after the response body. # For terminal output only. diff --git a/httpie/plugins/base.py b/httpie/plugins/base.py index f933342e51..1b44e5aec5 100644 --- a/httpie/plugins/base.py +++ b/httpie/plugins/base.py @@ -155,3 +155,11 @@ def format_body(self, content: str, mime: str) -> str: """ return content + + def format_metadata(self, metadata: str) -> str: + """Return processed `metadata`. + + :param metadata: The metadata as text. + + """ + return metadata diff --git a/tests/test_downloads.py b/tests/test_downloads.py index 9b6d38f980..9a567d88d6 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -1,6 +1,7 @@ import os import tempfile import time +import requests from unittest import mock from urllib.request import urlopen @@ -14,7 +15,7 @@ from .utils import http, MockEnvironment -class Response: +class Response(requests.Response): # noinspection PyDefaultArgument def __init__(self, url, headers={}, status_code=200): self.url = url diff --git a/tests/test_meta.py b/tests/test_meta.py new file mode 100644 index 0000000000..f9c1bc270c --- /dev/null +++ b/tests/test_meta.py @@ -0,0 +1,7 @@ +from .utils import http + + +def test_meta_elapsed_time(httpbin, monkeypatch): + r = http('--meta', httpbin + '/get') + for line in r.splitlines(): + assert 'Elapsed time' in r diff --git a/tests/test_output.py b/tests/test_output.py index f310b24e15..4d9587b38b 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -17,7 +17,7 @@ ) from httpie.cli.definition import parser from httpie.encoding import UTF8 -from httpie.output.formatters.colors import get_lexer +from httpie.output.formatters.colors import PIE_STYLES, get_lexer from httpie.status import ExitStatus from .fixtures import XML_DATA_RAW, XML_DATA_FORMATTED from .utils import COLOR, CRLF, HTTP_OK, MockEnvironment, http, DUMMY_URL @@ -227,6 +227,13 @@ def test_ensure_contents_colored(httpbin, endpoint): assert COLOR in r +@pytest.mark.parametrize('style', PIE_STYLES.keys()) +def test_ensure_meta_is_colored(httpbin, style): + env = MockEnvironment(colors=256) + r = http('--meta', '--style', style, 'GET', httpbin + '/get', env=env) + assert COLOR in r + + class TestPrettyOptions: """Test the --pretty handling.""" diff --git a/tests/test_tokens.py b/tests/test_tokens.py index 7281b2a334..655445ce49 100644 --- a/tests/test_tokens.py +++ b/tests/test_tokens.py @@ -101,3 +101,18 @@ def test_verbose_chunked(httpbin_with_chunked_support): def test_request_headers_response_body(httpbin): r = http('--print=Hb', httpbin + '/get') assert_output_matches(r, ExpectSequence.TERMINAL_REQUEST) + + +def test_request_single_verbose(httpbin): + r = http('-v', httpbin + '/post', 'hello=world') + assert_output_matches(r, ExpectSequence.TERMINAL_EXCHANGE) + + +def test_request_double_verbose(httpbin): + r = http('-vv', httpbin + '/post', 'hello=world') + assert_output_matches(r, ExpectSequence.TERMINAL_EXCHANGE_META) + + +def test_request_meta(httpbin): + r = http('--meta', httpbin + '/get') + assert_output_matches(r, [Expect.RESPONSE_META]) diff --git a/tests/utils/matching/parsing.py b/tests/utils/matching/parsing.py index 998fe9a4e1..e502d76bc8 100644 --- a/tests/utils/matching/parsing.py +++ b/tests/utils/matching/parsing.py @@ -7,6 +7,7 @@ SEPARATOR_RE = re.compile(f'^{MESSAGE_SEPARATOR}') +KEY_VALUE_RE = re.compile(r'[\n]*((.*?):(.+)[\n]?)+[\n]*') def make_headers_re(message_type: Expect): @@ -43,6 +44,7 @@ def make_headers_re(message_type: Expect): TOKEN_REGEX_MAP = { Expect.REQUEST_HEADERS: make_headers_re(Expect.REQUEST_HEADERS), Expect.RESPONSE_HEADERS: make_headers_re(Expect.RESPONSE_HEADERS), + Expect.RESPONSE_META: KEY_VALUE_RE, Expect.SEPARATOR: SEPARATOR_RE, } diff --git a/tests/utils/matching/test_matching.py b/tests/utils/matching/test_matching.py index 649884aafe..2e7735a6d3 100644 --- a/tests/utils/matching/test_matching.py +++ b/tests/utils/matching/test_matching.py @@ -107,6 +107,29 @@ def test_assert_output_matches_headers_with_body_and_separator(): ) +def test_assert_output_matches_response_meta(): + assert_output_matches( + ( + 'Key: Value\n' + 'Elapsed Time: 3.3s' + ), + [Expect.RESPONSE_META] + ) + + +def test_assert_output_matches_whole_response(): + assert_output_matches( + ( + f'HTTP/1.1{CRLF}' + f'AAA:BBB{CRLF}' + f'{CRLF}' + f'CCC{MESSAGE_SEPARATOR}' + 'Elapsed Time: 3.3s' + ), + [Expect.RESPONSE_HEADERS, Expect.BODY, Expect.RESPONSE_META] + ) + + def test_assert_output_matches_multiple_messages(): assert_output_matches( ( diff --git a/tests/utils/matching/tokens.py b/tests/utils/matching/tokens.py index 61bc7234c7..c82dafedc2 100644 --- a/tests/utils/matching/tokens.py +++ b/tests/utils/matching/tokens.py @@ -8,6 +8,7 @@ class Expect(Enum): """ REQUEST_HEADERS = auto() RESPONSE_HEADERS = auto() + RESPONSE_META = auto() BODY = auto() SEPARATOR = auto() @@ -45,6 +46,10 @@ class ExpectSequence: *TERMINAL_REQUEST, *TERMINAL_RESPONSE, ] + TERMINAL_EXCHANGE_META = [ + *TERMINAL_EXCHANGE, + Expect.RESPONSE_META + ] TERMINAL_BODY = [ RAW_BODY, Expect.SEPARATOR From 747accc2ae19eb7b111e7398bbcf9b17e52ee054 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 24 Dec 2021 11:50:19 +0300 Subject: [PATCH 0954/1182] Include response metadata in --print help --- httpie/cli/definition.py | 1 + 1 file changed, 1 insertion(+) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index dca8cf1a2d..42c9a200b7 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -383,6 +383,7 @@ def format_style_help(available_styles): '{OUT_REQ_BODY}' request body '{OUT_RESP_HEAD}' response headers '{OUT_RESP_BODY}' response body + '{OUT_RESP_META}' response metadata The default behaviour is '{OUTPUT_OPTIONS_DEFAULT}' (i.e., the response headers and body is printed), if standard output is not redirected. From c6926695263deb881b0034530d35fb36b45a5c21 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 24 Dec 2021 11:51:11 +0300 Subject: [PATCH 0955/1182] Fix -v docs to include BASE_OUTPUT_OPTIONS --- httpie/cli/definition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 42c9a200b7..7c03fc12ec 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -12,7 +12,7 @@ readable_file_arg, response_charset_type, response_mime_type, ) from .constants import ( - DEFAULT_FORMAT_OPTIONS, OUTPUT_OPTIONS, + DEFAULT_FORMAT_OPTIONS, BASE_OUTPUT_OPTIONS, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_BODY, OUT_RESP_HEAD, OUT_RESP_META, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, RequestType, SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY, @@ -431,7 +431,7 @@ def format_style_help(available_styles): help=f''' Verbose output. Print the whole request as well as the response. Also print any intermediary requests/responses (such as redirects). - It's a shortcut for: --all --print={''.join(OUTPUT_OPTIONS)} + It's a shortcut for: --all --print={''.join(BASE_OUTPUT_OPTIONS)} ''' ) From 0ebc9a7e09d2a04b3a79a37df695512f876dcf6e Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 24 Dec 2021 11:53:15 +0300 Subject: [PATCH 0956/1182] Mention about levels in -v --- httpie/cli/definition.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 7c03fc12ec..02beeb13e2 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -429,10 +429,10 @@ def format_style_help(available_styles): action='count', default=0, help=f''' - Verbose output. Print the whole request as well as the response. Also print - any intermediary requests/responses (such as redirects). - It's a shortcut for: --all --print={''.join(BASE_OUTPUT_OPTIONS)} - + Verbose output. For the level one (with single `-v`/`--verbose`), print + the whole request as well as the response. Also print any intermediary + requests/responses (such as redirects). For the second level and higher, + print these as well as the response metadata. ''' ) output_options.add_argument( From 05c02f0f398ffdac07723ef31ce021782866bb26 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 24 Dec 2021 11:53:31 +0300 Subject: [PATCH 0957/1182] Update shortcuts as well --- httpie/cli/definition.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 02beeb13e2..5ccc3a16f9 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -433,6 +433,9 @@ def format_style_help(available_styles): the whole request as well as the response. Also print any intermediary requests/responses (such as redirects). For the second level and higher, print these as well as the response metadata. + + Level one is a shortcut for: --all --print={''.join(BASE_OUTPUT_OPTIONS)} + Level two is a shortcut for: --all --print={''.join(OUTPUT_OPTIONS)} ''' ) output_options.add_argument( From 17ed3bb8c519fc6e0cc62fa3bb0fc10929de2595 Mon Sep 17 00:00:00 2001 From: Sebastian Czech Date: Wed, 29 Dec 2021 10:00:47 +0100 Subject: [PATCH 0958/1182] Store prompted passwords in local sessions (#1239) Co-authored-by: Batuhan Taskaya --- httpie/cli/argparser.py | 4 ++++ tests/test_sessions.py | 31 +++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index e243fd3c8b..64481096c7 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -296,6 +296,10 @@ def _process_auth(self): ' --ignore-stdin is set.' ) credentials.prompt_password(url.netloc) + + if (credentials.key and credentials.value): + plugin.raw_auth = credentials.key + ":" + credentials.value + self.args.auth = plugin.get_auth( username=credentials.key, password=credentials.value, diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 5615c08f05..5835993605 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -15,6 +15,7 @@ from httpie.utils import get_expired_cookies from .test_auth_plugins import basic_auth from .utils import HTTP_OK, MockEnvironment, http, mk_config_dir +from base64 import b64encode class SessionTestBase: @@ -298,8 +299,6 @@ def get_auth(self, username=None, password=None): assert f'Authorization: {header}' in r2 plugin_manager.unregister(Plugin) - @mock.patch('httpie.cli.argtypes.AuthCredentials._getpass', - new=lambda self, prompt: 'password') def test_auth_plugin_prompt_password_in_session(self, httpbin): self.start_session(httpbin) session_path = self.config_dir / 'test-session.json' @@ -308,17 +307,22 @@ class Plugin(AuthPlugin): auth_type = 'test-prompted' def get_auth(self, username=None, password=None): - return basic_auth() + basic_auth_header = "Basic " + b64encode(self.raw_auth.encode()).strip().decode('latin1') + return basic_auth(basic_auth_header) plugin_manager.register(Plugin) - r1 = http( - '--session', str(session_path), - httpbin + '/basic-auth/user/password', - '--auth-type', - Plugin.auth_type, - '--auth', 'user:', - ) + with mock.patch( + 'httpie.cli.argtypes.AuthCredentials._getpass', + new=lambda self, prompt: 'password' + ): + r1 = http( + '--session', str(session_path), + httpbin + '/basic-auth/user/password', + '--auth-type', + Plugin.auth_type, + '--auth', 'user', + ) r2 = http( '--session', str(session_path), @@ -326,6 +330,13 @@ def get_auth(self, username=None, password=None): ) assert HTTP_OK in r1 assert HTTP_OK in r2 + + # additional test for issue: https://github.com/httpie/httpie/issues/1098 + with open(session_path) as session_file: + session_file_lines = ''.join(session_file.readlines()) + assert "\"type\": \"test-prompted\"" in session_file_lines + assert "\"raw_auth\": \"user:password\"" in session_file_lines + plugin_manager.unregister(Plugin) def test_auth_type_stored_in_session_file(self, httpbin): From 8d84248ee3f40f8bccb5d83ce07668704b5a1901 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 29 Dec 2021 12:01:49 +0300 Subject: [PATCH 0959/1182] Add the changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 432886205c..af5f701be9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for displaying the total elapsed time throguh `--meta`/`-vv` or `--print=m`. ([#243](https://github.com/httpie/httpie/issues/243)) - Added new `pie-dark`/`pie-light` (and `pie`) styles that match with [HTTPie for Web and Desktop](https://httpie.io/product). ([#1237](https://github.com/httpie/httpie/issues/1237)) - Added support for better error handling on DNS failures. ([#1248](https://github.com/httpie/httpie/issues/1248)) +- Added support for storing prompted passwords in the local sessions. - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) - Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156)) - Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/httpie/issues/1242)) From 06512c72a3d7cb6b387dfcd76f22bd42a2075614 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 29 Dec 2021 12:02:24 +0300 Subject: [PATCH 0960/1182] Include the original issue in the changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af5f701be9..c831fd10fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for displaying the total elapsed time throguh `--meta`/`-vv` or `--print=m`. ([#243](https://github.com/httpie/httpie/issues/243)) - Added new `pie-dark`/`pie-light` (and `pie`) styles that match with [HTTPie for Web and Desktop](https://httpie.io/product). ([#1237](https://github.com/httpie/httpie/issues/1237)) - Added support for better error handling on DNS failures. ([#1248](https://github.com/httpie/httpie/issues/1248)) -- Added support for storing prompted passwords in the local sessions. +- Added support for storing prompted passwords in the local sessions. ([#1098](https://github.com/httpie/httpie/issues/1098)) - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) - Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156)) - Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/httpie/issues/1242)) From 0e10e23dca078183ce34f3ee17809d94a46a973e Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 29 Dec 2021 12:03:44 +0300 Subject: [PATCH 0961/1182] Mention explicitly about prompted passwords are stored as raw in the docs --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 4befc75d5d..2b7abcdd4a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2014,7 +2014,7 @@ $ cat session.json $ http --session=./session.json pie.dev/headers ``` -All session data, including credentials, cookie data, and custom headers are stored in plain text. +All session data, including credentials, prompted passwords, 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. It also means that they can be read by anyone who has access to the session file. From 4c56d894ba9e2bb1c097a3a6067006843ac2944d Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 29 Dec 2021 12:41:44 +0300 Subject: [PATCH 0962/1182] Fix --raw with --chunked (#1254) * Fix --raw with --chunked * Better naming / annotations * More annotations --- CHANGELOG.md | 1 + httpie/client.py | 36 ++++++---- httpie/uploads.py | 158 ++++++++++++++++++++++++++---------------- tests/test_uploads.py | 13 ++++ 4 files changed, 133 insertions(+), 75 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c831fd10fd..323249350d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) - Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156)) - Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/httpie/issues/1242)) +- Fixed an unexpected crash when `--raw` is used with `--chunked`. ([#1253](https://github.com/httpie/httpie/issues/1253)) ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) diff --git a/httpie/client.py b/httpie/client.py index ba0cc77332..dcf248261e 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -4,7 +4,7 @@ import sys from contextlib import contextmanager from pathlib import Path -from typing import Callable, Iterable +from typing import Any, Dict, Callable, Iterable from urllib.parse import urlparse, urlunparse import requests @@ -273,6 +273,24 @@ def make_send_kwargs_mergeable_from_env(args: argparse.Namespace) -> dict: } +def json_dict_to_request_body(data: Dict[str, Any]) -> str: + # Propagate the top-level list if there is only one + # item in the object, with an en empty key. + if len(data) == 1: + [(key, value)] = data.items() + if key == '' and isinstance(value, list): + data = value + + if data: + data = json.dumps(data) + else: + # We need to set data to an empty string to prevent requests + # from assigning an empty list to `response.request.data`. + data = '' + + return data + + def make_request_kwargs( args: argparse.Namespace, base_headers: HTTPHeadersDict = None, @@ -287,19 +305,7 @@ def make_request_kwargs( data = args.data auto_json = data and not args.form if (args.json or auto_json) and isinstance(data, dict): - # Propagate the top-level list if there is only one - # item in the object, with an en empty key. - if len(data) == 1: - [(key, value)] = data.items() - if key == '' and isinstance(value, list): - data = value - - if data: - data = json.dumps(data) - else: - # We need to set data to an empty string to prevent requests - # from assigning an empty list to `response.request.data`. - data = '' + data = json_dict_to_request_body(data) # Finalize headers. headers = make_default_headers(args) @@ -324,7 +330,7 @@ def make_request_kwargs( 'url': args.url, 'headers': headers, 'data': prepare_request_body( - body=data, + data, body_read_callback=request_body_read_callback, chunked=args.chunked, offline=args.offline, diff --git a/httpie/uploads.py b/httpie/uploads.py index c3c4e766db..0bb307e5cf 100644 --- a/httpie/uploads.py +++ b/httpie/uploads.py @@ -1,5 +1,6 @@ import zlib -from typing import Callable, IO, Iterable, Tuple, Union, TYPE_CHECKING +import functools +from typing import Any, Callable, IO, Iterable, Optional, Tuple, Union, TYPE_CHECKING from urllib.parse import urlencode import requests @@ -11,7 +12,12 @@ from .cli.dicts import MultipartRequestDataDict, RequestDataDict -class ChunkedUploadStream: +class ChunkedStream: + def __iter__(self) -> Iterable[Union[str, bytes]]: + raise NotImplementedError + + +class ChunkedUploadStream(ChunkedStream): def __init__(self, stream: Iterable, callback: Callable): self.callback = callback self.stream = stream @@ -22,7 +28,7 @@ def __iter__(self) -> Iterable[Union[str, bytes]]: yield chunk -class ChunkedMultipartUploadStream: +class ChunkedMultipartUploadStream(ChunkedStream): chunk_size = 100 * 1024 def __init__(self, encoder: 'MultipartEncoder'): @@ -36,69 +42,101 @@ def __iter__(self) -> Iterable[Union[str, bytes]]: yield chunk -def prepare_request_body( - body: Union[str, bytes, IO, 'MultipartEncoder', RequestDataDict], - body_read_callback: Callable[[bytes], bytes], - content_length_header_value: int = None, - chunked=False, - offline=False, -) -> Union[str, bytes, IO, 'MultipartEncoder', ChunkedUploadStream]: +def as_bytes(data: Union[str, bytes]) -> bytes: + if isinstance(data, str): + return data.encode() + else: + return data + + +CallbackT = Callable[[bytes], bytes] + + +def _wrap_function_with_callback( + func: Callable[..., Any], + callback: CallbackT +) -> Callable[..., Any]: + @functools.wraps(func) + def wrapped(*args, **kwargs): + chunk = func(*args, **kwargs) + callback(chunk) + return chunk + return wrapped + + +def _prepare_file_for_upload( + file: Union[IO, 'MultipartEncoder'], + callback: CallbackT, + chunked: bool = False, + content_length_header_value: Optional[int] = None, +) -> Union[bytes, IO, ChunkedStream]: + if not super_len(file): + # Zero-length -> assume stdin. + if content_length_header_value is None and not chunked: + # Read the whole stdin to determine `Content-Length`. + # + # TODO: Instead of opt-in --chunked, consider making + # `Transfer-Encoding: chunked` for STDIN opt-out via + # something like --no-chunked. + # This would be backwards-incompatible so wait until v3.0.0. + # + file = as_bytes(file.read()) + else: + file.read = _wrap_function_with_callback( + file.read, + callback + ) + + if chunked: + from requests_toolbelt import MultipartEncoder + if isinstance(file, MultipartEncoder): + return ChunkedMultipartUploadStream( + encoder=file, + ) + else: + return ChunkedUploadStream( + stream=file, + callback=callback, + ) + else: + return file - is_file_like = hasattr(body, 'read') - if isinstance(body, RequestDataDict): - body = urlencode(body, doseq=True) +def prepare_request_body( + raw_body: Union[str, bytes, IO, 'MultipartEncoder', RequestDataDict], + body_read_callback: CallbackT, + offline: bool = False, + chunked: bool = False, + content_length_header_value: Optional[int] = None, +) -> Union[bytes, IO, 'MultipartEncoder', ChunkedStream]: + is_file_like = hasattr(raw_body, 'read') + if isinstance(raw_body, (bytes, str)): + body = as_bytes(raw_body) + elif isinstance(raw_body, RequestDataDict): + body = as_bytes(urlencode(raw_body, doseq=True)) + else: + body = raw_body if offline: if is_file_like: - return body.read() - return body - - if not is_file_like: - if chunked: - body = ChunkedUploadStream( - # Pass the entire body as one chunk. - stream=(chunk.encode() for chunk in [body]), - callback=body_read_callback, - ) - else: - # File-like object. - - if not super_len(body): - # Zero-length -> assume stdin. - if content_length_header_value is None and not chunked: - # - # Read the whole stdin to determine `Content-Length`. - # - # TODO: Instead of opt-in --chunked, consider making - # `Transfer-Encoding: chunked` for STDIN opt-out via - # something like --no-chunked. - # This would be backwards-incompatible so wait until v3.0.0. - # - body = body.read() + return as_bytes(raw_body.read()) else: - orig_read = body.read - - def new_read(*args): - chunk = orig_read(*args) - body_read_callback(chunk) - return chunk - - body.read = new_read - - if chunked: - from requests_toolbelt import MultipartEncoder - if isinstance(body, MultipartEncoder): - body = ChunkedMultipartUploadStream( - encoder=body, - ) - else: - body = ChunkedUploadStream( - stream=body, - callback=body_read_callback, - ) - - return body + return body + + if is_file_like: + return _prepare_file_for_upload( + body, + chunked=chunked, + callback=body_read_callback, + content_length_header_value=content_length_header_value + ) + elif chunked: + return ChunkedUploadStream( + stream=iter([body]), + callback=body_read_callback + ) + else: + return body def get_multipart_data_and_content_type( diff --git a/tests/test_uploads.py b/tests/test_uploads.py index 2c7014771a..28d427aebe 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -1,4 +1,5 @@ import os +import json import pytest @@ -70,6 +71,18 @@ def test_chunked_stdin_multiple_chunks(httpbin_with_chunked_support): assert r.count(FILE_CONTENT) == 4 +def test_chunked_raw(httpbin_with_chunked_support): + r = http( + '--verbose', + '--chunked', + httpbin_with_chunked_support + '/post', + '--raw', + json.dumps({'a': 1, 'b': '2fafds', 'c': '🥰'}), + ) + assert HTTP_OK in r + assert 'Transfer-Encoding: chunked' in r + + class TestMultipartFormDataFileUpload: def test_non_existent_file_raises_parse_error(self, httpbin): From 508788ca5688bbdfba24b1a810d3091c78eccf46 Mon Sep 17 00:00:00 2001 From: Greg Myers Date: Mon, 10 Jan 2022 03:48:42 -0700 Subject: [PATCH 0963/1182] Fix two typos in docs/README.md (#1261) contaning -> containing overwriten -> overwritten Co-authored-by: greg --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 2b7abcdd4a..6b19b91aa0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -441,7 +441,7 @@ There are no restrictions regarding which request methods can include a body. Yo $ http POST pie.dev/post ``` -You can also make `GET` requests contaning a body: +You can also make `GET` requests containing a body: ```bash $ http GET pie.dev/get hello=world @@ -1193,7 +1193,7 @@ GET / HTTP/1.1 Numbers: one,two ``` -Also be aware that if the current session contains any headers they will get overwriten +Also be aware that if the current session contains any headers they will get overwritten by individual commands when sending a request instead of being joined together. ### Limiting response headers From 00c859c51d725159249aa6fda812a775e352f21b Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 12 Jan 2022 17:07:34 +0300 Subject: [PATCH 0964/1182] Add warnings when there is no incoming data from stdin (#1256) * Add warnings when there is no incoming data from stdin * Pass os.environ as well * Apply suggestions --- CHANGELOG.md | 1 + httpie/client.py | 9 +++-- httpie/core.py | 2 +- httpie/uploads.py | 51 ++++++++++++++++++++++++++ tests/test_uploads.py | 85 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 144 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 323249350d..cd73afcc22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added new `pie-dark`/`pie-light` (and `pie`) styles that match with [HTTPie for Web and Desktop](https://httpie.io/product). ([#1237](https://github.com/httpie/httpie/issues/1237)) - Added support for better error handling on DNS failures. ([#1248](https://github.com/httpie/httpie/issues/1248)) - Added support for storing prompted passwords in the local sessions. ([#1098](https://github.com/httpie/httpie/issues/1098)) +- Added warnings about the `--ignore-stdin`, when there is no incoming data from stdin. ([#1255](https://github.com/httpie/httpie/issues/1255)) - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) - Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156)) - Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/httpie/issues/1242)) diff --git a/httpie/client.py b/httpie/client.py index dcf248261e..58575fe63b 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -3,7 +3,6 @@ import json import sys from contextlib import contextmanager -from pathlib import Path from typing import Any, Dict, Callable, Iterable from urllib.parse import urlparse, urlunparse @@ -12,6 +11,7 @@ import urllib3 from . import __version__ from .adapters import HTTPieHTTPAdapter +from .context import Environment from .cli.dicts import HTTPHeadersDict from .encoding import UTF8 from .models import RequestsMessage @@ -34,15 +34,15 @@ def collect_messages( + env: Environment, args: argparse.Namespace, - config_dir: Path, request_body_read_callback: Callable[[bytes], None] = None, ) -> Iterable[RequestsMessage]: httpie_session = None httpie_session_headers = None if args.session or args.session_read_only: httpie_session = get_httpie_session( - config_dir=config_dir, + config_dir=env.config.directory, session_name=args.session or args.session_read_only, host=args.headers.get('Host'), url=args.url, @@ -50,6 +50,7 @@ def collect_messages( httpie_session_headers = httpie_session.headers request_kwargs = make_request_kwargs( + env, args=args, base_headers=httpie_session_headers, request_body_read_callback=request_body_read_callback @@ -292,6 +293,7 @@ def json_dict_to_request_body(data: Dict[str, Any]) -> str: def make_request_kwargs( + env: Environment, args: argparse.Namespace, base_headers: HTTPHeadersDict = None, request_body_read_callback=lambda chunk: chunk @@ -330,6 +332,7 @@ def make_request_kwargs( 'url': args.url, 'headers': headers, 'data': prepare_request_body( + env, data, body_read_callback=request_body_read_callback, chunked=args.chunked, diff --git a/httpie/core.py b/httpie/core.py index 38f67065d9..4718b92489 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -188,7 +188,7 @@ def request_body_read_callback(chunk: bytes): args.follow = True # --download implies --follow. downloader = Downloader(output_file=args.output_file, progress_file=env.stderr, resume=args.download_resume) downloader.pre_request(args.headers) - messages = collect_messages(args=args, config_dir=env.config.directory, + messages = collect_messages(env, args=args, request_body_read_callback=request_body_read_callback) force_separator = False prev_with_body = False diff --git a/httpie/uploads.py b/httpie/uploads.py index 0bb307e5cf..4fdb79222d 100644 --- a/httpie/uploads.py +++ b/httpie/uploads.py @@ -1,3 +1,5 @@ +import sys +import os import zlib import functools from typing import Any, Callable, IO, Iterable, Optional, Tuple, Union, TYPE_CHECKING @@ -9,7 +11,9 @@ if TYPE_CHECKING: from requests_toolbelt import MultipartEncoder +from .context import Environment from .cli.dicts import MultipartRequestDataDict, RequestDataDict +from .compat import is_windows class ChunkedStream: @@ -64,13 +68,58 @@ def wrapped(*args, **kwargs): return wrapped +def is_stdin(file: IO) -> bool: + try: + file_no = file.fileno() + except Exception: + return False + else: + return file_no == sys.stdin.fileno() + + +READ_THRESHOLD = float(os.getenv("HTTPIE_STDIN_READ_WARN_THRESHOLD", 10.0)) + + +def observe_stdin_for_data_thread(env: Environment, file: IO) -> None: + # Windows unfortunately does not support select() operation + # on regular files, like stdin in our use case. + # https://docs.python.org/3/library/select.html#select.select + if is_windows: + return None + + # If the user configures READ_THRESHOLD to be 0, then + # disable this warning. + if READ_THRESHOLD == 0: + return None + + import select + import threading + + def worker(): + can_read, _, _ = select.select([file], [], [], READ_THRESHOLD) + if not can_read: + env.stderr.write( + f'> warning: no stdin data read in {READ_THRESHOLD}s ' + f'(perhaps you want to --ignore-stdin)\n' + f'> See: https://httpie.io/docs/cli/best-practices\n' + ) + + thread = threading.Thread( + target=worker + ) + thread.start() + + def _prepare_file_for_upload( + env: Environment, file: Union[IO, 'MultipartEncoder'], callback: CallbackT, chunked: bool = False, content_length_header_value: Optional[int] = None, ) -> Union[bytes, IO, ChunkedStream]: if not super_len(file): + if is_stdin(file): + observe_stdin_for_data_thread(env, file) # Zero-length -> assume stdin. if content_length_header_value is None and not chunked: # Read the whole stdin to determine `Content-Length`. @@ -103,6 +152,7 @@ def _prepare_file_for_upload( def prepare_request_body( + env: Environment, raw_body: Union[str, bytes, IO, 'MultipartEncoder', RequestDataDict], body_read_callback: CallbackT, offline: bool = False, @@ -125,6 +175,7 @@ def prepare_request_body( if is_file_like: return _prepare_file_for_upload( + env, body, chunked=chunked, callback=body_read_callback, diff --git a/tests/test_uploads.py b/tests/test_uploads.py index 28d427aebe..613007ba9f 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -1,10 +1,16 @@ import os import json +import sys +import subprocess +import time +import contextlib +import httpie.__main__ as main import pytest from httpie.cli.exceptions import ParseError from httpie.client import FORM_CONTENT_TYPE +from httpie.compat import is_windows from httpie.status import ExitStatus from .utils import ( MockEnvironment, StdinBytesIO, http, @@ -83,6 +89,85 @@ def test_chunked_raw(httpbin_with_chunked_support): assert 'Transfer-Encoding: chunked' in r +@contextlib.contextmanager +def stdin_processes(httpbin, *args): + process_1 = subprocess.Popen( + [ + "cat" + ], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE + ) + process_2 = subprocess.Popen( + [ + sys.executable, + main.__file__, + "POST", + httpbin + "/post", + *args + ], + stdin=process_1.stdout, + stderr=subprocess.PIPE, + env={ + **os.environ, + "HTTPIE_STDIN_READ_WARN_THRESHOLD": "0.1" + } + ) + try: + yield process_1, process_2 + finally: + process_1.terminate() + process_2.terminate() + + +@pytest.mark.parametrize("wait", (True, False)) +@pytest.mark.skipif(is_windows, reason="Windows doesn't support select() calls into files") +def test_reading_from_stdin(httpbin, wait): + with stdin_processes(httpbin) as (process_1, process_2): + process_1.communicate(timeout=0.1, input=b"bleh") + # Since there is data, it doesn't matter if there + # you wait or not. + if wait: + time.sleep(0.75) + + try: + _, errs = process_2.communicate(timeout=0.25) + except subprocess.TimeoutExpired: + errs = b'' + + assert b'> warning: no stdin data read in 0.1s' not in errs + + +@pytest.mark.skipif(is_windows, reason="Windows doesn't support select() calls into files") +def test_stdin_read_warning(httpbin): + with stdin_processes(httpbin) as (process_1, process_2): + # Wait before sending any data + time.sleep(0.75) + process_1.communicate(timeout=0.1, input=b"bleh\n") + + try: + _, errs = process_2.communicate(timeout=0.25) + except subprocess.TimeoutExpired: + errs = b'' + + assert b'> warning: no stdin data read in 0.1s' in errs + + +@pytest.mark.skipif(is_windows, reason="Windows doesn't support select() calls into files") +def test_stdin_read_warning_with_quiet(httpbin): + with stdin_processes(httpbin, "-qq") as (process_1, process_2): + # Wait before sending any data + time.sleep(0.75) + process_1.communicate(timeout=0.1, input=b"bleh\n") + + try: + _, errs = process_2.communicate(timeout=0.25) + except subprocess.TimeoutExpired: + errs = b'' + + assert b'> warning: no stdin data read in 0.1s' not in errs + + class TestMultipartFormDataFileUpload: def test_non_existent_file_raises_parse_error(self, httpbin): From c126bc11c7d8ab41fbb08b2c8fce2c625cc2a2eb Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 13 Jan 2022 15:04:30 +0300 Subject: [PATCH 0965/1182] Make the stdin wait tests more reliable --- tests/test_uploads.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_uploads.py b/tests/test_uploads.py index 613007ba9f..d9de3ac984 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -128,7 +128,7 @@ def test_reading_from_stdin(httpbin, wait): # Since there is data, it doesn't matter if there # you wait or not. if wait: - time.sleep(0.75) + time.sleep(1) try: _, errs = process_2.communicate(timeout=0.25) @@ -142,7 +142,7 @@ def test_reading_from_stdin(httpbin, wait): def test_stdin_read_warning(httpbin): with stdin_processes(httpbin) as (process_1, process_2): # Wait before sending any data - time.sleep(0.75) + time.sleep(1) process_1.communicate(timeout=0.1, input=b"bleh\n") try: @@ -157,7 +157,7 @@ def test_stdin_read_warning(httpbin): def test_stdin_read_warning_with_quiet(httpbin): with stdin_processes(httpbin, "-qq") as (process_1, process_2): # Wait before sending any data - time.sleep(0.75) + time.sleep(1) process_1.communicate(timeout=0.1, input=b"bleh\n") try: From 21faddc4b967070c5910477f934c107c8d6e5be6 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 13 Jan 2022 15:04:44 +0300 Subject: [PATCH 0966/1182] Proper separation of meta/body --- httpie/output/streams.py | 7 ++----- httpie/output/writer.py | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/httpie/output/streams.py b/httpie/output/streams.py index 4371af39f9..ec275faa41 100644 --- a/httpie/output/streams.py +++ b/httpie/output/streams.py @@ -76,14 +76,11 @@ def __iter__(self) -> Iterable[bytes]: yield e.message if self.output_options.meta: - mixed = self.output_options.headers or self.output_options.body - - if mixed: + if self.output_options.body: yield b'\n\n' yield self.get_metadata() - if not mixed: - yield b'\n' + yield b'\n\n' class RawStream(BaseStream): diff --git a/httpie/output/writer.py b/httpie/output/writer.py index 0a911560ca..cbd06e9274 100644 --- a/httpie/output/writer.py +++ b/httpie/output/writer.py @@ -115,7 +115,7 @@ def build_output_stream_for_message( output_options=output_options, **stream_kwargs, ) - if (env.stdout_isatty and output_options.body + if (env.stdout_isatty and output_options.body and not output_options.meta and not getattr(requests_message, 'is_body_upload_chunk', False)): # Ensure a blank line after the response body. # For terminal output only. From 7bf373751d3e4874de35ca3b3ac0bc6097fcf051 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 4 Jan 2022 12:04:20 +0300 Subject: [PATCH 0967/1182] Implement HTTPie Nested JSON v2 --- httpie/cli/argtypes.py | 4 +- httpie/cli/constants.py | 2 + httpie/cli/json_form.py | 150 ------------- httpie/cli/nested_json.py | 311 +++++++++++++++++++++++++++ httpie/cli/requestitems.py | 4 +- httpie/core.py | 6 + tests/test_json.py | 420 ++++++++++++++++++++++++++++++------- 7 files changed, 667 insertions(+), 230 deletions(-) delete mode 100644 httpie/cli/json_form.py create mode 100644 httpie/cli/nested_json.py diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index 0ed564804f..7bc487ea81 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -57,7 +57,7 @@ class KeyValueArgType: def __init__(self, *separators: str): self.separators = separators - self.special_characters = set('\\') + self.special_characters = set() for separator in separators: self.special_characters.update(separator) @@ -113,7 +113,7 @@ def tokenize(self, s: str) -> List[Union[str, Escaped]]: There are only two token types - strings and escaped characters: >>> KeyValueArgType('=').tokenize(r'foo\=bar\\baz') - ['foo', Escaped('='), 'bar', Escaped('\\'), 'baz'] + ['foo', Escaped('='), 'bar\\\\baz'] """ tokens = [''] diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index 6d69b9ba95..f00911e58a 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -52,6 +52,8 @@ SEPARATOR_GROUP_NESTED_JSON_ITEMS = frozenset([ SEPARATOR_DATA_STRING, SEPARATOR_DATA_RAW_JSON, + SEPARATOR_DATA_EMBED_FILE_CONTENTS, + SEPARATOR_DATA_EMBED_RAW_JSON_FILE, ]) # Separators allowed in ITEM arguments diff --git a/httpie/cli/json_form.py b/httpie/cli/json_form.py deleted file mode 100644 index 9263e5cb12..0000000000 --- a/httpie/cli/json_form.py +++ /dev/null @@ -1,150 +0,0 @@ -""" -Routines for JSON form syntax, used to support nested JSON request items. - -Highly inspired from the great jarg project . -""" -import re -import operator -from typing import Optional - - -def step(value: str, is_escaped: bool) -> str: - if is_escaped: - value = value.replace(r'\[', '[').replace(r'\]', ']') - return value - - -def find_opening_bracket( - value: str, - search=re.compile(r'(? Optional[int]: - match = search(value) - if not match: - return None - return match.start() - - -def find_closing_bracket( - value: str, - search=re.compile(r'(? Optional[int]: - match = search(value) - if not match: - return None - return match.start() - - -def parse_path(path): - """ - Parse a string as a JSON path. - - An implementation of 'steps to parse a JSON encoding path'. - - - """ - original = path - is_escaped = r'\[' in original - - opening_bracket = find_opening_bracket(original) - last_step = [(step(path, is_escaped), {'last': True, 'type': 'object'})] - if opening_bracket is None: - return last_step - - steps = [(step(original[:opening_bracket], is_escaped), {'type': 'object'})] - path = original[opening_bracket:] - while path: - if path.startswith('[]'): - steps[-1][1]['append'] = True - path = path[2:] - if path: - return last_step - elif path[0] == '[': - path = path[1:] - closing_bracket = find_closing_bracket(path) - if closing_bracket is None: - return last_step - key = path[:closing_bracket] - path = path[closing_bracket + 1:] - try: - steps.append((int(key), {'type': 'array'})) - except ValueError: - steps.append((key, {'type': 'object'})) - elif path[:2] == r'\[': - key = step(path[1:path.index(r'\]') + 2], is_escaped) - path = path[path.index(r'\]') + 2:] - steps.append((key, {'type': 'object'})) - else: - return last_step - - for i in range(len(steps) - 1): - steps[i][1]['type'] = steps[i + 1][1]['type'] - steps[-1][1]['last'] = True - return steps - - -def set_value(context, step, current_value, entry_value): - """Apply a JSON value to a context object. - - An implementation of 'steps to set a JSON encoding value'. - - - """ - key, flags = step - if flags.get('last', False): - if current_value is None: - if flags.get('append', False): - context[key] = [entry_value] - else: - if isinstance(context, list) and len(context) <= key: - context.extend([None] * (key - len(context) + 1)) - context[key] = entry_value - elif isinstance(current_value, list): - context[key].append(entry_value) - else: - context[key] = [current_value, entry_value] - return context - - if current_value is None: - if flags.get('type') == 'array': - context[key] = [] - else: - if isinstance(context, list) and len(context) <= key: - context.extend([None] * (key - len(context) + 1)) - context[key] = {} - return context[key] - elif isinstance(current_value, dict): - return context[key] - elif isinstance(current_value, list): - if flags.get('type') == 'array': - return current_value - - obj = {} - for i, item in enumerate(current_value): - if item is not None: - obj[i] = item - else: - context[key] = obj - return obj - else: - obj = {'': current_value} - context[key] = obj - return obj - - -def interpret_json_form(pairs): - """The application/json form encoding algorithm. - - - - """ - result = {} - for key, value in pairs: - steps = parse_path(key) - context = result - for step in steps: - try: - current_value = operator.getitem(context, step[0]) - except LookupError: - current_value = None - context = set_value(context, step, current_value, value) - return result diff --git a/httpie/cli/nested_json.py b/httpie/cli/nested_json.py new file mode 100644 index 0000000000..807076c0ab --- /dev/null +++ b/httpie/cli/nested_json.py @@ -0,0 +1,311 @@ +from enum import Enum, auto +from typing import ( + Any, + Iterator, + NamedTuple, + Optional, + List, + NoReturn, + Type, + Union, +) + + +class HTTPieSyntaxError(ValueError): + def __init__( + self, + source: str, + token: Optional['Token'], + message: str, + message_kind: str = 'Syntax', + ) -> None: + self.source = source + self.token = token + self.message = message + self.message_kind = message_kind + + def __str__(self): + lines = [f'HTTPie {self.message_kind} Error: {self.message}'] + if self.token is not None: + lines.append(self.source) + lines.append( + ' ' * (self.token.start) + + '^' * (self.token.end - self.token.start) + ) + return '\n'.join(lines) + + +class TokenKind(Enum): + TEXT = auto() + NUMBER = auto() + LEFT_BRACKET = auto() + RIGHT_BRACKET = auto() + + def to_name(self) -> str: + for key, value in OPERATORS.items(): + if value is self: + return repr(key) + else: + return 'a ' + self.name.lower() + + +OPERATORS = {'[': TokenKind.LEFT_BRACKET, ']': TokenKind.RIGHT_BRACKET} +SPECIAL_CHARS = OPERATORS.keys() | {'\\'} + + +class Token(NamedTuple): + kind: TokenKind + value: Union[str, int] + start: int + end: int + + +def assert_cant_happen() -> NoReturn: + raise ValueError("Unexpected value") + + +def tokenize(source: str) -> Iterator[Token]: + cursor = 0 + backslashes = 0 + buffer = [] + + def send_buffer() -> Iterator[Token]: + nonlocal backslashes + if not buffer: + return None + + value = ''.join(buffer) + try: + value = int(value) + except ValueError: + kind = TokenKind.TEXT + else: + kind = TokenKind.NUMBER + + yield Token( + kind, value, start=cursor - (len(buffer) + backslashes), end=cursor + ) + buffer.clear() + backslashes = 0 + + def can_advance() -> bool: + return cursor < len(source) + + while can_advance(): + index = source[cursor] + if index in OPERATORS: + yield from send_buffer() + yield Token(OPERATORS[index], index, cursor, cursor + 1) + elif index == '\\' and can_advance(): + if source[cursor + 1] in SPECIAL_CHARS: + backslashes += 1 + else: + buffer.append(index) + + buffer.append(source[cursor + 1]) + cursor += 1 + else: + buffer.append(index) + + cursor += 1 + + yield from send_buffer() + + +class Path: + def __init__( + self, + kind: str, + accessor: Optional[Union[str, int]] = None, + tokens: Optional[List[Token]] = None, + is_root: bool = False, + ): + self.kind = kind + self.accessor = accessor + self.tokens = tokens or [] + self.is_root = is_root + + def reconstruct(self) -> str: + if self.kind == 'key': + if self.is_root: + return self.accessor + return '[' + self.accessor + ']' + elif self.kind == 'index': + return '[' + str(self.accessor) + ']' + elif self.kind == 'append': + return '[]' + else: + assert_cant_happen() + + +def parse(source: str) -> Iterator[Path]: + """ + start: literal? path* + + literal: TEXT | NUMBER + + path: + key_path + | index_path + | append_path + key_path: LEFT_BRACKET TEXT RIGHT_BRACKET + index_path: LEFT_BRACKET NUMBER RIGHT_BRACKET + append_path: LEFT_BRACKET RIGHT_BRACKET + """ + + tokens = list(tokenize(source)) + cursor = 0 + + def can_advance(): + return cursor < len(tokens) + + def expect(*kinds): + nonlocal cursor + + assert len(kinds) > 0 + if can_advance(): + token = tokens[cursor] + cursor += 1 + if token.kind in kinds: + return token + else: + token = tokens[-1]._replace( + start=tokens[-1].end + 0, end=tokens[-1].end + 1 + ) + + if len(kinds) == 1: + suffix = kinds[0].to_name() + else: + suffix = ', '.join(kind.to_name() for kind in kinds[:-1]) + suffix += ' or ' + kinds[-1].to_name() + + message = f'Expecting {suffix}' + raise HTTPieSyntaxError(source, token, message) + + root = Path('key', '', is_root=True) + if can_advance(): + token = tokens[cursor] + if token.kind in {TokenKind.TEXT, TokenKind.NUMBER}: + token = expect(TokenKind.TEXT, TokenKind.NUMBER) + root.accessor = str(token.value) + root.tokens.append(token) + + yield root + + while can_advance(): + path_tokens = [] + path_tokens.append(expect(TokenKind.LEFT_BRACKET)) + + token = expect( + TokenKind.TEXT, TokenKind.NUMBER, TokenKind.RIGHT_BRACKET + ) + path_tokens.append(token) + if token.kind is TokenKind.RIGHT_BRACKET: + path = Path('append', tokens=path_tokens) + elif token.kind is TokenKind.TEXT: + path = Path('key', token.value, tokens=path_tokens) + path_tokens.append(expect(TokenKind.RIGHT_BRACKET)) + elif token.kind is TokenKind.NUMBER: + path = Path('index', token.value, tokens=path_tokens) + path_tokens.append(expect(TokenKind.RIGHT_BRACKET)) + else: + assert_cant_happen() + yield path + + +JSON_TYPE_MAPPING = { + dict: 'object', + list: 'array', + int: 'number', + float: 'number', + str: 'string', +} + + +def interpret(context: Any, key: str, value: Any) -> Any: + cursor = context + + paths = list(parse(key)) + paths.append(Path('set', value)) + + def type_check(index: int, path: Path, expected_type: Type[Any]) -> None: + if not isinstance(cursor, expected_type): + if path.tokens: + pseudo_token = Token( + None, None, path.tokens[0].start, path.tokens[-1].end + ) + else: + pseudo_token = None + + cursor_type = JSON_TYPE_MAPPING.get( + type(cursor), type(cursor).__name__ + ) + required_type = JSON_TYPE_MAPPING[expected_type] + + message = f"Can't perform {path.kind!r} based access on " + message += repr( + ''.join(path.reconstruct() for path in paths[:index]) + ) + message += ( + f' which has a type of {cursor_type!r} but this operation' + ) + message += f' requires a type of {required_type!r}.' + raise HTTPieSyntaxError( + key, pseudo_token, message, message_kind='Type' + ) + + def object_for(kind: str) -> str: + if kind == 'key': + return {} + elif kind in {'index', 'append'}: + return [] + else: + assert_cant_happen() + + for index, (path, next_path) in enumerate(zip(paths, paths[1:])): + if path.kind == 'key': + type_check(index, path, dict) + if next_path.kind == 'set': + cursor[path.accessor] = next_path.accessor + break + + cursor = cursor.setdefault( + path.accessor, object_for(next_path.kind) + ) + elif path.kind == 'index': + type_check(index, path, list) + if path.accessor < 0: + raise HTTPieSyntaxError( + key, + path.tokens[1], + 'Negative indexes are not supported.', + message_kind='Value', + ) + cursor.extend([None] * (path.accessor - len(cursor) + 1)) + if next_path.kind == 'set': + cursor[path.accessor] = next_path.accessor + break + + if cursor[path.accessor] is None: + cursor[path.accessor] = object_for(next_path.kind) + + cursor = cursor[path.accessor] + elif path.kind == 'append': + type_check(index, path, list) + if next_path.kind == 'set': + cursor.append(next_path.accessor) + break + + cursor.append(object_for(next_path.kind)) + cursor = cursor[-1] + else: + assert_cant_happen() + + return context + + +def interpret_nested_json(pairs): + context = {} + for key, value in pairs: + interpret(context, key, value) + return context diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index e804911e1f..96731b59a2 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -17,7 +17,7 @@ RequestQueryParamsDict, ) from .exceptions import ParseError -from .json_form import interpret_json_form +from .nested_json import interpret_nested_json from ..utils import get_content_type, load_json_preserve_order_and_dupe_keys, split @@ -202,7 +202,7 @@ def process_data_raw_json_embed_arg(arg: KeyValueArg) -> JSONType: def process_data_nested_json_embed_args(pairs) -> Dict[str, JSONType]: - return interpret_json_form(pairs) + return interpret_nested_json(pairs) def load_text_file(item: KeyValueArg) -> str: diff --git a/httpie/core.py b/httpie/core.py index 4718b92489..04cfa021f8 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -11,6 +11,7 @@ from . import __version__ as httpie_version from .cli.constants import OUT_REQ_BODY +from .cli.nested_json import HTTPieSyntaxError from .client import collect_messages from .context import Environment from .downloads import Downloader @@ -69,6 +70,11 @@ def handle_generic_error(e, annotation=None): args=args, env=env, ) + except HTTPieSyntaxError as exc: + env.stderr.write(str(exc) + "\n") + if include_traceback: + raise + exit_status = ExitStatus.ERROR except KeyboardInterrupt: env.stderr.write('\n') if include_traceback: diff --git a/tests/test_json.py b/tests/test_json.py index 945bf4dcd6..287b2f4167 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -5,12 +5,19 @@ from httpie.cli.constants import PRETTY_MAP from httpie.cli.exceptions import ParseError +from httpie.cli.nested_json import HTTPieSyntaxError from httpie.compat import is_windows from httpie.output.formatters.colors import ColorFormatter from httpie.utils import JsonDictPreservingDuplicateKeys -from .fixtures import JSON_WITH_DUPE_KEYS_FILE_PATH -from .utils import MockEnvironment, http, DUMMY_URL +from .fixtures import ( + FILE_CONTENT, + FILE_PATH, + JSON_FILE_CONTENT, + JSON_FILE_PATH, + JSON_WITH_DUPE_KEYS_FILE_PATH, +) +from .utils import DUMMY_URL, MockEnvironment, http TEST_JSON_XXSI_PREFIXES = [ r")]}',\n", @@ -35,25 +42,27 @@ TEST_PREFIX_TOKEN_COLOR = '\x1b[38;5;15m' if is_windows else '\x1b[04m\x1b[91m' JSON_WITH_DUPES_RAW = '{"key": 15, "key": 15, "key": 3, "key": 7}' -JSON_WITH_DUPES_FORMATTED_SORTED = '''{ +JSON_WITH_DUPES_FORMATTED_SORTED = """{ "key": 3, "key": 7, "key": 15, "key": 15 -}''' -JSON_WITH_DUPES_FORMATTED_UNSORTED = '''{ +}""" +JSON_WITH_DUPES_FORMATTED_UNSORTED = """{ "key": 15, "key": 15, "key": 3, "key": 7 -}''' +}""" @pytest.mark.parametrize('data_prefix', TEST_JSON_XXSI_PREFIXES) @pytest.mark.parametrize('json_data', TEST_JSON_VALUES) @pytest.mark.parametrize('pretty', PRETTY_MAP.keys()) @responses.activate -def test_json_formatter_with_body_preceded_by_non_json_data(data_prefix, json_data, pretty): +def test_json_formatter_with_body_preceded_by_non_json_data( + data_prefix, json_data, pretty +): """Test JSON bodies preceded by non-JSON data.""" body = data_prefix + json.dumps(json_data) content_type = 'application/json;charset=utf8' @@ -71,11 +80,15 @@ def test_json_formatter_with_body_preceded_by_non_json_data(data_prefix, json_da indent = None if pretty in {'none', 'colors'} else 4 expected_body = data_prefix + json.dumps(json_data, indent=indent) if colored_output: - fmt = ColorFormatter(env, format_options={'json': {'format': True, 'indent': 4}}) + fmt = ColorFormatter( + env, format_options={'json': {'format': True, 'indent': 4}} + ) expected_body = fmt.format_body(expected_body, content_type) # Check to ensure the non-JSON data prefix is colored only one time, # meaning it was correctly handled as a whole. - assert TEST_PREFIX_TOKEN_COLOR + data_prefix in expected_body, expected_body + assert ( + TEST_PREFIX_TOKEN_COLOR + data_prefix in expected_body + ), expected_body assert expected_body in r @@ -119,12 +132,7 @@ def test_duplicate_keys_support_from_input_file(): assert JSON_WITH_DUPES_FORMATTED_UNSORTED in r -@pytest.mark.parametrize("value", [ - 1, - 1.1, - True, - 'some_value' -]) +@pytest.mark.parametrize('value', [1, 1.1, True, 'some_value']) def test_simple_json_arguments_with_non_json(httpbin, value): r = http( '--form', @@ -134,15 +142,14 @@ def test_simple_json_arguments_with_non_json(httpbin, value): assert r.json['form'] == {'option': str(value)} -@pytest.mark.parametrize("request_type", [ - "--form", - "--multipart", -]) -@pytest.mark.parametrize("value", [ - [1, 2, 3], - {'a': 'b'}, - None -]) +@pytest.mark.parametrize( + 'request_type', + [ + '--form', + '--multipart', + ], +) +@pytest.mark.parametrize('value', [[1, 2, 3], {'a': 'b'}, None]) def test_complex_json_arguments_with_non_json(httpbin, request_type, value): with pytest.raises(ParseError) as cm: http( @@ -151,61 +158,322 @@ def test_complex_json_arguments_with_non_json(httpbin, request_type, value): f'option:={json.dumps(value)}', ) - cm.match('Can\'t use complex JSON value types') - - -@pytest.mark.parametrize('input_json, expected_json', [ - # Examples taken from https://www.w3.org/TR/html-json-forms/ - ( - ['bottle-on-wall:=1', 'bottle-on-wall:=2', 'bottle-on-wall:=3'], - {'bottle-on-wall': [1, 2, 3]}, - ), - ( - ['pet[species]=Dahut', 'pet[name]:="Hypatia"', 'kids[1]=Thelma', 'kids[0]:="Ashley"'], - {'pet': {'species': 'Dahut', 'name': 'Hypatia'}, 'kids': ['Ashley', 'Thelma']}, - ), - ( - ['pet[0][species]=Dahut', 'pet[0][name]=Hypatia', 'pet[1][species]=Felis Stultus', 'pet[1][name]:="Billie"'], - {'pet': [{'species': 'Dahut', 'name': 'Hypatia'}, {'species': 'Felis Stultus', 'name': 'Billie'}]}, - ), - ( - ['wow[such][deep][3][much][power][!]=Amaze'], - {'wow': {'such': {'deep': [None, None, None, {'much': {'power': {'!': 'Amaze'}}}]}}}, - ), - ( - ['mix=scalar', 'mix[0]=array 1', 'mix[2]:="array 2"', 'mix[key]:="key key"', 'mix[car]=car key'], - {'mix': {'': 'scalar', '0': 'array 1', '2': 'array 2', 'key': 'key key', 'car': 'car key'}}, - ), - ( - ['highlander[]=one'], - {'highlander': ['one']}, - ), - ( - ['error[good]=BOOM!', 'error[bad:="BOOM BOOM!"'], - {'error': {'good': 'BOOM!'}, 'error[bad': 'BOOM BOOM!'}, - ), - ( - ['special[]:=true', 'special[]:=false', 'special[]:="true"', 'special[]:=null'], - {'special': [True, False, 'true', None]}, - ), - ( - [r'\[\]:=1', r'escape\[d\]:=1', r'escaped\[\]:=1', r'e\[s\][c][a][p]\[ed\][]:=1'], - {'[]': 1, 'escape[d]': 1, 'escaped[]': 1, 'e[s]': {'c': {'a': {'p': {'[ed]': [1]}}}}}, - ), - ( - ['[]:=1', '[]=foo'], - [1, 'foo'], - ), - ( - [']:=1', '[]1:=1', '[1]]:=1'], - {']': 1, '[]1': 1, '[1]]': 1}, - ), -]) -def test_nested_json_syntax(input_json, expected_json, httpbin_both): - r = http(httpbin_both + '/post', *input_json) + cm.match("Can't use complex JSON value types") + + +@pytest.mark.parametrize( + 'input_json, expected_json', + [ + # Examples taken from https://www.w3.org/TR/html-json-forms/ + ( + [ + 'bottle-on-wall[]:=1', + 'bottle-on-wall[]:=2', + 'bottle-on-wall[]:=3', + ], + {'bottle-on-wall': [1, 2, 3]}, + ), + ( + [ + 'pet[species]=Dahut', + 'pet[name]:="Hypatia"', + 'kids[1]=Thelma', + 'kids[0]:="Ashley"', + ], + { + 'pet': {'species': 'Dahut', 'name': 'Hypatia'}, + 'kids': ['Ashley', 'Thelma'], + }, + ), + ( + [ + 'pet[0][species]=Dahut', + 'pet[0][name]=Hypatia', + 'pet[1][species]=Felis Stultus', + 'pet[1][name]:="Billie"', + ], + { + 'pet': [ + {'species': 'Dahut', 'name': 'Hypatia'}, + {'species': 'Felis Stultus', 'name': 'Billie'}, + ] + }, + ), + ( + ['wow[such][deep][3][much][power][!]=Amaze'], + { + 'wow': { + 'such': { + 'deep': [ + None, + None, + None, + {'much': {'power': {'!': 'Amaze'}}}, + ] + } + } + }, + ), + ( + ['mix[]=scalar', 'mix[2]=something', 'mix[4]:="something 2"'], + {'mix': ['scalar', None, 'something', None, 'something 2']}, + ), + ( + ['highlander[]=one'], + {'highlander': ['one']}, + ), + ( + ['error[good]=BOOM!', r'error\[bad:="BOOM BOOM!"'], + {'error': {'good': 'BOOM!'}, 'error[bad': 'BOOM BOOM!'}, + ), + ( + [ + 'special[]:=true', + 'special[]:=false', + 'special[]:="true"', + 'special[]:=null', + ], + {'special': [True, False, 'true', None]}, + ), + ( + [ + r'\[\]:=1', + r'escape\[d\]:=1', + r'escaped\[\]:=1', + r'e\[s\][c][a][p][\[ed\]][]:=1', + ], + { + '[]': 1, + 'escape[d]': 1, + 'escaped[]': 1, + 'e[s]': {'c': {'a': {'p': {'[ed]': [1]}}}}, + }, + ), + ( + ['[]:=1', '[]=foo'], + [1, 'foo'], + ), + ( + [r'\]:=1', r'\[\]1:=1', r'\[1\]\]:=1'], + {']': 1, '[]1': 1, '[1]]': 1}, + ), + ( + [ + r'foo\[bar\][baz]:=1', + r'foo\[bar\]\[baz\]:=3', + r'foo[bar][\[baz\]]:=4', + ], + { + 'foo[bar]': {'baz': 1}, + 'foo[bar][baz]': 3, + 'foo': {'bar': {'[baz]': 4}}, + }, + ), + ( + ['key[]:=1', 'key[][]:=2', 'key[][][]:=3', 'key[][][]:=4'], + {'key': [1, [2], [[3]], [[4]]]}, + ), + ( + ['x[0]:=1', 'x[]:=2', 'x[]:=3', 'x[][]:=4', 'x[][]:=5'], + {'x': [1, 2, 3, [4], [5]]}, + ), + ( + [ + f'x=@{FILE_PATH}', + f'y[z]=@{FILE_PATH}', + f'q[u][]:=@{JSON_FILE_PATH}', + ], + { + 'x': FILE_CONTENT, + 'y': {'z': FILE_CONTENT}, + 'q': {'u': [json.loads(JSON_FILE_CONTENT)]}, + }, + ), + ( + [ + 'foo[bar][5][]:=5', + 'foo[bar][]:=6', + 'foo[bar][][]:=7', + 'foo[bar][][x]=dfasfdas', + 'foo[baz]:=[1, 2, 3]', + 'foo[baz][]:=4', + ], + { + 'foo': { + 'bar': [ + None, + None, + None, + None, + None, + [5], + 6, + [7], + {'x': 'dfasfdas'}, + ], + 'baz': [1, 2, 3, 4], + } + }, + ), + ( + [ + 'foo[]:=1', + 'foo[]:=2', + 'foo[][key]=value', + 'foo[2][key 2]=value 2', + r'foo[2][key \[]=value 3', + r'[nesting][under][!][empty][?][\\key]:=4', + ], + { + 'foo': [ + 1, + 2, + {'key': 'value', 'key 2': 'value 2', 'key [': 'value 3'}, + ], + '': { + 'nesting': {'under': {'!': {'empty': {'?': {'\\key': 4}}}}} + }, + }, + ), + ( + [ + r'foo\[key\]:=1', + r'bar\[1\]:=2', + r'baz\[\]:3', + r'quux[key\[escape\]]:=4', + r'quux[key 2][\\][\\\\][\\\[\]\\\]\\\[\n\\]:=5', + ], + { + 'foo[key]': 1, + 'bar[1]': 2, + 'quux': { + 'key[escape]': 4, + 'key 2': {'\\': {'\\\\': {'\\[]\\]\\[\\n\\': 5}}}, + }, + }, + ), + ( + [r'A[B\\]=C', r'A[B\\\\]=C', r'A[\B\\]=C'], + {'A': {'B\\': 'C', 'B\\\\': 'C', '\\B\\': 'C'}}, + ), + ( + [ + 'name=python', + 'version:=3', + 'date[year]:=2021', + 'date[month]=December', + 'systems[]=Linux', + 'systems[]=Mac', + 'systems[]=Windows', + 'people[known_ids][1]:=1000', + 'people[known_ids][5]:=5000', + ], + { + 'name': 'python', + 'version': 3, + 'date': {'year': 2021, 'month': 'December'}, + 'systems': ['Linux', 'Mac', 'Windows'], + 'people': {'known_ids': [None, 1000, None, None, None, 5000]}, + }, + ), + ], +) +def test_nested_json_syntax(input_json, expected_json, httpbin): + r = http(httpbin + '/post', *input_json) assert r.json['json'] == expected_json +@pytest.mark.parametrize( + 'input_json, expected_error', + [ + ( + ['A[:=1'], + "HTTPie Syntax Error: Expecting a text, a number or ']'\nA[\n ^", + ), + (['A[1:=1'], "HTTPie Syntax Error: Expecting ']'\nA[1\n ^"), + (['A[text:=1'], "HTTPie Syntax Error: Expecting ']'\nA[text\n ^"), + ( + ['A[text][:=1'], + "HTTPie Syntax Error: Expecting a text, a number or ']'\nA[text][\n ^", + ), + ( + ['A[key]=value', 'B[something]=u', 'A[text][:=1', 'C[key]=value'], + "HTTPie Syntax Error: Expecting a text, a number or ']'\nA[text][\n ^", + ), + ( + ['A[text]1:=1'], + "HTTPie Syntax Error: Expecting '['\nA[text]1\n ^", + ), + (['A\\[]:=1'], "HTTPie Syntax Error: Expecting '['\nA\\[]\n ^"), + ( + ['A[something\\]:=1'], + "HTTPie Syntax Error: Expecting ']'\nA[something\\]\n ^", + ), + ( + ['foo\\[bar\\]\\\\[ bleh:=1'], + "HTTPie Syntax Error: Expecting ']'\nfoo\\[bar\\]\\\\[ bleh\n ^", + ), + ( + ['foo\\[bar\\]\\\\[ bleh :=1'], + "HTTPie Syntax Error: Expecting ']'\nfoo\\[bar\\]\\\\[ bleh \n ^", + ), + ( + ['foo[bar][1]][]:=2'], + "HTTPie Syntax Error: Expecting '['\nfoo[bar][1]][]\n ^", + ), + ( + ['foo[bar][1]something[]:=2'], + "HTTPie Syntax Error: Expecting '['\nfoo[bar][1]something[]\n ^^^^^^^^^", + ), + ( + ['foo[bar][1][142241[]:=2'], + "HTTPie Syntax Error: Expecting ']'\nfoo[bar][1][142241[]\n ^", + ), + ( + ['foo[bar][1]\\[142241[]:=2'], + "HTTPie Syntax Error: Expecting '['\nfoo[bar][1]\\[142241[]\n ^^^^^^^^", + ), + ( + ['foo=1', 'foo[key]:=2'], + "HTTPie Type Error: Can't perform 'key' based access on 'foo' which has a type of 'string' but this operation requires a type of 'object'.\nfoo[key]\n ^^^^^", + ), + ( + ['foo=1', 'foo[0]:=2'], + "HTTPie Type Error: Can't perform 'index' based access on 'foo' which has a type of 'string' but this operation requires a type of 'array'.\nfoo[0]\n ^^^", + ), + ( + ['foo=1', 'foo[]:=2'], + "HTTPie Type Error: Can't perform 'append' based access on 'foo' which has a type of 'string' but this operation requires a type of 'array'.\nfoo[]\n ^^", + ), + ( + ['data[key]=value', 'data[key 2]=value 2', 'data[0]=value'], + "HTTPie Type Error: Can't perform 'index' based access on 'data' which has a type of 'object' but this operation requires a type of 'array'.\ndata[0]\n ^^^", + ), + ( + ['data[key]=value', 'data[key 2]=value 2', 'data[]=value'], + "HTTPie Type Error: Can't perform 'append' based access on 'data' which has a type of 'object' but this operation requires a type of 'array'.\ndata[]\n ^^", + ), + ( + [ + 'foo[bar][baz][5]:=[1,2,3]', + 'foo[bar][baz][5][]:=4', + 'foo[bar][baz][key][]:=5', + ], + "HTTPie Type Error: Can't perform 'key' based access on 'foo[bar][baz]' which has a type of 'array' but this operation requires a type of 'object'.\nfoo[bar][baz][key][]\n ^^^^^", + ), + ( + ['foo[-10]:=[1,2]'], + 'HTTPie Value Error: Negative indexes are not supported.\nfoo[-10]\n ^^^', + ), + ], +) +def test_nested_json_errors(input_json, expected_error, httpbin): + with pytest.raises(HTTPieSyntaxError) as exc: + http(httpbin + '/post', *input_json) + + assert str(exc.value) == expected_error + + def test_nested_json_sparse_array(httpbin_both): r = http(httpbin_both + '/post', 'test[0]:=1', 'test[100]:=1') assert len(r.json['json']['test']) == 101 From 2cda966384c36ac395c63d688f8ebae856984214 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 7 Jan 2022 12:52:13 +0300 Subject: [PATCH 0968/1182] Implement escaped integers --- httpie/cli/nested_json.py | 30 ++++++++++++++++++++++++------ tests/test_json.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/httpie/cli/nested_json.py b/httpie/cli/nested_json.py index 807076c0ab..615f0427bf 100644 --- a/httpie/cli/nested_json.py +++ b/httpie/cli/nested_json.py @@ -61,7 +61,19 @@ class Token(NamedTuple): def assert_cant_happen() -> NoReturn: - raise ValueError("Unexpected value") + raise ValueError('Unexpected value') + + +def check_escaped_int(value: str) -> str: + if not value.startswith('\\'): + raise ValueError('Not an escaped int') + + try: + int(value[1:]) + except ValueError as exc: + raise ValueError('Not an escaped int') from exc + else: + return value[1:] def tokenize(source: str) -> Iterator[Token]: @@ -75,12 +87,18 @@ def send_buffer() -> Iterator[Token]: return None value = ''.join(buffer) - try: - value = int(value) - except ValueError: - kind = TokenKind.TEXT + for variation, kind in [ + (int, TokenKind.NUMBER), + (check_escaped_int, TokenKind.TEXT), + ]: + try: + value = variation(value) + except ValueError: + continue + else: + break else: - kind = TokenKind.NUMBER + kind = TokenKind.TEXT yield Token( kind, value, start=cursor - (len(buffer) + backslashes), end=cursor diff --git a/tests/test_json.py b/tests/test_json.py index 287b2f4167..ae74834035 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -376,6 +376,28 @@ def test_complex_json_arguments_with_non_json(httpbin, request_type, value): 'people': {'known_ids': [None, 1000, None, None, None, 5000]}, }, ), + ( + [ + r'foo[\1][type]=migration', + r'foo[\2][type]=migration', + r'foo[\dates]:=[2012, 2013]', + r'foo[\dates][0]:=2014', + r'foo[\2012 bleh]:=2013', + r'foo[bleh \2012]:=2014', + r'\2012[x]:=2', + r'\2012[\[3\]]:=4', + ], + { + 'foo': { + '1': {'type': 'migration'}, + '2': {'type': 'migration'}, + '\\dates': [2014, 2013], + '\\2012 bleh': 2013, + 'bleh \\2012': 2014, + }, + '2012': {'x': 2, '[3]': 4}, + }, + ), ], ) def test_nested_json_syntax(input_json, expected_json, httpbin): @@ -465,6 +487,14 @@ def test_nested_json_syntax(input_json, expected_json, httpbin): ['foo[-10]:=[1,2]'], 'HTTPie Value Error: Negative indexes are not supported.\nfoo[-10]\n ^^^', ), + ( + ['foo[0]:=1', 'foo[]:=2', 'foo[\\2]:=3'], + "HTTPie Type Error: Can't perform 'key' based access on 'foo' which has a type of 'array' but this operation requires a type of 'object'.\nfoo[\\2]\n ^^^^", + ), + ( + ['foo[\\1]:=2', 'foo[5]:=3'], + "HTTPie Type Error: Can't perform 'index' based access on 'foo' which has a type of 'object' but this operation requires a type of 'array'.\nfoo[5]\n ^^^", + ), ], ) def test_nested_json_errors(input_json, expected_error, httpbin): From 980bd59e29682caec02c9f0ecc37e5ec1349aa5a Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 7 Jan 2022 14:01:08 +0300 Subject: [PATCH 0969/1182] Rewrite the docs --- docs/README.md | 304 ++++++++++++++++++++++++++++--------------------- 1 file changed, 173 insertions(+), 131 deletions(-) diff --git a/docs/README.md b/docs/README.md index 6b19b91aa0..8adf49d4cb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -749,14 +749,9 @@ Other JSON types, however, are not allowed with `--form` or `--multipart`. ### Nested JSON fields -For creating nested JSON structures, you can simply declare the path for the object's new destination -and HTTPie will interpret it according to the [JSON form](https://www.w3.org/TR/html-json-forms/) -notation and create your object. It works directly with the existing data field (`=`) and raw JSON -field (`:=`) operators. - -#### Path Declaration - -A simple path can be a shallow key; +In the past (pre-3.0), HTTPie's data operators (`=`/`:=`) allowed you to +directly create basic JSON objects right from your terminal. Though this +functionality was limited to only top-level keys. ```bash $ http --offline --print=B pie.dev/post \ @@ -769,228 +764,275 @@ $ http --offline --print=B pie.dev/post \ } ``` -As well as a nested one, +For embedding more complex JSON objects, you needed to use the `:=` operator. ```bash $ http --offline --print=B pie.dev/post \ - result[type]=success + type=success \ + 'product:={"name":"something", "price":10}' ``` ```json { - "result": {"type": "success"} + "product": { + "name": "something", + "price": 10 + }, + "type": "success" } ``` -Or even multiple levels of nesting. +Starting with 3.0, we have embedded a mini language inside HTTPie's own syntax to +build complex JSON with ease. This syntax was inspired by the [JSON form](https://www.w3.org/TR/html-json-forms/) +proposal for HTML, though we have changed a lot of parts to offer the best experience +and reduce the number of typing-caused failures. + +#### Introduction + +Let's start with a simple introduction, and build the JSON object we have seen in the example +above: ```bash $ http --offline --print=B pie.dev/post \ - result[status][type]=ok + type=success \ + product[name]=something \ + product[price]:=10 ``` +With the new syntax, you can designate the path for the value. For example `product[name]` means +create a new object under the `product` key, and set the `name` field of that object to the given +value. + ```json { - "result": { - "status": { - "type": "ok" - } - } + "product": { + "name": "something", + "price": 10 + }, + "type": "success" } ``` -The declaration also supports creating arrays; which can be either done by simply -assigning the same path multiple times +You can also build arrays, through `[]` suffix. Which means create a list, and append the value +to that list: ```bash $ http --offline --print=B pie.dev/post \ - ids:=1 ids:=2 + search[keywords][]=soda \ + search[keywords][]=fries ``` ```json { - "ids": [ - 1, - 2 - ] + "search": { + "keywords": [ + "soda", + "fries" + ] + } } ``` -Or using the append suffix `[]`, which would create an array and append the items to the -end of it. +If you want to specify the direct index, that is also supported: ```bash $ http --offline --print=B pie.dev/post \ - ids[]:=1 + search[keywords][0]=soda \ + search[keywords][1]=fries ``` ```json { - "ids": [ - 1, - 2 - ] + "search": { + "keywords": [ + "soda", + "fries" + ] + } } ``` -You can also use indexes to set items on an array, +You can also create 'sparse arrays' (arrays where you set 2 non-consecutive indexes), which +the missing values gets nullified: ```bash $ http --offline --print=B pie.dev/post \ - items[0]=terminal items[1]=desktop + search[keywords][2]=soda \ + search[keywords][5]=fries \ + search[keywords][]=fish ``` ```json { - "items": [ - "terminal", - "desktop" - ] + "search": { + "keywords": [ + null, + null, + "soda", + null, + null, + "fries", + "fish" + ] + } } ``` -If you don't set value for the indexes between, then those will be nullified. +It is also possible to embed raw JSON to a nested structure, for example: ```bash $ http --offline --print=B pie.dev/post \ - items[1]=terminal items[3]=desktop + invitation[type]=meetup \ + 'invitation[dates]:=[2021, 2022, 2023, 2024]' \ + invitation[dates][]:=2025 ``` ```json { - "items": [ - null, - "terminal", - null, - "desktop" - ] + "invitation": { + "dates": [ + 2021, + 2022, + 2023, + 2024, + 2025 + ], + "type": "meetup" + } } ``` -It is permitted to mix index-access with append actions (`[]`), but be aware that appends will not fill -the voids but instead they will append after the last item. +And for the last, let's create a very deeply nested JSON object: + +```bash +$ http PUT pie.dev/put \ + shallow=value \ # Shallow key-value pair + object[key]=value \ # Nested key-value pair + array[]:=1 \ # Array — first item + array[1]:=2 \ # Array — second item + array[2]:=3 \ # Array — append (third item) + very[nested][json][3][httpie][power][]=Amaze # Nested object +``` + +#### Advanced Usage + +##### Escaping Behavior + +Nested JSON syntax uses the same escaping rules [escaping rules](escaping-rules) as +the terminal. There are 3 special characters, and 1 special token that you can escape. + +If you want to send a bracket as is, escape it with a backslash (`\`): ```bash $ http --offline --print=B pie.dev/post \ - items[1]=terminal items[3]=desktop items[]=web + 'foo\[bar\]:=1' \ + 'baz[\[]:=2' \ + 'baz[\]]:=3' ``` ```json { - "items": [ - null, - "terminal", - null, - "desktop", - "web" - ] + "baz": { + "[": 2, + "]": 3 + }, + "foo[bar]": 1 } ``` -If you need to send a top-level list (without any object that is encapsulating it), use the append operator (`[]`) without -any keys. +If you want the send the literal backslash character (`\`), escape it with another backslash: ```bash $ http --offline --print=B pie.dev/post \ - []:=1 []:=2 []:=3 + 'backslash[\\]:=1' ``` ```json -[ - 1, - 2, - 3 -] +{ + "backslash": { + "\\": 1 + } +} ``` -Here is a slightly unified example +A regular integer in a path (e.g `[10]`) means an array index; but if you want it to be treated as +a string, you can escape the whole number by using a backslash (`\`) prefix. ```bash -$ http --offline --print=B pie.dev/post name=python version:=3 \ - date[year]:=2021 date[month]=December \ - systems=Linux systems=Mac systems=Windows \ - people[known_ids][1]=1000 people[known_ids][5]=5000 +$ http --offline --print=B pie.dev/post \ + 'object[\1]=stringified' \ + 'object[\100]=same' \ + 'array[1]=indexified' ``` ```json { - "date": { - "month": "December", - "year": 2021 - }, - "name": "python", - "people": { - "known_ids": [ - null, - "1000", - null, - null, - null, - "5000" - ] - }, - "systems": [ - "Linux", - "Mac", - "Windows" + "array": [ + null, + "indexified" ], - "version": 3 + "object": { + "1": "stringified", + "100": "same" + } } ``` -And here is an even more comprehensive example to show all the features. +##### Guiding Syntax Errors + +If you make a typo or forget to close a bracket, the errors will guide you to fix it. For example: ```bash -$ http PUT pie.dev/put \ - 'object=scalar' \ # Object — blank key - 'object[0]=array 1' \ # Object — "0" key - 'object[key]=key key' \ # Object — "key" key - 'array:=1' \ # Array — first item - 'array:=2' \ # Array — second item - 'array[]:=3' \ # Array — append (third item) - 'wow[such][deep][3][much][power][!]=Amaze' # Nested object +$ http --offline --print=B pie.dev/post \ + 'foo[bar]=OK' \ + 'foo[baz][quux=FAIL' ``` -```http -PUT /person/1 HTTP/1.1 -Accept: application/json, */*;q=0.5 -Content-Type: application/json -Host: pie.dev +```console +HTTPie Syntax Error: Expecting ']' +foo[baz][quux + ^ +``` + +You can follow to given instruction (adding a `]`) and repair your expression. + +##### Type Safety + +Each container path (e.g `x[y][z]` in `x[y][z][1]`) has a certain type, which gets defined with +the first usage and can't be changed after that. If you try to do a key-based access to an array or +an index-based access to an object, HTTPie will error out: + +```bash +$ http --offline --print=B pie.dev/post \ + 'array[]:=1' \ + 'array[]:=2' \ + 'array[key]:=3' +HTTPie Type Error: Can't perform 'key' based access on 'array' which has a type of 'array' but this operation requires a type of 'object'. +array[key] + ^^^^^ +``` +Type Safety does not apply to value overrides, for example: + +```bash +$ http --offline --print=B pie.dev/post \ + user[name]:=411 # Defined as an integer + user[name]=string # Overridden with a string +``` + +```json { - "array": [ - 1, - 2, - 3 - ], - "object": { - "": "scalar", - "0": "array 1", - "key": "key key" - }, - "wow": { - "such": { - "deep": [ - null, - null, - null, - { - "much": { - "power": { - "!": "Amaze" - } - } - } - ] - } + "user": { + "name": "string" } } ``` -### Raw and complex JSON +### Raw JSON -Please note that with the [request items](#request-items) data field syntax, commands can quickly become unwieldy when sending complex structures. -In such cases, it’s better to pass the full raw JSON data via [raw request body](#raw-request-body), for example: +Please note that on some very complex JSON structures, manually building the JSON object right from the terminal +might be more complicated compared to typing it on a file and directly sending it through HTTPie. Depending on your +use case, some of the following examples can help: ```bash $ echo -n '{"hello": "world"}' | http POST pie.dev/post From eb4e32ca28196a9cbb8e843d4354b65199592f5f Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 7 Jan 2022 14:19:50 +0300 Subject: [PATCH 0970/1182] A few edits --- docs/README.md | 7 +++---- httpie/cli/nested_json.py | 8 +++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/README.md b/docs/README.md index 8adf49d4cb..f40e393481 100644 --- a/docs/README.md +++ b/docs/README.md @@ -782,10 +782,9 @@ $ http --offline --print=B pie.dev/post \ } ``` -Starting with 3.0, we have embedded a mini language inside HTTPie's own syntax to -build complex JSON with ease. This syntax was inspired by the [JSON form](https://www.w3.org/TR/html-json-forms/) -proposal for HTML, though we have changed a lot of parts to offer the best experience -and reduce the number of typing-caused failures. +Starting with 3.0, we have created a mini language in HTTPie's own syntax to +build complex JSON objects with ease. This syntax was inspired by the [JSON form](https://www.w3.org/TR/html-json-forms/) +proposal for HTML, though we have changed a lot of parts to offer the best experience. #### Introduction diff --git a/httpie/cli/nested_json.py b/httpie/cli/nested_json.py index 615f0427bf..59dcf3e728 100644 --- a/httpie/cli/nested_json.py +++ b/httpie/cli/nested_json.py @@ -146,7 +146,7 @@ def __init__( def reconstruct(self) -> str: if self.kind == 'key': if self.is_root: - return self.accessor + return str(self.accessor) return '[' + self.accessor + ']' elif self.kind == 'index': return '[' + str(self.accessor) + ']' @@ -186,10 +186,12 @@ def expect(*kinds): cursor += 1 if token.kind in kinds: return token - else: + elif tokens: token = tokens[-1]._replace( start=tokens[-1].end + 0, end=tokens[-1].end + 1 ) + else: + token = None if len(kinds) == 1: suffix = kinds[0].to_name() @@ -272,7 +274,7 @@ def type_check(index: int, path: Path, expected_type: Type[Any]) -> None: key, pseudo_token, message, message_kind='Type' ) - def object_for(kind: str) -> str: + def object_for(kind: str) -> Any: if kind == 'key': return {} elif kind in {'index', 'append'}: From fb82f44cd14568b0810746d6c030e542bef93e21 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 12 Jan 2022 20:37:15 +0300 Subject: [PATCH 0971/1182] Use enums --- httpie/cli/nested_json.py | 48 ++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/httpie/cli/nested_json.py b/httpie/cli/nested_json.py index 59dcf3e728..d60ea9b8aa 100644 --- a/httpie/cli/nested_json.py +++ b/httpie/cli/nested_json.py @@ -130,10 +130,22 @@ def can_advance() -> bool: yield from send_buffer() +class PathAction(Enum): + KEY = auto() + INDEX = auto() + APPEND = auto() + + # Pseudo action, used by the interpreter + SET = auto() + + def to_string(self) -> str: + return self.name.lower() + + class Path: def __init__( self, - kind: str, + kind: PathAction, accessor: Optional[Union[str, int]] = None, tokens: Optional[List[Token]] = None, is_root: bool = False, @@ -144,13 +156,13 @@ def __init__( self.is_root = is_root def reconstruct(self) -> str: - if self.kind == 'key': + if self.kind is PathAction.KEY: if self.is_root: return str(self.accessor) return '[' + self.accessor + ']' - elif self.kind == 'index': + elif self.kind is PathAction.INDEX: return '[' + str(self.accessor) + ']' - elif self.kind == 'append': + elif self.kind is PathAction.APPEND: return '[]' else: assert_cant_happen() @@ -202,7 +214,7 @@ def expect(*kinds): message = f'Expecting {suffix}' raise HTTPieSyntaxError(source, token, message) - root = Path('key', '', is_root=True) + root = Path(PathAction.KEY, '', is_root=True) if can_advance(): token = tokens[cursor] if token.kind in {TokenKind.TEXT, TokenKind.NUMBER}: @@ -221,12 +233,12 @@ def expect(*kinds): ) path_tokens.append(token) if token.kind is TokenKind.RIGHT_BRACKET: - path = Path('append', tokens=path_tokens) + path = Path(PathAction.APPEND, tokens=path_tokens) elif token.kind is TokenKind.TEXT: - path = Path('key', token.value, tokens=path_tokens) + path = Path(PathAction.KEY, token.value, tokens=path_tokens) path_tokens.append(expect(TokenKind.RIGHT_BRACKET)) elif token.kind is TokenKind.NUMBER: - path = Path('index', token.value, tokens=path_tokens) + path = Path(PathAction.INDEX, token.value, tokens=path_tokens) path_tokens.append(expect(TokenKind.RIGHT_BRACKET)) else: assert_cant_happen() @@ -246,7 +258,7 @@ def interpret(context: Any, key: str, value: Any) -> Any: cursor = context paths = list(parse(key)) - paths.append(Path('set', value)) + paths.append(Path(PathAction.SET, value)) def type_check(index: int, path: Path, expected_type: Type[Any]) -> None: if not isinstance(cursor, expected_type): @@ -262,7 +274,7 @@ def type_check(index: int, path: Path, expected_type: Type[Any]) -> None: ) required_type = JSON_TYPE_MAPPING[expected_type] - message = f"Can't perform {path.kind!r} based access on " + message = f"Can't perform {path.kind.to_string()!r} based access on " message += repr( ''.join(path.reconstruct() for path in paths[:index]) ) @@ -275,24 +287,24 @@ def type_check(index: int, path: Path, expected_type: Type[Any]) -> None: ) def object_for(kind: str) -> Any: - if kind == 'key': + if kind is PathAction.KEY: return {} - elif kind in {'index', 'append'}: + elif kind in {PathAction.INDEX, PathAction.APPEND}: return [] else: assert_cant_happen() for index, (path, next_path) in enumerate(zip(paths, paths[1:])): - if path.kind == 'key': + if path.kind is PathAction.KEY: type_check(index, path, dict) - if next_path.kind == 'set': + if next_path.kind is PathAction.SET: cursor[path.accessor] = next_path.accessor break cursor = cursor.setdefault( path.accessor, object_for(next_path.kind) ) - elif path.kind == 'index': + elif path.kind is PathAction.INDEX: type_check(index, path, list) if path.accessor < 0: raise HTTPieSyntaxError( @@ -302,7 +314,7 @@ def object_for(kind: str) -> Any: message_kind='Value', ) cursor.extend([None] * (path.accessor - len(cursor) + 1)) - if next_path.kind == 'set': + if next_path.kind is PathAction.SET: cursor[path.accessor] = next_path.accessor break @@ -310,9 +322,9 @@ def object_for(kind: str) -> Any: cursor[path.accessor] = object_for(next_path.kind) cursor = cursor[path.accessor] - elif path.kind == 'append': + elif path.kind is PathAction.APPEND: type_check(index, path, list) - if next_path.kind == 'set': + if next_path.kind is PathAction.SET: cursor.append(next_path.accessor) break From dc3091989324f4cbf9b04bcac5eeb4301ec94cd1 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 13 Jan 2022 19:45:16 +0300 Subject: [PATCH 0972/1182] use constants --- httpie/cli/constants.py | 6 ++++++ httpie/cli/nested_json.py | 17 +++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index f00911e58a..897e806b4d 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -125,3 +125,9 @@ class RequestType(enum.Enum): FORM = enum.auto() MULTIPART = enum.auto() JSON = enum.auto() + + +OPEN_BRACKET = '[' +CLOSE_BRACKET = ']' +BACKSLASH = '\\' +HIGHLIGHTER = '^' diff --git a/httpie/cli/nested_json.py b/httpie/cli/nested_json.py index d60ea9b8aa..501e3b594f 100644 --- a/httpie/cli/nested_json.py +++ b/httpie/cli/nested_json.py @@ -9,6 +9,7 @@ Type, Union, ) +from httpie.cli.constants import OPEN_BRACKET, CLOSE_BRACKET, BACKSLASH, HIGHLIGHTER class HTTPieSyntaxError(ValueError): @@ -30,7 +31,7 @@ def __str__(self): lines.append(self.source) lines.append( ' ' * (self.token.start) - + '^' * (self.token.end - self.token.start) + + HIGHLIGHTER * (self.token.end - self.token.start) ) return '\n'.join(lines) @@ -49,8 +50,8 @@ def to_name(self) -> str: return 'a ' + self.name.lower() -OPERATORS = {'[': TokenKind.LEFT_BRACKET, ']': TokenKind.RIGHT_BRACKET} -SPECIAL_CHARS = OPERATORS.keys() | {'\\'} +OPERATORS = {OPEN_BRACKET: TokenKind.LEFT_BRACKET, CLOSE_BRACKET: TokenKind.RIGHT_BRACKET} +SPECIAL_CHARS = OPERATORS.keys() | {BACKSLASH} class Token(NamedTuple): @@ -65,7 +66,7 @@ def assert_cant_happen() -> NoReturn: def check_escaped_int(value: str) -> str: - if not value.startswith('\\'): + if not value.startswith(BACKSLASH): raise ValueError('Not an escaped int') try: @@ -114,7 +115,7 @@ def can_advance() -> bool: if index in OPERATORS: yield from send_buffer() yield Token(OPERATORS[index], index, cursor, cursor + 1) - elif index == '\\' and can_advance(): + elif index == BACKSLASH and can_advance(): if source[cursor + 1] in SPECIAL_CHARS: backslashes += 1 else: @@ -159,11 +160,11 @@ def reconstruct(self) -> str: if self.kind is PathAction.KEY: if self.is_root: return str(self.accessor) - return '[' + self.accessor + ']' + return OPEN_BRACKET + self.accessor + CLOSE_BRACKET elif self.kind is PathAction.INDEX: - return '[' + str(self.accessor) + ']' + return OPEN_BRACKET + str(self.accessor) + CLOSE_BRACKET elif self.kind is PathAction.APPEND: - return '[]' + return OPEN_BRACKET + CLOSE_BRACKET else: assert_cant_happen() From 3856f94d3de23829277d02f5e5301119175a8d07 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 14 Jan 2022 13:27:19 +0300 Subject: [PATCH 0973/1182] Update the brew file --- docs/packaging/brew/httpie.rb | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/packaging/brew/httpie.rb b/docs/packaging/brew/httpie.rb index 48097e5109..382460dcdd 100644 --- a/docs/packaging/brew/httpie.rb +++ b/docs/packaging/brew/httpie.rb @@ -6,14 +6,16 @@ class Httpie < Formula url "https://files.pythonhosted.org/packages/53/96/cbcfec73c186f076e4443faf3d91cbbc868f18f6323703afd348b1aba46d/httpie-2.6.0.tar.gz" sha256 "ef929317b239bbf0a5bb7159b4c5d2edbfc55f8a0bcf9cd24ce597daec2afca5" license "BSD-3-Clause" - head "https://github.com/httpie/httpie.git" + head "https://github.com/httpie/httpie.git", branch: "master" bottle do - sha256 cellar: :any_skip_relocation, arm64_big_sur: "52946f8c07e853a3f4fa4e629c42f3655ba4eaba5fdf204bbc365377e65bbf85" - sha256 cellar: :any_skip_relocation, big_sur: "aa6fdb95027863739c34d53a5788f4dfb4593a6cde1a1f54e2bfb9c25d673ff3" - sha256 cellar: :any_skip_relocation, catalina: "ef2d994c88121e8059952c5716ff81246a8a0745ca2e3ed50249093d76d93f12" - sha256 cellar: :any_skip_relocation, mojave: "9ebdd4ac816cf6d1ed306e8cbef4a7442c7318bedd6b0f9d3809c8963a46a566" - sha256 cellar: :any_skip_relocation, x86_64_linux: "768b8806307683e91867df6975803597437c12966cc9fa4b7a4bda322fa3d7c0" + sha256 cellar: :any_skip_relocation, arm64_monterey: "83aab05ffbcd4c3baa6de6158d57ebdaa67c148bef8c872527d90bdaebff0504" + sha256 cellar: :any_skip_relocation, arm64_big_sur: "3c3a5c2458d0658e14b663495e115297c573aa3466d292f12d02c3ec13a24bdf" + sha256 cellar: :any_skip_relocation, monterey: "f860e7d3b77dca4928a2c5e10c4cbd50d792330dfb99f7d736ca0da9fb9dd0d0" + sha256 cellar: :any_skip_relocation, big_sur: "377b0643aa1f6d310ba4cfc70d66a94cc458213db8d134940d3b10a32defacf1" + sha256 cellar: :any_skip_relocation, catalina: "6d306c30f6f1d7a551d88415efe12b7c3f25d0602f3579dc632771a463f78fa5" + sha256 cellar: :any_skip_relocation, mojave: "f66b8cdff9cb7b44a84197c3e3d81d810f7ff8f2188998b977ccadfc7e2ec893" + sha256 cellar: :any_skip_relocation, x86_64_linux: "53f036b0114814c28982e8c022dcf494e7024de088641d7076fd73d12a45a0e9" end depends_on "python@3.10" @@ -24,8 +26,8 @@ class Httpie < Formula end resource "charset-normalizer" do - url "https://files.pythonhosted.org/packages/9f/c5/334c019f92c26e59637bb42bd14a190428874b2b2de75a355da394cf16c1/charset-normalizer-2.0.7.tar.gz" - sha256 "e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0" + url "https://files.pythonhosted.org/packages/48/44/76b179e0d1afe6e6a91fd5661c284f60238987f3b42b676d141d01cd5b97/charset-normalizer-2.0.10.tar.gz" + sha256 "876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd" end resource "defusedxml" do @@ -34,13 +36,13 @@ class Httpie < Formula end resource "idna" do - url "https://files.pythonhosted.org/packages/62/08/e3fc7c8161090f742f504f40b1bccbfc544d4a4e09eb774bf40aafce5436/idna-3.3.tar.gz" - sha256 "9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + url "https://files.pythonhosted.org/packages/cb/38/4c4d00ddfa48abe616d7e572e02a04273603db446975ab46bbcd36552005/idna-3.2.tar.gz" + sha256 "467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" end resource "Pygments" do - url "https://files.pythonhosted.org/packages/b7/b3/5cba26637fe43500d4568d0ee7b7362de1fb29c0e158d50b4b69e9a40422/Pygments-2.10.0.tar.gz" - sha256 "f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6" + url "https://files.pythonhosted.org/packages/94/9c/cb656d06950268155f46d4f6ce25d7ffc51a0da47eadf1b164bbf23b718b/Pygments-2.11.2.tar.gz" + sha256 "4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a" end resource "PySocks" do @@ -49,8 +51,8 @@ class Httpie < Formula end resource "requests" do - url "https://files.pythonhosted.org/packages/e7/01/3569e0b535fb2e4a6c384bdbed00c55b9d78b5084e0fb7f4d0bf523d7670/requests-2.26.0.tar.gz" - sha256 "b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" + url "https://files.pythonhosted.org/packages/60/f3/26ff3767f099b73e0efa138a9998da67890793bfa475d8278f84a30fec77/requests-2.27.1.tar.gz" + sha256 "68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61" end resource "requests-toolbelt" do @@ -59,8 +61,8 @@ class Httpie < Formula end resource "urllib3" do - url "https://files.pythonhosted.org/packages/80/be/3ee43b6c5757cabea19e75b8f46eaf05a2f5144107d7db48c7cf3a864f73/urllib3-1.26.7.tar.gz" - sha256 "4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece" + url "https://files.pythonhosted.org/packages/b0/b1/7bbf5181f8e3258efae31702f5eab87d8a74a72a0aa78bc8c08c1466e243/urllib3-1.26.8.tar.gz" + sha256 "0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c" end resource "multidict" do From 87629706c933a33adbfb5b4f5e435be722eb057b Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 14 Jan 2022 19:47:10 +0300 Subject: [PATCH 0974/1182] Change the default style for windows from fruity to auto (#1268) --- CHANGELOG.md | 1 + httpie/output/formatters/colors.py | 6 ------ tests/test_json.py | 3 +-- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd73afcc22..820cabc62c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156)) - Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/httpie/issues/1242)) - Fixed an unexpected crash when `--raw` is used with `--chunked`. ([#1253](https://github.com/httpie/httpie/issues/1253)) +- Changed the default Windows theme from `fruity` to `auto`. ([#1266](https://github.com/httpie/httpie/issues/1266)) ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 454dc1154d..135eb7cd0c 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -18,7 +18,6 @@ from ..lexers.json import EnhancedJsonLexer from ..lexers.metadata import MetadataLexer from ..ui.palette import SHADE_NAMES, get_color -from ...compat import is_windows from ...context import Environment from ...plugins import FormatterPlugin @@ -27,11 +26,6 @@ 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. - DEFAULT_STYLE = 'fruity' - BUNDLED_STYLES = { SOLARIZED_STYLE, AUTO_STYLE diff --git a/tests/test_json.py b/tests/test_json.py index ae74834035..b454c03408 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -6,7 +6,6 @@ from httpie.cli.constants import PRETTY_MAP from httpie.cli.exceptions import ParseError from httpie.cli.nested_json import HTTPieSyntaxError -from httpie.compat import is_windows from httpie.output.formatters.colors import ColorFormatter from httpie.utils import JsonDictPreservingDuplicateKeys @@ -39,7 +38,7 @@ False, None, ] -TEST_PREFIX_TOKEN_COLOR = '\x1b[38;5;15m' if is_windows else '\x1b[04m\x1b[91m' +TEST_PREFIX_TOKEN_COLOR = '\x1b[04m\x1b[91m' JSON_WITH_DUPES_RAW = '{"key": 15, "key": 15, "key": 3, "key": 7}' JSON_WITH_DUPES_FORMATTED_SORTED = """{ From cd877a5e0875bfc27d560956b21230e65ad8c347 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 14 Jan 2022 19:49:05 +0300 Subject: [PATCH 0975/1182] Remove 3.6 support / discontinue less available platforms (#1267) * Remove redundant systems * Drop it from the docs * Remove the packaging info about the legacy systems * Fix some typos * Drop support for python 3.6 --- .github/workflows/test-package-linux-snap.yml | 1 + .github/workflows/tests.yml | 2 +- CHANGELOG.md | 1 + CONTRIBUTING.md | 2 +- docs/README.md | 72 +---------------- docs/installation/methods.yml | 72 +---------------- docs/packaging/README.md | 9 +-- docs/packaging/linux-alpine/APKBUILD | 41 ---------- docs/packaging/linux-alpine/README.md | 67 ---------------- docs/packaging/linux-aosc/README.md | 24 ------ docs/packaging/linux-aosc/autobuild/defines | 8 -- docs/packaging/linux-aosc/spec | 5 -- docs/packaging/linux-gentoo/Manifest | 3 - docs/packaging/linux-gentoo/README.md | 78 ------------------- .../linux-gentoo/httpie-2.6.0.ebuild | 43 ---------- docs/packaging/linux-gentoo/metadata.xml | 21 ----- docs/packaging/linux-void/README.md | 73 ----------------- docs/packaging/linux-void/template | 29 ------- docs/packaging/mac-ports/Portfile | 5 +- docs/packaging/spack/README.md | 50 ------------ docs/packaging/spack/package.py | 36 --------- .../windows-chocolatey/httpie.nuspec | 2 +- httpie/plugins/manager.py | 13 +--- setup.py | 2 +- 24 files changed, 13 insertions(+), 646 deletions(-) delete mode 100644 docs/packaging/linux-alpine/APKBUILD delete mode 100644 docs/packaging/linux-alpine/README.md delete mode 100644 docs/packaging/linux-aosc/README.md delete mode 100644 docs/packaging/linux-aosc/autobuild/defines delete mode 100644 docs/packaging/linux-aosc/spec delete mode 100644 docs/packaging/linux-gentoo/Manifest delete mode 100644 docs/packaging/linux-gentoo/README.md delete mode 100644 docs/packaging/linux-gentoo/httpie-2.6.0.ebuild delete mode 100644 docs/packaging/linux-gentoo/metadata.xml delete mode 100644 docs/packaging/linux-void/README.md delete mode 100644 docs/packaging/linux-void/template delete mode 100644 docs/packaging/spack/README.md delete mode 100644 docs/packaging/spack/package.py diff --git a/.github/workflows/test-package-linux-snap.yml b/.github/workflows/test-package-linux-snap.yml index 316b3ac268..17200074e2 100644 --- a/.github/workflows/test-package-linux-snap.yml +++ b/.github/workflows/test-package-linux-snap.yml @@ -19,6 +19,7 @@ jobs: run: | httpie.http --version httpie.https --version + httpie --version # Auto-aliases cannot be tested when installing a snap outside the store. # http --version # https --version diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b8409f7c64..96289c603c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: [3.6, 3.7, 3.8, 3.9, "3.10"] + python-version: [3.7, 3.8, 3.9, "3.10"] pyopenssl: [0, 1] runs-on: ${{ matrix.os }} steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 820cabc62c..d69956cb03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [3.0.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) +- Drop support for Python 3.6. ([#1177](https://github.com/httpie/httpie/issues/1177)) - Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) - Added support for nested JSON syntax. ([#1169](https://github.com/httpie/httpie/issues/1169)) - Added `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/httpie/issues/566)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2eeac05d43..555aa913b9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -162,7 +162,7 @@ oversight. Ping one of the maintainers to get a `benchmark` label on your branch If you are on a Windows machine and not able to run `make`, follow the next steps for a basic setup. As a prerequisite, you need to have -Python 3.6+ installed. +Python 3.7+ installed. Create a virtual environment and activate it: diff --git a/docs/README.md b/docs/README.md index f40e393481..0c1cd9463f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -60,7 +60,7 @@ Do not edit here, but in docs/installation/. #### PyPI -Please make sure you have Python 3.6 or newer (`python --version`). +Please make sure you have Python 3.7 or newer (`python --version`). ```bash # Install httpie @@ -108,20 +108,6 @@ $ port selfupdate $ port upgrade httpie ``` -#### Spack (macOS) - -To install [Spack](https://spack.readthedocs.io/en/latest/index.html), see [its installation](https://spack.readthedocs.io/en/latest/getting_started.html#installation). - -```bash -# Install httpie -$ spack install httpie -``` - -```bash -# Upgrade httpie -$ spack install httpie -``` - ### Windows #### Chocolatey @@ -213,34 +199,6 @@ $ yum install httpie $ yum upgrade httpie ``` -#### Alpine Linux - -```bash -# Install httpie -$ apk update -$ apk add httpie -``` - -```bash -# Upgrade httpie -$ apk update -$ apk add --upgrade httpie -``` - -#### Gentoo - -```bash -# Install httpie -$ emerge --sync -$ emerge httpie -``` - -```bash -# Upgrade httpie -$ emerge --sync -$ emerge --update httpie -``` - #### Arch Linux Also works for other Arch-derived distributions like ArcoLinux, EndeavourOS, Artix Linux, etc. @@ -255,34 +213,6 @@ $ pacman -Sy httpie $ pacman -Syu httpie ``` -#### Void Linux - -```bash -# Install httpie -$ xbps-install -Su -$ xbps-install -S httpie -``` - -```bash -# Upgrade httpie -$ xbps-install -Su -$ xbps-install -Su httpie -``` - -#### Spack (Linux) - -To install [Spack](https://spack.readthedocs.io/en/latest/index.html), see [its installation](https://spack.readthedocs.io/en/latest/getting_started.html#installation). - -```bash -# Install httpie -$ spack install httpie -``` - -```bash -# Upgrade httpie -$ spack install httpie -``` - ### FreeBSD #### FreshPorts diff --git a/docs/installation/methods.yml b/docs/installation/methods.yml index d84b30cfbf..1583b2364a 100644 --- a/docs/installation/methods.yml +++ b/docs/installation/methods.yml @@ -14,7 +14,6 @@ docs-structure: macOS: - brew-mac - port - - spack-mac Windows: - chocolatey Linux: @@ -23,29 +22,11 @@ docs-structure: - apt - dnf - yum - - apk - - emerge - pacman - - xbps-install - - spack-linux FreeBSD: - pkg tools: - apk: - title: Alpine Linux - name: apk - links: - homepage: https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management - package: https://pkgs.alpinelinux.org/package/edge/community/x86/httpie - commands: - install: - - apk update - - apk add httpie - upgrade: - - apk update - - apk add --upgrade httpie - apt: title: Debian and Ubuntu note: Also works for other Debian-derived distributions like MX Linux, Linux Mint, deepin, Pop!_OS, KDE neon, Zorin OS, elementary OS, Kubuntu, Devuan, Linux Lite, Peppermint OS, Lubuntu, antiX, Xubuntu, etc. @@ -116,20 +97,6 @@ tools: upgrade: - dnf upgrade httpie - emerge: - title: Gentoo - name: Portage - links: - homepage: https://wiki.gentoo.org/wiki/Portage - package: https://packages.gentoo.org/packages/net-misc/httpie - commands: - install: - - emerge --sync - - emerge httpie - upgrade: - - emerge --sync - - emerge --update httpie - pacman: title: Arch Linux name: pacman @@ -173,7 +140,7 @@ tools: pypi: title: PyPI name: pip - note: Please make sure you have Python 3.6 or newer (`python --version`). + note: Please make sure you have Python 3.7 or newer (`python --version`). links: homepage: https://pypi.org/ # setup: https://pip.pypa.io/en/stable/installation/ @@ -199,43 +166,6 @@ tools: upgrade: - snap refresh httpie - spack-linux: - title: Spack (Linux) - name: Spack - links: - homepage: https://spack.readthedocs.io/en/latest/index.html - setup: https://spack.readthedocs.io/en/latest/getting_started.html#installation - commands: - install: - - spack install httpie - upgrade: - - spack install httpie - - spack-mac: - title: Spack (macOS) - name: Spack - links: - homepage: https://spack.readthedocs.io/en/latest/index.html - setup: https://spack.readthedocs.io/en/latest/getting_started.html#installation - commands: - install: - - spack install httpie - upgrade: - - spack install httpie - - xbps-install: - title: Void Linux - name: XBPS - links: - homepage: https://docs.voidlinux.org/xbps/index.html - commands: - install: - - xbps-install -Su - - xbps-install -S httpie - upgrade: - - xbps-install -Su - - xbps-install -Su httpie - yum: title: CentOS and RHEL name: Yum diff --git a/docs/packaging/README.md b/docs/packaging/README.md index 6654789c58..c8d18b2832 100644 --- a/docs/packaging/README.md +++ b/docs/packaging/README.md @@ -12,11 +12,11 @@ You are looking at the HTTPie packaging documentation, where you will find valua The overall release process starts simple: -1. Do the [PyPi](https://pypi.org/project/httpie/) publication. +1. Do the [PyPI](https://pypi.org/project/httpie/) publication. 2. Then, handle company-related tasks. 3. Finally, follow OS-specific steps, described in documents below, to send patches downstream. -## First, PyPi +## First, PyPI Let's do the release on [PyPi](https://pypi.org/project/httpie/). That is done quite easily by manually triggering the [release workflow](https://github.com/httpie/httpie/actions/workflows/release.yml). @@ -34,18 +34,13 @@ A more complete state of deployment can be found on [repology](https://repology. | OS | Maintainer | | -------------------------------------------: | -------------- | -| [Alpine](linux-alpine/) | **HTTPie** | | [Arch Linux, and derived](linux-arch/) | trusted person | -| :construction: [AOSC OS](linux-aosc/) | **HTTPie** | | [CentOS, RHEL, and derived](linux-centos/) | trusted person | | [Debian, Ubuntu, and derived](linux-debian/) | trusted person | | [Fedora](linux-fedora/) | trusted person | -| [Gentoo](linux-gentoo/) | **HTTPie** | | :construction: [Homebrew, Linuxbrew](brew/) | **HTTPie** | | :construction: [MacPorts](mac-ports/) | **HTTPie** | | [Snapcraft](snapcraft/) | **HTTPie** | -| [Spack](spack/) | **HTTPie** | -| [Void Linux](linux-void/) | **HTTPie** | | [Windows — Chocolatey](windows-chocolatey/) | **HTTPie** | :new: You do not find your system or you would like to see HTTPie supported on another OS? Then [let us know](https://github.com/httpie/httpie/issues/). diff --git a/docs/packaging/linux-alpine/APKBUILD b/docs/packaging/linux-alpine/APKBUILD deleted file mode 100644 index 17ffda2d15..0000000000 --- a/docs/packaging/linux-alpine/APKBUILD +++ /dev/null @@ -1,41 +0,0 @@ -# Contributor: Fabian Affolter -# Maintainer: Fabian Affolter -# Contributor: Daniel Isaksen -# Contributor: Mickaël Schoentgen -pkgname=httpie -pkgver=2.6.0 -pkgrel=0 -pkgdesc="Modern, user-friendly command-line HTTP client for the API era" -url="https://httpie.org/" -arch="noarch" -license="BSD-3-Clause" -depends=" - python3 - py3-setuptools - py3-requests - py3-pygments - py3-requests-toolbelt - py3-pysocks - py3-defusedxml - py3-charset-normalizer - " -checkdepends="py3-pytest py3-pytest-httpbin py3-responses" -source="https://files.pythonhosted.org/packages/source/h/httpie/httpie-$pkgver.tar.gz" - -# secfixes: -# 1.0.3-r0: -# - CVE-2019-10751 - -build() { - python3 setup.py build -} - -check() { - python3 -m pytest ./httpie ./tests -} - -package() { - python3 setup.py install --prefix=/usr --root="$pkgdir" -} - -sha512sums="a38e9769c1994fcb4e5f898e5a72283c636ea155f1fc4d594eb59c43fe98115335dec4fddd6d4e396bd11b674715c573d2fc40c4afb732ba31da0cb8e2068fd2 httpie-2.6.0.tar.gz" diff --git a/docs/packaging/linux-alpine/README.md b/docs/packaging/linux-alpine/README.md deleted file mode 100644 index 225bd74f18..0000000000 --- a/docs/packaging/linux-alpine/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# HTTPie on Alpine Linux - -Welcome to the documentation about **packaging HTTPie for Alpine Linux**. - -- If you do not know HTTPie, have a look [here](https://httpie.io/cli). -- If you are looking for HTTPie installation or upgrade instructions on Alpine Linux, then you can find them on [that page](https://httpie.io/docs#alpine-linux). -- If you are looking for technical information about the HTTPie packaging on Alpine Linux, then you are in a good place. - -## About - -This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Alpine Linux. -We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. - -## Overall process - -Open a pull request to update the [downstream file](https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/httpie/APKBUILD) ([example](https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/25075)). - -Notes: - -- The `pkgrel` value must be set to `0`. -- The commit message must be `community/httpie: upgrade to XXX`. -- The commit must be signed-off (`git commit -s`). - -## Hacking - -Launch the docker image: - -```bash -docker pull alpine -docker run -it --rm alpine -``` - -From inside the container: - -```bash -# Install tools -apk add alpine-sdk sudo - -# Add a user (password required) -adduser me -addgroup me abuild -echo "me ALL=(ALL) ALL" >> /etc/sudoers - -# Switch user -su - me - -# Create a private key (not used but required) -abuild-keygen -a -i - -# Clone -git clone --depth=1 https://gitlab.alpinelinux.org/alpine/aports.git -cd aports/community/httpie - -# Retrieve the patch of the latest HTTPie version -curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-alpine/APKBUILD \ - -o APKBUILD - -# Build the package -abuild -r - -# Install the package -sudo apk add --repository ~/packages/community httpie - -# And test it! -http --version -https --version -``` diff --git a/docs/packaging/linux-aosc/README.md b/docs/packaging/linux-aosc/README.md deleted file mode 100644 index 72cc67439c..0000000000 --- a/docs/packaging/linux-aosc/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# HTTPie on AOSC OS - -Welcome to the documentation about **packaging HTTPie for AOSC OS**. - -- If you do not know HTTPie, have a look [here](https://httpie.io/cli). -- If you are looking for technical information about the HTTPie packaging on AOSC OS, then you are in a good place. - -## About - -This document contains technical details, where we describe how to create a patch for the latest HTTPie version for AOSC OS. -We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. - -## Overall process - -Open a pull request to update the [downstream file](https://github.com/AOSC-Dev/aosc-os-abbs/blob/stable/extra-web/httpie/spec) ([example](https://github.com/AOSC-Dev/aosc-os-abbs/commit/d0d3ba0bcea347387bb582a1b0b1b4e518720c80)). - -Notes: - -- The commit message must be `httpie: update to XXX`. -- The commit must be signed-off (`git commit -s`). - -## Hacking - -:construction: Work in progress. diff --git a/docs/packaging/linux-aosc/autobuild/defines b/docs/packaging/linux-aosc/autobuild/defines deleted file mode 100644 index e59dea204c..0000000000 --- a/docs/packaging/linux-aosc/autobuild/defines +++ /dev/null @@ -1,8 +0,0 @@ -PKGNAME=httpie -PKGSEC=utils -PKGDEP="charset-normalizer defusedxml requests toolbelt pygments pysocks" -PKGDES="Modern, user-friendly command-line HTTP client for the API era" - -ABHOST=noarch -ABTYPE=python -NOPYTHON2=1 diff --git a/docs/packaging/linux-aosc/spec b/docs/packaging/linux-aosc/spec deleted file mode 100644 index ee235501fd..0000000000 --- a/docs/packaging/linux-aosc/spec +++ /dev/null @@ -1,5 +0,0 @@ -VER=2.5.0 -SRCS="tbl::https://github.com/httpie/httpie/archive/$VER.tar.gz" -CHKSUMS="sha256::66af56e0efc1ca6237323f1186ba34bca1be24e67a4319fd5df7228ab986faea" -REL=1 -CHKUPDATE="anitya::id=1337" diff --git a/docs/packaging/linux-gentoo/Manifest b/docs/packaging/linux-gentoo/Manifest deleted file mode 100644 index e11717c653..0000000000 --- a/docs/packaging/linux-gentoo/Manifest +++ /dev/null @@ -1,3 +0,0 @@ -DIST httpie-2.4.0.tar.gz 1772537 BLAKE2B 111451cc7dc353d5b586554f98ac715a3198f03e74d261944a5f021d2dcc948455500800222b323d182a2a067d0549bda7c318ab3a6c934b9a9beec64aff2db2 SHA512 44cc7ff4fe0f3d8c53a7dd750465f6b56c36f5bbac06d22b760579bd60949039e82313845699669a659ec91adc69dbeac22c06ddd63af64e6f2e0edecf3e732a -DIST httpie-2.5.0.tar.gz 1105177 BLAKE2B 6e16868c81522d4e6d2fc0a4e093c190f18ced720b35217930865ae3f8e168193cc33dfecc13c5d310f52647d6e79d17b247f56e56e8586d633a2d9502be66a7 SHA512 f14aa23fea7578181b9bd6ededea04de9ddf0b2f697b23f76d2d96e2c17b95617318c711750bad6af550400dbc03732ab17fdf84e59d577f33f073e600a55330 -DIST httpie-2.6.0.tar.gz 1133495 BLAKE2B 3ac61fc68ab59ac7523b030a8c7af85c4af05357aa19282b514b813351efabe783f47ab82d292117e0a9170ff793b71356941dc4eb159c585629cae3adec9b5a SHA512 acd7dc847b67e27909c49ccddec84321c4d73fa5b49f06ce3d94d790093a8f168a1c6627bc4921ca8c0e48b9904f38e17935b645495e2313d16ac2eecf659038 diff --git a/docs/packaging/linux-gentoo/README.md b/docs/packaging/linux-gentoo/README.md deleted file mode 100644 index d49a25e892..0000000000 --- a/docs/packaging/linux-gentoo/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# HTTPie on Gentoo - -Welcome to the documentation about **packaging HTTPie for Gentoo**. - -- If you do not know HTTPie, have a look [here](https://httpie.io/cli). -- If you are looking for HTTPie installation or upgrade instructions on Gentoo, then you can find them on [that page](https://httpie.io/docs#gentoo). -- If you are looking for technical information about the HTTPie packaging on Gentoo, then you are in a good place. - -## About - -This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Gentoo. -We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. - -## Overall process - -Open a pull request to create `httpie-XXX.ebuild` and update `Manifest` ([example](https://github.com/gentoo/gentoo/pull/22576)). - -- Here is how to calculate the size and checksum (replace `2.5.0` with the correct version): - - ```bash - # Download - $ wget https://github.com/httpie/httpie/archive/2.5.0.tar.gz - - # Size - $ stat --printf="%s\n" 2.5.0.tar.gz - 1105177 - - # Checksum - $ openssl dgst -blake2b512 2.5.0.tar.gz - BLAKE2b512(2.5.0.tar.gz)= 6e16868c81522d4e6d2fc0a4e093c190f18ced720b35217930865ae3f8e168193cc33dfecc13c5d310f52647d6e79d17b247f56e56e8586d633a2d9502be66a7 - ``` - -- The commit message must be `net-misc/httpie: version bump to XXX`. -- The commit must be signed-off (`git commit -s`). - -## Hacking - -Launch the docker image: - -```bash -docker pull gentoo/stage3 -docker run -it --rm gentoo/stage3 -``` - -From inside the container: - -```bash -# Install tools -emerge --sync -emerge pkgcheck repoman - -# Go to the package location -cd /var/db/repos/gentoo/net-misc/httpie - -# Retrieve the patch of the latest HTTPie version -# (only files that were modified since the previous release) -curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-gentoo/httpie-XXX.ebuild \ - -o httpie-XXX.ebuild -curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-gentoo/Manifest \ - -o Manifest -curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-gentoo/metadata.xml \ - -o metadata.xml - -# Basic checks -repoman manifest -repoman full -d -x -pkgcheck scan - -# Build and install the package -emerge --with-test-deps httpie-XXX.ebuild - -# Run the tests suite -ebuild httpie-XXX.ebuild clean test - -# And test it! -http --version -https --version -``` diff --git a/docs/packaging/linux-gentoo/httpie-2.6.0.ebuild b/docs/packaging/linux-gentoo/httpie-2.6.0.ebuild deleted file mode 100644 index 9190f742b5..0000000000 --- a/docs/packaging/linux-gentoo/httpie-2.6.0.ebuild +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -DISTUTILS_USE_SETUPTOOLS=rdepend -PYTHON_COMPAT=( python3_{8,9,10} ) -PYTHON_REQ_USE="ssl(+)" - -inherit bash-completion-r1 distutils-r1 - -DESCRIPTION="Modern, user-friendly command-line HTTP client for the API era" -HOMEPAGE="https://httpie.io/ https://pypi.org/project/httpie/" -SRC_URI="https://github.com/httpie/httpie/archive/${PV}.tar.gz -> ${P}.tar.gz" - -LICENSE="BSD" -SLOT="0" -KEYWORDS="~amd64 ~x86" - -RDEPEND=" - dev-python/charset_normalizer[${PYTHON_USEDEP}] - dev-python/defusedxml[${PYTHON_USEDEP}] - dev-python/pygments[${PYTHON_USEDEP}] - >=dev-python/requests-2.22.0[${PYTHON_USEDEP}] - >=dev-python/requests-toolbelt-0.9.1[${PYTHON_USEDEP}] -" -BDEPEND=" - test? ( - ${RDEPEND} - dev-python/pyopenssl[${PYTHON_USEDEP}] - dev-python/pytest-httpbin[${PYTHON_USEDEP}] - dev-python/responses[${PYTHON_USEDEP}] - ) -" - -distutils_enable_tests pytest - -python_install_all() { - newbashcomp extras/httpie-completion.bash http - insinto /usr/share/fish/vendor_completions.d - newins extras/httpie-completion.fish http.fish - distutils-r1_python_install_all -} diff --git a/docs/packaging/linux-gentoo/metadata.xml b/docs/packaging/linux-gentoo/metadata.xml deleted file mode 100644 index cba10e14d2..0000000000 --- a/docs/packaging/linux-gentoo/metadata.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - HTTPie (pronounced aitch-tee-tee-pie) is a command line HTTP - client. Its goal is to make CLI interaction with web services as - human-friendly as possible. It provides a simple http command - that allows for sending arbitrary HTTP requests using a simple - and natural syntax, and displays colorized output. HTTPie can be - used for testing, debugging, and generally interacting with HTTP - servers. - - - https://github.com/httpie/httpie/issues - https://raw.githubusercontent.com/httpie/httpie/master/CHANGELOG.md - https://httpie.io/docs - httpie/httpie - httpie - - diff --git a/docs/packaging/linux-void/README.md b/docs/packaging/linux-void/README.md deleted file mode 100644 index 7836851da6..0000000000 --- a/docs/packaging/linux-void/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# HTTPie on Void Linux - -Welcome to the documentation about **packaging HTTPie for Void Linux**. - -- If you do not know HTTPie, have a look [here](https://httpie.io/cli). -- If you are looking for HTTPie installation or upgrade instructions on Void Linux, then you can find them on [that page](https://httpie.io/docs#void-linux). -- If you are looking for technical information about the HTTPie packaging on Void Linux, then you are in a good place. - -## About - -This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Void Linux. -We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. - -## Overall process - -Open a pull request to update the [downstream file](https://github.com/void-linux/void-packages/blob/master/srcpkgs/httpie/template) ([example](https://github.com/void-linux/void-packages/pull/33539)). - -- The `revision` must be set to `0`. -- The commit message must be `httpie: update to XXX.`. -- The commit must be signed-off (`git commit -s`). - -## Hacking - -Launch the docker image: - -```bash -docker pull voidlinux/voidlinux -docker run -it --rm voidlinux/voidlinux -``` - -From inside the container: - -```bash -# Sync and upgrade once, assume error comes from xbps update -xbps-install -Syu -# Install tools -xbps-install -y git xtools file util-linux binutils bsdtar coreutils - -# Clone -git clone --depth=1 git://github.com/void-linux/void-packages.git void-packages-src -cd void-packages-src - -# Retrieve the patch of the latest HTTPie version -curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/linux-void/template \ - -o srcpkgs/httpie/template - -# Check the package -xlint srcpkgs/httpie/template - -# Link / to /masterdir -ln -s / masterdir - -# Enable ethereal chroot-style -echo XBPS_BUILD_ENVIRONMENT=void-packages-ci >> etc/conf -echo XBPS_ALLOW_RESTRICTED=yes >> etc/conf -echo XBPS_CHROOT_CMD=ethereal >> etc/conf -echo XBPS_ALLOW_CHROOT_BREAKOUT=yes >> etc/conf -export XBPS_ALLOW_CHROOT_BREAKOUT=yes -./xbps-src binary-bootstrap -./xbps-src chroot - -# Build the package -cd void-packages -export SOURCE_DATE_EPOCH=0 -./xbps-src pkg httpie - -# Install the package -xbps-install --repository=hostdir/binpkgs httpie - -# And finally test it! -http --version -https --version -``` diff --git a/docs/packaging/linux-void/template b/docs/packaging/linux-void/template deleted file mode 100644 index c4a64ff89e..0000000000 --- a/docs/packaging/linux-void/template +++ /dev/null @@ -1,29 +0,0 @@ -# Template file for 'httpie' -pkgname=httpie -version=2.6.0 -revision=1 -build_style=python3-module -hostmakedepends="python3-setuptools" -depends="python3-setuptools python3-requests python3-requests-toolbelt - python3-Pygments python3-pysocks python3-defusedxml - python3-charset-normalizer" -short_desc="Modern, user-friendly command-line HTTP client for the API era" -maintainer="Jakub Roztocil " -license="BSD-3-Clause" -homepage="https://httpie.io/" -changelog="https://raw.githubusercontent.com/httpie/httpie/master/CHANGELOG.md" -distfiles="https://github.com/httpie/httpie/archive/${version}.tar.gz" -checksum=3bcd9a8cb2b11299da12d3af36c095c6d4b665e41c395898a07f1ae4d99fc14a -make_check=no # needs pytest_httpbin which is not packaged - -post_install() { - vcompletion extras/httpie-completion.bash bash http - vcompletion extras/httpie-completion.fish fish http - vlicense LICENSE -} - -python3-httpie_package() { - build_style=meta - short_desc+=" (transitional dummy package)" - depends="httpie>=${version}_${revision}" -} diff --git a/docs/packaging/mac-ports/Portfile b/docs/packaging/mac-ports/Portfile index 26c91d820e..6d113727d3 100644 --- a/docs/packaging/mac-ports/Portfile +++ b/docs/packaging/mac-ports/Portfile @@ -20,15 +20,12 @@ platforms darwin license BSD homepage https://httpie.io/ -variant python36 conflicts python37 python38 python39 python310 description "Use Python 3.6" {} variant python37 conflicts python36 python38 python39 python310 description "Use Python 3.7" {} variant python38 conflicts python36 python37 python39 python310 description "Use Python 3.8" {} variant python39 conflicts python36 python37 python38 python310 description "Use Python 3.9" {} variant python310 conflicts python36 python37 python38 python39 description "Use Python 3.10" {} -if {[variant_isset python36]} { - python.default_version 36 -} elseif {[variant_isset python37]} { +if {[variant_isset python37]} { python.default_version 37 } elseif {[variant_isset python39]} { python.default_version 39 diff --git a/docs/packaging/spack/README.md b/docs/packaging/spack/README.md deleted file mode 100644 index ccd05977b5..0000000000 --- a/docs/packaging/spack/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# HTTPie on Spack - -Welcome to the documentation about **packaging HTTPie for Spack**. - -- If you do not know HTTPie, have a look [here](https://httpie.io/cli). -- If you are looking for HTTPie installation or upgrade instructions on Spack, then you can find them on [that page](https://httpie.io/docs#spack-linux) ([that one](https://httpie.io/docs#spack-macos) for macOS). -- If you are looking for technical information about the HTTPie packaging on Spack, then you are in a good place. - -## About - -This document contains technical details, where we describe how to create a patch for the latest HTTPie version for Spack. They apply to Spack on Linux, and macOS. -We will discuss setting up the environment, installing development tools, installing and testing changes before submitting a patch downstream. - -## Overall process - -Open a pull request to update the [downstream file](https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/httpie/package.py) ([example](https://github.com/spack/spack/pull/25888)). - -- The commit message must be `httpie: add vXXX`. -- The commit must be signed-off (`git commit -s`). - -## Hacking - -Launch the docker image: - -```bash -docker pull spack/centos7 -docker run -it --rm spack/centos7 -``` - -From inside the container: - -```bash -# Retrieve the patch of the latest HTTPie version -curl https://raw.githubusercontent.com/httpie/httpie/master/docs/packaging/spack/package.py \ - -o /opt/spack/var/spack/repos/builtin/packages/httpie/package.py - -# Check available versions (it should show the new version) -spack versions httpie - -# Check the package -spack spec httpie@XXX - -# Install the package -spack install httpie@XXX -spack load httpie - -# And test it! -http --version -https --version -``` diff --git a/docs/packaging/spack/package.py b/docs/packaging/spack/package.py deleted file mode 100644 index 7ac511563a..0000000000 --- a/docs/packaging/spack/package.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other -# Spack Project Developers. See the top-level COPYRIGHT file for details. -# -# SPDX-License-Identifier: (Apache-2.0 OR MIT) - -from spack import * - - -class Httpie(PythonPackage): - """Modern, user-friendly command-line HTTP client for the API era.""" - - homepage = 'https://httpie.io/' - pypi = 'httpie/httpie-2.6.0.tar.gz' - maintainers = ['jakubroztocil'] - - version('2.6.0', sha256='ef929317b239bbf0a5bb7159b4c5d2edbfc55f8a0bcf9cd24ce597daec2afca5') - version('2.5.0', sha256='fe6a8bc50fb0635a84ebe1296a732e39357c3e1354541bf51a7057b4877e47f9') - # TODO: Remove both versions for HTTPie 2.7.0. - version('0.9.9', sha256='f1202e6fa60367e2265284a53f35bfa5917119592c2ab08277efc7fffd744fcb', deprecated=True) - version('0.9.8', sha256='515870b15231530f56fe2164190581748e8799b66ef0fe36ec9da3396f0df6e1', deprecated=True) - - depends_on('python@3.6:', when='@2.5:', type=('build', 'run')) - depends_on('py-setuptools', type=('build', 'run')) - depends_on('py-charset-normalizer@2:', when='@2.6:', type=('build', 'run')) - depends_on('py-defusedxml@0.6:', when='@2.5:', type=('build', 'run')) - depends_on('py-pygments@2.1.3:', type=('build', 'run')) - depends_on('py-pygments@2.5.2:', when='@2.5:', type=('build', 'run')) - depends_on('py-requests@2.11:', type=('build', 'run')) - depends_on('py-requests@2.22:+socks', when='@2.5:', type=('build', 'run')) - depends_on('py-requests-toolbelt@0.9.1:', when='@2.5:', type=('build', 'run')) - # TODO: Remove completely py-argparse for HTTPie 2.7.0. - # Concretization problem breaks this. Unconditional for now... - # https://github.com/spack/spack/issues/3628 - # depends_on('py-argparse@1.2.1:', type=('build', 'run'), - # when='^python@:2.6,3.0:3.1') - depends_on('py-argparse@1.2.1:', type=('build', 'run'), when='^python@:2.6') diff --git a/docs/packaging/windows-chocolatey/httpie.nuspec b/docs/packaging/windows-chocolatey/httpie.nuspec index e43b71ee32..ce69afa5a7 100644 --- a/docs/packaging/windows-chocolatey/httpie.nuspec +++ b/docs/packaging/windows-chocolatey/httpie.nuspec @@ -41,7 +41,7 @@ Main features: https://httpie.io/docs https://github.com/httpie/httpie/issues - + diff --git a/httpie/plugins/manager.py b/httpie/plugins/manager.py index 6d78653fc7..7a60a5c042 100644 --- a/httpie/plugins/manager.py +++ b/httpie/plugins/manager.py @@ -4,9 +4,9 @@ from itertools import groupby from operator import attrgetter -from typing import Dict, List, Type, Iterator, TypeVar, Optional, ContextManager +from typing import Dict, List, Type, Iterator, Optional, ContextManager from pathlib import Path -from contextlib import contextmanager +from contextlib import contextmanager, nullcontext from ..compat import importlib_metadata, find_entry_points, get_dist_name @@ -34,15 +34,6 @@ def _load_directory(plugins_dir: Path) -> Iterator[None]: sys.path.remove(plugins_path) -T = TypeVar("T") - - -@contextmanager -def nullcontext(obj: Optional[T] = None) -> Iterator[Optional[T]]: - # A naive replacement of the nullcontext() for 3.6 - yield obj - - def enable_plugins(plugins_dir: Optional[Path]) -> ContextManager[None]: if plugins_dir is None: return nullcontext() diff --git a/setup.py b/setup.py index acec43b3b2..5316ff73d3 100644 --- a/setup.py +++ b/setup.py @@ -84,7 +84,7 @@ def long_description(): 'httpie = httpie.manager.__main__:main', ], }, - python_requires='>=3.6', + python_requires='>=3.7', extras_require=extras_require, install_requires=install_requires, classifiers=[ From d2d40eb3360f0fe1d871466aa4aadd85c618da12 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 21 Jan 2022 18:24:07 +0100 Subject: [PATCH 0976/1182] Finish docs for v3.0.0 (#1269) * WIP * Rewrite the introduction segment of the Nested JSON Co-authored-by: Batuhan Taskaya --- CHANGELOG.md | 6 +- docs/README.md | 178 ++++++++++++++++++++----------------------------- 2 files changed, 77 insertions(+), 107 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d69956cb03..435b5723ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [3.0.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) -- Drop support for Python 3.6. ([#1177](https://github.com/httpie/httpie/issues/1177)) +- Dropped support for Python 3.6. ([#1177](https://github.com/httpie/httpie/issues/1177)) - Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) - Added support for nested JSON syntax. ([#1169](https://github.com/httpie/httpie/issues/1169)) - Added `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/httpie/issues/566)) @@ -15,12 +15,12 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for _receiving_ multiple HTTP headers lines with the same name. ([#1207](https://github.com/httpie/httpie/issues/1207)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) - Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376)) -- Added support for displaying the total elapsed time throguh `--meta`/`-vv` or `--print=m`. ([#243](https://github.com/httpie/httpie/issues/243)) +- Added support for displaying the total elapsed time through `--meta`/`-vv` or `--print=m`. ([#243](https://github.com/httpie/httpie/issues/243)) - Added new `pie-dark`/`pie-light` (and `pie`) styles that match with [HTTPie for Web and Desktop](https://httpie.io/product). ([#1237](https://github.com/httpie/httpie/issues/1237)) - Added support for better error handling on DNS failures. ([#1248](https://github.com/httpie/httpie/issues/1248)) - Added support for storing prompted passwords in the local sessions. ([#1098](https://github.com/httpie/httpie/issues/1098)) - Added warnings about the `--ignore-stdin`, when there is no incoming data from stdin. ([#1255](https://github.com/httpie/httpie/issues/1255)) -- Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) +- Fixed crashing due to broken plugins. ([#1204](https://github.com/httpie/httpie/issues/1204)) - Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156)) - Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/httpie/issues/1242)) - Fixed an unexpected crash when `--raw` is used with `--chunked`. ([#1253](https://github.com/httpie/httpie/issues/1253)) diff --git a/docs/README.md b/docs/README.md index 0c1cd9463f..063ebd4b11 100644 --- a/docs/README.md +++ b/docs/README.md @@ -598,7 +598,7 @@ Content-Type: application/json ## JSON -JSON is the *lingua franca* of modern web services and it is also the **implicit content type** HTTPie uses by default. +JSON is the *lingua franca* of modern web services, and it is also the **implicit content type** HTTPie uses by default. Simple example: @@ -624,7 +624,7 @@ Host: pie.dev If your command includes some data [request items](#request-items), they are serialized as a JSON object by default. HTTPie also automatically sets the following headers, both of which can be overwritten: | Header | Value | -| -------------: | ----------------------------- | +|---------------:|-------------------------------| | `Content-Type` | `application/json` | | `Accept` | `application/json, */*;q=0.5` | @@ -677,132 +677,106 @@ The `:=`/`:=@` syntax is JSON-specific. You can switch your request to `--form` and string, float, and number values will continue to be serialized (as string form values). Other JSON types, however, are not allowed with `--form` or `--multipart`. -### Nested JSON fields +### Nested JSON -In the past (pre-3.0), HTTPie's data operators (`=`/`:=`) allowed you to -directly create basic JSON objects right from your terminal. Though this -functionality was limited to only top-level keys. - -```bash -$ http --offline --print=B pie.dev/post \ - type=success -``` - -```json -{ - "type": "success" -} -``` - -For embedding more complex JSON objects, you needed to use the `:=` operator. - -```bash -$ http --offline --print=B pie.dev/post \ - type=success \ - 'product:={"name":"something", "price":10}' -``` - -```json -{ - "product": { - "name": "something", - "price": 10 - }, - "type": "success" -} -``` - -Starting with 3.0, we have created a mini language in HTTPie's own syntax to -build complex JSON objects with ease. This syntax was inspired by the [JSON form](https://www.w3.org/TR/html-json-forms/) -proposal for HTML, though we have changed a lot of parts to offer the best experience. +If your use case involves sending complex JSON objects as part of the request body, +HTTPie can help you build them right from your terminal. You still use the existing +data field operators (`=`/`:=`) but instead of specifying a top-level field name (like `key=value`), you specify a path declaration. This tells HTTPie where and how to put the given value inside of an object. #### Introduction -Let's start with a simple introduction, and build the JSON object we have seen in the example -above: +Let's start with a simple example, and build a simple search query: ```bash $ http --offline --print=B pie.dev/post \ - type=success \ - product[name]=something \ - product[price]:=10 + category=tools \ + search[type]=id \ + search[id]:=1 ``` -With the new syntax, you can designate the path for the value. For example `product[name]` means -create a new object under the `product` key, and set the `name` field of that object to the given -value. +In the example above, the `search[type]` is an instruction for creating an object called `search`, and setting the `type` field of it to the given value (`"id"`). + +Also note that, just as the regular syntax, you can use the `:=` operator to directly pass raw JSON values (e.g numbers in the case above). ```json { - "product": { - "name": "something", - "price": 10 - }, - "type": "success" + "category": "tools", + "search": { + "id": 1, + "type": "id" + } } ``` -You can also build arrays, through `[]` suffix. Which means create a list, and append the value -to that list: +Building arrays is also possible, through `[]` suffix (an append operation). This tells HTTPie to create an array in the given path (if there is not one already), and append the given value to that array. ```bash $ http --offline --print=B pie.dev/post \ - search[keywords][]=soda \ - search[keywords][]=fries + category=tools \ + search[type]=keyword \ + search[keywords][]=APIs \ + search[keywords][]=CLI ``` ```json { + "category": "tools", "search": { "keywords": [ - "soda", - "fries" - ] + "APIs", + "CLI" + ], + "type": "keyword" } } ``` -If you want to specify the direct index, that is also supported: +If you want to explicitly specify the position of elements inside an array, +you can simply pass the desired index as the path: ```bash $ http --offline --print=B pie.dev/post \ - search[keywords][0]=soda \ - search[keywords][1]=fries + category=tools \ + search[type]=keyword \ + search[keywords][1]=APIs \ + search[keywords][2]=CLI ``` ```json { + "category": "tools", "search": { "keywords": [ - "soda", - "fries" - ] + "CLIs", + "API" + ], + "type": "keyword" } } ``` -You can also create 'sparse arrays' (arrays where you set 2 non-consecutive indexes), which -the missing values gets nullified: +If there are any missing indexes, HTTPie will nullify them in order to create a concrete object that can be sent: ```bash $ http --offline --print=B pie.dev/post \ - search[keywords][2]=soda \ - search[keywords][5]=fries \ - search[keywords][]=fish + category=tools \ + search[type]=platforms \ + search[platforms][]=Terminal \ + search[platforms][1]=Desktop \ + search[platforms][3]=Mobile ``` ```json { + "category": "tools", "search": { - "keywords": [ - null, - null, - "soda", + "platforms": [ + "Terminal", + "Desktop", null, - null, - "fries", - "fish" - ] + "Mobile" + ], + "type": "platforms" } } ``` @@ -811,27 +785,29 @@ It is also possible to embed raw JSON to a nested structure, for example: ```bash $ http --offline --print=B pie.dev/post \ - invitation[type]=meetup \ - 'invitation[dates]:=[2021, 2022, 2023, 2024]' \ - invitation[dates][]:=2025 + category=tools \ + search[type]=platforms \ + 'search[platforms]:=["Terminal", "Desktop"]' \ + search[platforms][]=Web \ + search[platforms][]=Mobile ``` ```json { - "invitation": { - "dates": [ - 2021, - 2022, - 2023, - 2024, - 2025 + "category": "tools", + "search": { + "platforms": [ + "Terminal", + "Desktop", + "Web", + "Mobile" ], - "type": "meetup" + "type": "platforms" } } ``` -And for the last, let's create a very deeply nested JSON object: +And just to demonstrate all of these features together, let's create a very deeply nested JSON object: ```bash $ http PUT pie.dev/put \ @@ -843,11 +819,11 @@ $ http PUT pie.dev/put \ very[nested][json][3][httpie][power][]=Amaze # Nested object ``` -#### Advanced Usage +#### Advanced usage -##### Escaping Behavior +##### Escaping behavior -Nested JSON syntax uses the same escaping rules [escaping rules](escaping-rules) as +Nested JSON syntax uses the same [escaping rules](#escaping-rules) as the terminal. There are 3 special characters, and 1 special token that you can escape. If you want to send a bracket as is, escape it with a backslash (`\`): @@ -907,7 +883,7 @@ $ http --offline --print=B pie.dev/post \ } ``` -##### Guiding Syntax Errors +##### Guiding syntax errors If you make a typo or forget to close a bracket, the errors will guide you to fix it. For example: @@ -925,7 +901,7 @@ foo[baz][quux You can follow to given instruction (adding a `]`) and repair your expression. -##### Type Safety +##### Type safety Each container path (e.g `x[y][z]` in `x[y][z][1]`) has a certain type, which gets defined with the first usage and can't be changed after that. If you try to do a key-based access to an array or @@ -959,18 +935,12 @@ $ http --offline --print=B pie.dev/post \ ### Raw JSON -Please note that on some very complex JSON structures, manually building the JSON object right from the terminal -might be more complicated compared to typing it on a file and directly sending it through HTTPie. Depending on your -use case, some of the following examples can help: +For very complex JSON structures, it may be more convenient to [pass it as raw request body](#raw-request-body), for example: ```bash $ echo -n '{"hello": "world"}' | http POST pie.dev/post ``` -```bash -$ http --raw '{"hello": "world"}' POST pie.dev/post -``` - ```bash $ http POST pie.dev/post < files/data.json ``` @@ -1253,7 +1223,7 @@ the [sessions](#sessions) feature. The currently supported authentication schemes are Basic and Digest (see [auth plugins](#auth-plugins) for more). There are two flags that control authentication: | Flag | Arguments | -| ----------------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|------------------:|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `--auth, -a` | Pass either a `username:password` pair or a `token` as the argument. If the selected authenticated method requires username/password combination and if you only specify a username (`-a username`), you’ll be prompted for the password before the request is sent. To send an empty password, pass `username:`. The `username:password@hostname` URL syntax is supported as well (but credentials passed via `-a` have higher priority) | | `--auth-type, -A` | Specify the auth mechanism. Possible values are `basic`, `digest`, `bearer` or the name of any [auth plugins](#auth-plugins) you have installed. The default value is `basic` so it can often be omitted | @@ -1592,7 +1562,7 @@ The response headers are downloaded always, even if they are not part of the out In addition to crafting structured [JSON](#json) and [forms](#forms) requests with the [request items](#request-items) syntax, you can provide a raw request body that will be sent without further processing. These two approaches for specifying request data (i.e., structured and raw) cannot be combined. -There’re three methods for passing raw request data: piping via `stdin`, +There are three methods for passing raw request data: piping via `stdin`, `--raw='data'`, and `@/file/path`. ### Redirected Input From 88140422a9d6585a7edfb2c265ebed5d0736df2c Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 21 Jan 2022 20:34:38 +0300 Subject: [PATCH 0977/1182] 3.0 release prep (#1272) --- CHANGELOG.md | 2 +- docs/README.md | 2 +- httpie/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 435b5723ab..c6219c8fa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). -## [3.0.0.dev0](https://github.com/httpie/httpie/compare/2.6.0...master) (unreleased) +## [3.0.0](https://github.com/httpie/httpie/compare/2.6.0...3.0.0) (2022-01-21) - Dropped support for Python 3.6. ([#1177](https://github.com/httpie/httpie/issues/1177)) - Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) diff --git a/docs/README.md b/docs/README.md index 063ebd4b11..2b2cf0dc78 100644 --- a/docs/README.md +++ b/docs/README.md @@ -260,7 +260,7 @@ Verify that now you have the [current development version identifier](https://gi ```bash $ http --version -# 2.7.0.dev0 +# 3.0.0 ``` ## Usage diff --git a/httpie/__init__.py b/httpie/__init__.py index 0fdea0c474..b3ad043ed3 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '3.0.0.dev0' +__version__ = '3.0.0' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From c97fe64a37107986f3a11bd482a879bfb918eef7 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 21 Jan 2022 21:08:33 +0300 Subject: [PATCH 0978/1182] Update brew with 3.0 (#1273) --- docs/packaging/brew/httpie.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/packaging/brew/httpie.rb b/docs/packaging/brew/httpie.rb index 382460dcdd..0bda8972e2 100644 --- a/docs/packaging/brew/httpie.rb +++ b/docs/packaging/brew/httpie.rb @@ -3,8 +3,8 @@ class Httpie < Formula desc "User-friendly cURL replacement (command-line HTTP client)" homepage "https://httpie.io/" - url "https://files.pythonhosted.org/packages/53/96/cbcfec73c186f076e4443faf3d91cbbc868f18f6323703afd348b1aba46d/httpie-2.6.0.tar.gz" - sha256 "ef929317b239bbf0a5bb7159b4c5d2edbfc55f8a0bcf9cd24ce597daec2afca5" + url "https://files.pythonhosted.org/packages/64/ee/7b158899655231322f13ecd313d1a0546efe8b9e75167ec8b7fd9ddf7952/httpie-3.0.0.tar.gz" + sha256 "e719711aadf1ecd33278033b96dfef7f4e9e341d3a5d1f166785ac4b7fbdee29" license "BSD-3-Clause" head "https://github.com/httpie/httpie.git", branch: "master" From a88e44c28460e7c51cec0b0fcc50c027f1fca974 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 21 Jan 2022 19:48:35 +0100 Subject: [PATCH 0979/1182] Fix `make brew-test` `brew test` is only usable for non-from-source installations. --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ed9ea9b982..0e5c1a1217 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,8 @@ brew-test: - brew install --build-from-source ./docs/packaging/brew/httpie.rb @echo $(H1)Verifying…$(H1END) - brew test httpie + http --version + https --version @echo $(H1)Auditing…$(H1END) brew audit --strict httpie From b3f29c8d1eade64d49055ed9d9ed15dfdb42e90d Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 21 Jan 2022 22:15:55 +0300 Subject: [PATCH 0980/1182] Display the latest docs (#1274) --- docs/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.json b/docs/config.json index 4012933dcf..4375a5a5e7 100644 --- a/docs/config.json +++ b/docs/config.json @@ -1,5 +1,5 @@ { "website": { - "master_and_released_docs_differ_after": "d40f06687f8cbbd22bf7dba05bee93aea11a169f" + "master_and_released_docs_differ_after": null } } From 8a03b7a824a5f1e2e600bc63f1e6cb4a5d358922 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Sun, 23 Jan 2022 04:25:00 +0300 Subject: [PATCH 0981/1182] Update the contributors (#1275) --- docs/contributors/people.json | 337 ++++++++++++++++++++++++++++++++-- 1 file changed, 319 insertions(+), 18 deletions(-) diff --git a/docs/contributors/people.json b/docs/contributors/people.json index aeea1906e9..041e67f2f7 100644 --- a/docs/contributors/people.json +++ b/docs/contributors/people.json @@ -1,19 +1,45 @@ { + "Aaron Miller": { + "committed": [], + "github": "aaronhmiller", + "reported": [ + "3.0.0" + ], + "twitter": "aaronmiller8" + }, + "Alexander Bogdanov": { + "committed": [], + "github": "ab-kily", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "Almad": { "committed": [ "2.5.0" ], "github": "Almad", "reported": [ - "2.6.0" + "2.6.0", + "3.0.0" ], "twitter": "almadcz" }, + "Andr\u00e1s Czig\u00e1ny": { + "committed": [], + "github": "andrascz", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "Annette Wilson": { "committed": [], "github": "annettejanewilson", "reported": [ - "2.6.0" + "2.6.0", + "3.0.0" ], "twitter": null }, @@ -25,6 +51,32 @@ "reported": [], "twitter": null }, + "Batuhan Taskaya": { + "committed": [ + "3.0.0" + ], + "github": "isidentical", + "reported": [ + "3.0.0" + ], + "twitter": "isidentical" + }, + "Brad Crittenden": { + "committed": [], + "github": "bac", + "reported": [ + "3.0.0" + ], + "twitter": null + }, + "Chad": { + "committed": [], + "github": "cythrawll", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "D8ger": { "committed": [], "github": "caofanCPU", @@ -35,7 +87,8 @@ }, "Dave": { "committed": [ - "2.6.0" + "2.6.0", + "3.0.0" ], "github": "davecheney", "reported": [], @@ -49,6 +102,14 @@ ], "twitter": "DawidFerenczy" }, + "Ed Rooth": { + "committed": [], + "github": "sym3tri", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "Elena Lape": { "committed": [ "2.5.0" @@ -61,7 +122,8 @@ "committed": [], "github": "peruzzof", "reported": [ - "2.6.0" + "2.6.0", + "3.0.0" ], "twitter": null }, @@ -73,6 +135,22 @@ ], "twitter": null }, + "Gabriel Cruz": { + "committed": [], + "github": "gmelodie", + "reported": [ + "3.0.0" + ], + "twitter": "gmelodiecruz" + }, + "Gaurav": { + "committed": [ + "3.0.0" + ], + "github": "gkcs", + "reported": [], + "twitter": null + }, "Giampaolo Rodola": { "committed": [], "github": "giampaolo", @@ -81,6 +159,14 @@ ], "twitter": null }, + "Greg Myers": { + "committed": [ + "3.0.0" + ], + "github": "myersg86", + "reported": [], + "twitter": null + }, "Hugh Williams": { "committed": [], "github": "hughpv", @@ -102,21 +188,33 @@ "Jakub Roztocil": { "committed": [ "2.5.0", - "2.6.0" + "2.6.0", + "3.0.0" ], "github": "jakubroztocil", "reported": [ "2.5.0", - "2.6.0" + "2.6.0", + "3.0.0" ], "twitter": "jakubroztocil" }, + "Jan Bra\u0161na": { + "committed": [ + "3.0.0" + ], + "github": "janbrasna", + "reported": [], + "twitter": "janbrasna" + }, "Jan Verbeek": { "committed": [ "2.5.0" ], "github": "blyxxyz", - "reported": [], + "reported": [ + "3.0.0" + ], "twitter": null }, "Jannik Vieten": { @@ -127,6 +225,22 @@ "reported": [], "twitter": null }, + "Jesper Holmberg": { + "committed": [], + "github": "strindberg", + "reported": [ + "3.0.0" + ], + "twitter": null + }, + "Kirill Krasnov": { + "committed": [], + "github": "Kirill", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "Marcel St\u00f6r": { "committed": [ "2.5.0" @@ -135,6 +249,14 @@ "reported": [], "twitter": "frightanic" }, + "Marco Seguri": { + "committed": [], + "github": "seguri", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "Mariano Ruiz": { "committed": [], "github": "mrsarm", @@ -143,22 +265,41 @@ ], "twitter": "mrsarm82" }, + "Mark Rosenbaum": { + "committed": [], + "github": "markrosenbaum", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "Micka\u00ebl Schoentgen": { "committed": [ "2.5.0", - "2.6.0" + "2.6.0", + "3.0.0" ], "github": "BoboTiG", "reported": [ "2.5.0", - "2.6.0" + "2.6.0", + "3.0.0" ], "twitter": "__tiger222__" }, + "Mike DePalatis": { + "committed": [], + "github": "mivade", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "Miro Hron\u010dok": { "committed": [ "2.5.0", - "2.6.0" + "2.6.0", + "3.0.0" ], "github": "hroncok", "reported": [], @@ -172,16 +313,42 @@ ], "twitter": null }, + "Nanashi.": { + "committed": [], + "github": "sevenc-nanashi", + "reported": [ + "3.0.0" + ], + "twitter": "sevenc_nanashi" + }, "Omer Akram": { "committed": [ - "2.6.0" + "2.6.0", + "3.0.0" ], "github": "om26er", "reported": [ - "2.6.0" + "2.6.0", + "3.0.0" ], "twitter": "om26er" }, + "Patrick Taylor": { + "committed": [], + "github": "pmeister", + "reported": [ + "3.0.0" + ], + "twitter": null + }, + "Paul Laffitte": { + "committed": [], + "github": "paullaffitte", + "reported": [ + "3.0.0" + ], + "twitter": "plaffitt" + }, "Pavel Alexeev aka Pahan-Hubbitus": { "committed": [], "github": "Hubbitus", @@ -190,6 +357,14 @@ ], "twitter": null }, + "Russell Shurts": { + "committed": [], + "github": "rshurts", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "Samuel Marks": { "committed": [], "github": "SamuelMarks", @@ -198,6 +373,14 @@ ], "twitter": null }, + "Sebastian Czech": { + "committed": [ + "3.0.0" + ], + "github": "sebastianczech", + "reported": [], + "twitter": "sebaczech" + }, "Sullivan SENECHAL": { "committed": [], "github": "soullivaneuh", @@ -218,7 +401,32 @@ "committed": [], "github": "vovtz", "reported": [ - "2.6.0" + "2.6.0", + "3.0.0" + ], + "twitter": null + }, + "Vivaan Verma": { + "committed": [ + "3.0.0" + ], + "github": "doublevcodes", + "reported": [], + "twitter": "doublevcodes" + }, + "Vladimir Berkutov": { + "committed": [ + "3.0.0" + ], + "github": "dair-targ", + "reported": [], + "twitter": null + }, + "Will Rogers": { + "committed": [], + "github": "wjrogers", + "reported": [ + "3.0.0" ], "twitter": null }, @@ -238,6 +446,14 @@ "reported": [], "twitter": null }, + "arloan": { + "committed": [], + "github": "arloan", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "bl-ue": { "committed": [ "2.5.0" @@ -246,22 +462,48 @@ "reported": [], "twitter": null }, + "blueray453": { + "committed": [], + "github": "blueray453", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "claudiatd": { "committed": [ - "2.6.0" + "2.6.0", + "3.0.0" ], "github": "claudiatd", "reported": [], "twitter": null }, + "coldcoff": { + "committed": [], + "github": "coldcoff", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "dkreeft": { "committed": [ - "2.6.0" + "2.6.0", + "3.0.0" ], "github": "dkreeft", "reported": [], "twitter": null }, + "greg": { + "committed": [ + "3.0.0" + ], + "github": "gregkh", + "reported": [], + "twitter": null + }, "henryhu712": { "committed": [ "2.5.0" @@ -270,14 +512,31 @@ "reported": [], "twitter": null }, + "hosseingt": { + "committed": [ + "3.0.0" + ], + "github": "hosseingt", + "reported": [], + "twitter": null + }, "jakubroztocil": { "committed": [ - "2.6.0" + "2.6.0", + "3.0.0" ], "github": "jkbr", "reported": [], "twitter": null }, + "josephworks": { + "committed": [], + "github": "josephworks", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "jungle-boogie": { "committed": [], "github": "jungle-boogie", @@ -286,6 +545,14 @@ ], "twitter": null }, + "luisuimi": { + "committed": [], + "github": "luisuimi", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "nixbytes": { "committed": [ "2.5.0" @@ -294,6 +561,14 @@ "reported": [], "twitter": "linuxbyte3" }, + "peterpt": { + "committed": [], + "github": "peterpt", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "qiulang": { "committed": [], "github": "qiulang", @@ -302,6 +577,30 @@ ], "twitter": null }, + "stonebig": { + "committed": [], + "github": "stonebig", + "reported": [ + "3.0.0" + ], + "twitter": null + }, + "whodidthis": { + "committed": [], + "github": "whodidthis", + "reported": [ + "3.0.0" + ], + "twitter": null + }, + "zoulja": { + "committed": [], + "github": "zoulja", + "reported": [ + "3.0.0" + ], + "twitter": null + }, "zwx00": { "committed": [], "github": "zwx00", @@ -314,7 +613,8 @@ "committed": [], "github": "rogerdehe", "reported": [ - "2.6.0" + "2.6.0", + "3.0.0" ], "twitter": null }, @@ -322,7 +622,8 @@ "committed": [], "github": "hh-in-zhuzhou", "reported": [ - "2.6.0" + "2.6.0", + "3.0.0" ], "twitter": null } From c815e21ef932e06eb0046136851c162f6bb0789e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jan 2022 13:52:38 +0100 Subject: [PATCH 0982/1182] Fix time elapsed (#1277) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Show the actual time elapsed; add docs * `requests.Response._headers_parsed_at` → `requests.Response._httpie_headers_parsed_at` * Add `ELAPSED_TIME_LABEL` constant * Tweak docs * Tweak docs * Allow multiple blank lines in Markdown files * Add rudimentary tests for --meta with different --style’s * Cleanup tests * Cleanup tests * Cleanup tests --- docs/README.md | 99 +++++++++++++++------------ docs/markdownlint.rb | 3 + httpie/client.py | 3 +- httpie/models.py | 13 +++- httpie/output/formatters/colors.py | 1 + httpie/output/lexers/metadata.py | 4 +- httpie/output/ui/palette.py | 14 ++-- tests/test_meta.py | 20 ++++-- tests/test_output.py | 4 +- tests/utils/matching/test_matching.py | 5 +- 10 files changed, 105 insertions(+), 61 deletions(-) diff --git a/docs/README.md b/docs/README.md index 2b2cf0dc78..a54b30feb4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -538,7 +538,7 @@ and URL parameters. This is a very practical way of constructing HTTP requests from scratch on the CLI. Each *request item* is simply a key/value pair separated with the following -characters: `:` (headers), `=` (data field, e.g JSON, Form), `:=` (raw data field) +characters: `:` (headers), `=` (data field, e.g., JSON, form), `:=` (raw data field) `==` (query parameters), `@` (file upload). ```bash @@ -550,9 +550,9 @@ $ http PUT pie.dev/put \ ``` | Item Type | Description | -| -----------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-------------------------------------------------------------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | HTTP Headers `Name:Value` | Arbitrary HTTP header, e.g. `X-API-Token:123` | -| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. | +| URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. | | Data Fields `field=value` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) | | Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:=[1,2,3]` (note the quotes) | | File upload fields `field@/dir/file`, `field@file;type=mime` | Only available with `--form`, `-f` and `--multipart`. For example `screenshot@~/Pictures/img.png`, or `'cv@cv.txt;type=text/markdown'`. With `--form`, the presence of a file field results in a `--multipart` request | @@ -570,7 +570,7 @@ to pass the desired value from a file. $ http POST pie.dev/post \ X-Data:@files/text.txt # Read a header from a file token==@files/text.txt # Read a query parameter from a file - name=@files/text.txt # Read a data field's value from a file + name=@files/text.txt # Read a data field’s value from a file bookmarks:=@files/data.json # Embed a JSON object from a file ``` @@ -681,11 +681,11 @@ Other JSON types, however, are not allowed with `--form` or `--multipart`. If your use case involves sending complex JSON objects as part of the request body, HTTPie can help you build them right from your terminal. You still use the existing -data field operators (`=`/`:=`) but instead of specifying a top-level field name (like `key=value`), you specify a path declaration. This tells HTTPie where and how to put the given value inside of an object. +data field operators (`=`/`:=`) but instead of specifying a top-level field name (like `key=value`), you specify a path declaration. This tells HTTPie where and how to put the given value inside an object. #### Introduction -Let's start with a simple example, and build a simple search query: +Let’s start with a simple example, and build a simple search query: ```bash $ http --offline --print=B pie.dev/post \ @@ -696,7 +696,7 @@ $ http --offline --print=B pie.dev/post \ In the example above, the `search[type]` is an instruction for creating an object called `search`, and setting the `type` field of it to the given value (`"id"`). -Also note that, just as the regular syntax, you can use the `:=` operator to directly pass raw JSON values (e.g numbers in the case above). +Also note that, just as the regular syntax, you can use the `:=` operator to directly pass raw JSON values (e.g, numbers in the case above). ```json { @@ -807,7 +807,7 @@ $ http --offline --print=B pie.dev/post \ } ``` -And just to demonstrate all of these features together, let's create a very deeply nested JSON object: +And just to demonstrate all of these features together, let’s create a very deeply nested JSON object: ```bash $ http PUT pie.dev/put \ @@ -845,7 +845,7 @@ $ http --offline --print=B pie.dev/post \ } ``` -If you want the send the literal backslash character (`\`), escape it with another backslash: +If you want to send the literal backslash character (`\`), escape it with another backslash: ```bash $ http --offline --print=B pie.dev/post \ @@ -903,8 +903,8 @@ You can follow to given instruction (adding a `]`) and repair your expression. ##### Type safety -Each container path (e.g `x[y][z]` in `x[y][z][1]`) has a certain type, which gets defined with -the first usage and can't be changed after that. If you try to do a key-based access to an array or +Each container path (e.g., `x[y][z]` in `x[y][z][1]`) has a certain type, which gets defined with +the first usage and can’t be changed after that. If you try to do a key-based access to an array or an index-based access to an object, HTTPie will error out: ```bash @@ -1010,7 +1010,7 @@ world File uploads are always streamed to avoid memory issues with large files. -By default, HTTPie uses a random unique string as the multipart boundary but you can use `--boundary` to specify a custom string instead: +By default, HTTPie uses a random unique string as the multipart boundary, but you can use `--boundary` to specify a custom string instead: ```bash $ http --form --multipart --boundary=xoxo --offline example.org hello=world @@ -1104,7 +1104,7 @@ To send a header with an empty value, use `Header;`, with a semicolon: $ http pie.dev/headers 'Header;' ``` -Please note that some internal headers, such as `Content-Length`, can't be unset if +Please note that some internal headers, such as `Content-Length`, can’t be unset if they are automatically added by the client itself. ### Multiple header values with the same name @@ -1174,7 +1174,7 @@ $ nc pie.dev 80 < request.http You can also use the `--offline` mode for debugging and exploring HTTP and HTTPie, and for “dry runs”. -`--offline` has the side-effect of automatically activating `--print=HB`, i.e., both the request headers and the body +`--offline` has the side effect of automatically activating `--print=HB`, i.e., both the request headers and the body are printed. You can customize the output with the usual [output options](#output-options), with the exception where there is no response to be printed. You can use `--offline` in combination with all the other options (e.g. `--session`). @@ -1438,15 +1438,15 @@ By default, HTTPie only outputs the final response and the whole response message is printed (headers as well as the body). You can control what should be printed via several options: -| Option | What is printed | -| -------------------------: | -------------------------------------------------------------------------------------------------- | -| `--headers, -h` | Only the response headers are printed | -| `--body, -b` | Only the response body is printed | -| `--meta, -m` | Only the response metadata is printed (various metrics like total elapsed time) | -| `--verbose, -v` | Print the whole HTTP exchange (request and response). This option also enables `--all` (see below) | +| Option | What is printed | +|---------------------------:|----------------------------------------------------------------------------------------------------| +| `--headers, -h` | Only the response headers are printed | +| `--body, -b` | Only the response body is printed | +| `--meta, -m` | Only the response metadata is printed (various metrics like total elapsed time) | +| `--verbose, -v` | Print the whole HTTP exchange (request and response). This option also enables `--all` (see below) | | `--verbose --verbose, -vv` | Just like `-v`, but also include the response metadata. | -| `--print, -p` | Selects parts of the HTTP exchange | -| `--quiet, -q` | Don't print anything to `stdout` and `stderr` | +| `--print, -p` | Selects parts of the HTTP exchange | +| `--quiet, -q` | Don’t print anything to `stdout` and `stderr` | ### What parts of the HTTP exchange should be printed @@ -1454,7 +1454,7 @@ All the other [output options](#output-options) are under the hood just shortcut It accepts a string of characters each of which represents a specific part of the HTTP exchange: | Character | Stands for | -| --------: | ---------------- | +|----------:|------------------| | `H` | request headers | | `B` | request body | | `h` | response headers | @@ -1467,6 +1467,15 @@ Print request and response headers: $ http --print=Hh PUT pie.dev/put hello=world ``` +#### Response meta + +The response metadata section currently includes the total time elapsed. It’s the number of seconds between opening the network connection and downloading the last byte of response the body. + +Please note that it also includes time spent on formatting the output, which adds a small penalty. Also, if the body is not part of the output, we don’t spend time downloading it — please see [conditional body download](#conditional-body-download). + +If you [use `--style` with one of the Pie themes](#colors-and-formatting), you’ll see the time information color-coded (green/orange/red) based on how long the exchange took. + + ### Verbose output `--verbose` can often be useful for debugging the request and generating documentation examples: @@ -1628,7 +1637,7 @@ On macOS, you can send the contents of the clipboard with `pbpaste`: $ pbpaste | http PUT pie.dev/put ``` -Passing data through `stdin` **can't** be combined with data fields specified on the command line: +Passing data through `stdin` **can’t** be combined with data fields specified on the command line: ```bash $ echo -n 'data' | http POST example.org more=data # This is invalid @@ -1711,21 +1720,21 @@ Syntax highlighting is applied to HTTP headers and bodies (where it makes sense) You can choose your preferred color scheme via the `--style` option if you don’t like the default one. There are dozens of styles available, here are just a few notable ones: -| Style | Description | -| ---------: | ------------------------------------------------------------------------------------------------------------------------------------ | -| `auto` | Follows your terminal ANSI color styles. This is the default style used by HTTPie | -| `default` | Default styles of the underlying Pygments library. Not actually used by default by HTTPie. You can enable it with `--style=default` | -| `pie-dark` | HTTPie’s original brand style. Also used in [HTTPie for Web and Desktop](https://httpie.io/product). | -|`pie-light` | Like `pie-dark`, but for terminals with light background colors. | -| `pie` | A generic version of `pie-dark` and `pie-light` themes that can work with any terminal background. Its universality requires compromises in terms of legibility, but it’s useful if you frequently switch your terminal between dark and light backgrounds. | -| `monokai` | A popular color scheme. Enable with `--style=monokai` | -| `fruity` | A bold, colorful scheme. Enable with `--style=fruity` | -| … | See `$ http --help` for all the possible `--style` values | +| Style | Description | +|------------:|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `auto` | Follows your terminal ANSI color styles. This is the default style used by HTTPie | +| `default` | Default styles of the underlying Pygments library. Not actually used by default by HTTPie. You can enable it with `--style=default` | +| `pie-dark` | HTTPie’s original brand style. Also used in [HTTPie for Web and Desktop](https://httpie.io/product). | +| `pie-light` | Like `pie-dark`, but for terminals with light background colors. | +| `pie` | A generic version of `pie-dark` and `pie-light` themes that can work with any terminal background. Its universality requires compromises in terms of legibility, but it’s useful if you frequently switch your terminal between dark and light backgrounds. | +| `monokai` | A popular color scheme. Enable with `--style=monokai` | +| `fruity` | A bold, colorful scheme. Enable with `--style=fruity` | +| … | See `$ http --help` for all the possible `--style` values | Use one of these options to control output processing: | Option | Description | -| ----------------: | ------------------------------------------------------------- | +|------------------:|---------------------------------------------------------------| | `--pretty=all` | Apply both colors and formatting. Default for terminal output | | `--pretty=colors` | Apply colors | | `--pretty=format` | Apply formatting | @@ -1744,7 +1753,7 @@ Formatting has the following effects: to the characters they represent. - XML and XHTML data is indented. -Please note that sometimes there might be changes made by formatters on the actual response body (e.g +Please note that sometimes there might be changes made by formatters on the actual response body (e.g., collapsing empty tags on XML) but the end result will always be semantically indistinguishable. Some of these formatting changes can be configured more granularly through [format options](#format-options). @@ -1754,7 +1763,7 @@ The `--format-options=opt1:value,opt2:value` option allows you to control how th when formatting is applied. The following options are available: | Option | Default value | Shortcuts | -| ---------------: | :-----------: | ------------------------ | +|-----------------:|:-------------:|--------------------------| | `headers.sort` | `true` | `--sorted`, `--unsorted` | | `json.format` | `true` | N/A | | `json.indent` | `4` | N/A | @@ -1903,7 +1912,7 @@ $ http -dco file.zip example.org/file - `--download` always implies `--follow` (redirects are followed). - `--download` also implies `--check-status` (error HTTP status will result in a non-zero exist static code). - HTTPie exits with status code `1` (error) if the body hasn’t been fully downloaded. -- `Accept-Encoding` can't be set with `--download`. +- `Accept-Encoding` can’t be set with `--download`. ## Streamed responses @@ -1982,7 +1991,7 @@ $ http --session=user2 -a user2:password pie.dev/get X-Bar:Foo Named sessions’ data is stored in JSON files inside the `sessions` subdirectory of the [config](#config) directory, typically `~/.config/httpie/sessions//.json` (`%APPDATA%\httpie\sessions\\.json` on Windows). -If you have executed the above commands on a Unix machine, you should be able list the generated sessions files using: +If you have executed the above commands on a Unix machine, you should be able to list the generated sessions files using: ```bash $ ls -l ~/.config/httpie/sessions/pie.dev @@ -2078,7 +2087,7 @@ If the server expires an existing cookie, it will also be removed from the sessi ## Config HTTPie uses a simple `config.json` file. -The file doesn’t exist by default but you can create it manually. +The file doesn’t exist by default, but you can create it manually. ### Config file directory @@ -2120,7 +2129,7 @@ $ cat ~/.config/httpie/config.json ``` Technically, it is possible to include any HTTPie options in there. -However, it is not recommended to modify the default behavior in a way that would break your compatibility with the wider world as that may become confusing. +However, it is not recommended modifying the default behavior in a way that would break your compatibility with the wider world as that may become confusing. #### `plugins_dir` @@ -2185,11 +2194,11 @@ This command is currently in beta. `plugins` interface is a very simple plugin manager for installing, listing and uninstalling HTTPie plugins. -> In the past `pip` was used to install/uninstall plugins, but on some environments (e.g brew installed -packages) it wasn't working properly. The new interface is a very simple overlay on top of `pip` to allow +In the past `pip` was used to install/uninstall plugins, but on some environments (e.g., brew installed +packages) it wasn’t working properly. The new interface is a very simple overlay on top of `pip` to allow plugin installations on every installation method. -> By default the plugins (and their missing dependencies) will be stored under the configuration directory, +By default, the plugins (and their missing dependencies) will be stored under the configuration directory, but this can be modified through `plugins_dir` variable on the config. #### `httpie plugins install` @@ -2232,7 +2241,7 @@ $ httpie plugins upgrade httpie-plugin #### `httpie plugins uninstall` Uninstall plugins from the isolated plugins directory. If the plugin is not installed -through `httpie plugins install`, it won't uninstall it. +through `httpie plugins install`, it won’t uninstall it. ```bash $ httpie plugins uninstall httpie-plugin diff --git a/docs/markdownlint.rb b/docs/markdownlint.rb index c31232d8af..0bf3f87b2b 100644 --- a/docs/markdownlint.rb +++ b/docs/markdownlint.rb @@ -20,6 +20,9 @@ # MD028 Blank line inside blockquote exclude_rule 'MD028' +# MD012 Multiple consecutive blank lines +exclude_rule 'MD012' + # Tell the linter to use ordered lists: # 1. Foo # 2. Bar diff --git a/httpie/client.py b/httpie/client.py index 58575fe63b..c2563cbc3e 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -3,6 +3,7 @@ import json import sys from contextlib import contextmanager +from time import monotonic from typing import Any, Dict, Callable, Iterable from urllib.parse import urlparse, urlunparse @@ -108,7 +109,7 @@ def collect_messages( **send_kwargs_merged, **send_kwargs, ) - + response._httpie_headers_parsed_at = monotonic() expired_cookies += get_expired_cookies( response.headers.get('Set-Cookie', '') ) diff --git a/httpie/models.py b/httpie/models.py index e0fde8e0d4..5faf4ee0c7 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -1,3 +1,5 @@ +from time import monotonic + import requests from enum import Enum, auto @@ -15,6 +17,9 @@ from .utils import split_cookies, parse_content_type_header +ELAPSED_TIME_LABEL = 'Elapsed time' + + class HTTPMessage: """Abstract class for HTTP messages.""" @@ -96,7 +101,13 @@ def headers(self): @property def metadata(self) -> str: data = {} - data['Elapsed time'] = str(self._orig.elapsed.total_seconds()) + 's' + time_to_parse_headers = self._orig.elapsed.total_seconds() + # noinspection PyProtectedMember + time_since_headers_parsed = monotonic() - self._orig._httpie_headers_parsed_at + time_elapsed = time_to_parse_headers + time_since_headers_parsed + # data['Headers time'] = str(round(time_to_parse_headers, 5)) + 's' + # data['Body time'] = str(round(time_since_headers_parsed, 5)) + 's' + data[ELAPSED_TIME_LABEL] = str(round(time_elapsed, 10)) + 's' return '\n'.join( f'{key}: {value}' for key, value in data.items() diff --git a/httpie/output/formatters/colors.py b/httpie/output/formatters/colors.py index 135eb7cd0c..c12c31c3e4 100644 --- a/httpie/output/formatters/colors.py +++ b/httpie/output/formatters/colors.py @@ -383,4 +383,5 @@ def make_styles(): PIE_STYLES = make_styles() +PIE_STYLE_NAMES = list(PIE_STYLES.keys()) BUNDLED_STYLES |= PIE_STYLES.keys() diff --git a/httpie/output/lexers/metadata.py b/httpie/output/lexers/metadata.py index d0216d5eea..fa68e45762 100644 --- a/httpie/output/lexers/metadata.py +++ b/httpie/output/lexers/metadata.py @@ -1,4 +1,6 @@ import pygments + +from httpie.models import ELAPSED_TIME_LABEL from httpie.output.lexers.common import precise SPEED_TOKENS = { @@ -34,7 +36,7 @@ class MetadataLexer(pygments.lexer.RegexLexer): tokens = { 'root': [ ( - r'(Elapsed time)( *)(:)( *)(\d+\.\d+)(s)', pygments.lexer.bygroups( + fr'({ELAPSED_TIME_LABEL})( *)(:)( *)(\d+\.\d+)(s)', pygments.lexer.bygroups( pygments.token.Name.Decorator, # Name pygments.token.Text, pygments.token.Operator, # Colon diff --git a/httpie/output/ui/palette.py b/httpie/output/ui/palette.py index a13aef058c..64bba703be 100644 --- a/httpie/output/ui/palette.py +++ b/httpie/output/ui/palette.py @@ -1,7 +1,12 @@ -# Copy the brand palette from typing import Optional +STYLE_PIE = 'pie' +STYLE_PIE_DARK = 'pie-dark' +STYLE_PIE_LIGHT = 'pie-light' + + COLOR_PALETTE = { + # Copy the brand palette 'transparent': 'transparent', 'current': 'currentColor', 'white': '#F5F5F0', @@ -138,10 +143,11 @@ COLOR_PALETTE['secondary'] = {'700': '#37523C', '600': '#6c6969', '500': '#6c6969'} + SHADE_NAMES = { - '500': 'pie-dark', - '600': 'pie', - '700': 'pie-light' + '500': STYLE_PIE_DARK, + '600': STYLE_PIE, + '700': STYLE_PIE_LIGHT } SHADES = [ diff --git a/tests/test_meta.py b/tests/test_meta.py index f9c1bc270c..a57b510f0d 100644 --- a/tests/test_meta.py +++ b/tests/test_meta.py @@ -1,7 +1,17 @@ -from .utils import http +import pytest +from httpie.models import ELAPSED_TIME_LABEL +from httpie.output.formatters.colors import PIE_STYLE_NAMES +from .utils import http, MockEnvironment, COLOR -def test_meta_elapsed_time(httpbin, monkeypatch): - r = http('--meta', httpbin + '/get') - for line in r.splitlines(): - assert 'Elapsed time' in r + +def test_meta_elapsed_time(httpbin): + r = http('--meta', httpbin + '/delay/1') + assert f'{ELAPSED_TIME_LABEL}: 1.' in r + + +@pytest.mark.parametrize('style', ['auto', 'fruity', *PIE_STYLE_NAMES]) +def test_meta_elapsed_time_colors(httpbin, style): + r = http('--style', style, '--meta', httpbin + '/get', env=MockEnvironment(colors=256)) + assert COLOR in r + assert ELAPSED_TIME_LABEL in r diff --git a/tests/test_output.py b/tests/test_output.py index 4d9587b38b..c68bfa9e38 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -17,7 +17,7 @@ ) from httpie.cli.definition import parser from httpie.encoding import UTF8 -from httpie.output.formatters.colors import PIE_STYLES, get_lexer +from httpie.output.formatters.colors import get_lexer, PIE_STYLE_NAMES from httpie.status import ExitStatus from .fixtures import XML_DATA_RAW, XML_DATA_FORMATTED from .utils import COLOR, CRLF, HTTP_OK, MockEnvironment, http, DUMMY_URL @@ -227,7 +227,7 @@ def test_ensure_contents_colored(httpbin, endpoint): assert COLOR in r -@pytest.mark.parametrize('style', PIE_STYLES.keys()) +@pytest.mark.parametrize('style', PIE_STYLE_NAMES) def test_ensure_meta_is_colored(httpbin, style): env = MockEnvironment(colors=256) r = http('--meta', '--style', style, 'GET', httpbin + '/get', env=env) diff --git a/tests/utils/matching/test_matching.py b/tests/utils/matching/test_matching.py index 2e7735a6d3..60aa1a9423 100644 --- a/tests/utils/matching/test_matching.py +++ b/tests/utils/matching/test_matching.py @@ -2,6 +2,7 @@ Here we test our output parsing and matching implementation, not HTTPie itself. """ +from httpie.models import ELAPSED_TIME_LABEL from httpie.output.writer import MESSAGE_SEPARATOR from ...utils import CRLF from . import assert_output_does_not_match, assert_output_matches, Expect @@ -111,7 +112,7 @@ def test_assert_output_matches_response_meta(): assert_output_matches( ( 'Key: Value\n' - 'Elapsed Time: 3.3s' + f'{ELAPSED_TIME_LABEL}: 3.3s' ), [Expect.RESPONSE_META] ) @@ -124,7 +125,7 @@ def test_assert_output_matches_whole_response(): f'AAA:BBB{CRLF}' f'{CRLF}' f'CCC{MESSAGE_SEPARATOR}' - 'Elapsed Time: 3.3s' + f'{ELAPSED_TIME_LABEL}: 3.3s' ), [Expect.RESPONSE_HEADERS, Expect.BODY, Expect.RESPONSE_META] ) From 3b441fa57e21229ae2be9b871098127547d100de Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jan 2022 13:57:04 +0100 Subject: [PATCH 0983/1182] 3.0.1 --- CHANGELOG.md | 4 ++++ httpie/__init__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6219c8fa9..e3b8e3f22a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). +## [3.0.1](https://github.com/httpie/httpie/compare/3.0.0...3.0.1) (2022-01-23) + +- Changed the value shown as time elapsed from time-to-read-headers to total exchange time ([#1277](https://github.com/httpie/httpie/issues/1277)) + ## [3.0.0](https://github.com/httpie/httpie/compare/2.6.0...3.0.0) (2022-01-21) - Dropped support for Python 3.6. ([#1177](https://github.com/httpie/httpie/issues/1177)) diff --git a/httpie/__init__.py b/httpie/__init__.py index b3ad043ed3..7861602703 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '3.0.0' +__version__ = '3.0.1' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 2797b7244c80452dfa6cba14925e5891f8755157 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jan 2022 14:11:09 +0100 Subject: [PATCH 0984/1182] Update cached brew formula --- docs/packaging/brew/httpie.rb | 38 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/docs/packaging/brew/httpie.rb b/docs/packaging/brew/httpie.rb index 0bda8972e2..ed09cb5309 100644 --- a/docs/packaging/brew/httpie.rb +++ b/docs/packaging/brew/httpie.rb @@ -3,19 +3,18 @@ class Httpie < Formula desc "User-friendly cURL replacement (command-line HTTP client)" homepage "https://httpie.io/" - url "https://files.pythonhosted.org/packages/64/ee/7b158899655231322f13ecd313d1a0546efe8b9e75167ec8b7fd9ddf7952/httpie-3.0.0.tar.gz" - sha256 "e719711aadf1ecd33278033b96dfef7f4e9e341d3a5d1f166785ac4b7fbdee29" + url "https://files.pythonhosted.org/packages/7b/f9/13070f19226b7db3641fb787df36bb715063abe1b8ca03fbaeca0f465d27/httpie-3.0.1.tar.gz" + sha256 "0e9bc93ebdcdd2d32ec24b8fa46cf7e4fde9eec7a6bd0c5d0ef224f25d7466b2" license "BSD-3-Clause" head "https://github.com/httpie/httpie.git", branch: "master" bottle do - sha256 cellar: :any_skip_relocation, arm64_monterey: "83aab05ffbcd4c3baa6de6158d57ebdaa67c148bef8c872527d90bdaebff0504" - sha256 cellar: :any_skip_relocation, arm64_big_sur: "3c3a5c2458d0658e14b663495e115297c573aa3466d292f12d02c3ec13a24bdf" - sha256 cellar: :any_skip_relocation, monterey: "f860e7d3b77dca4928a2c5e10c4cbd50d792330dfb99f7d736ca0da9fb9dd0d0" - sha256 cellar: :any_skip_relocation, big_sur: "377b0643aa1f6d310ba4cfc70d66a94cc458213db8d134940d3b10a32defacf1" - sha256 cellar: :any_skip_relocation, catalina: "6d306c30f6f1d7a551d88415efe12b7c3f25d0602f3579dc632771a463f78fa5" - sha256 cellar: :any_skip_relocation, mojave: "f66b8cdff9cb7b44a84197c3e3d81d810f7ff8f2188998b977ccadfc7e2ec893" - sha256 cellar: :any_skip_relocation, x86_64_linux: "53f036b0114814c28982e8c022dcf494e7024de088641d7076fd73d12a45a0e9" + sha256 cellar: :any_skip_relocation, arm64_monterey: "9d285fcfb55ce8ed787d1b01966d51e6e07f7e77c44a204695a2d6eee9c8698d" + sha256 cellar: :any_skip_relocation, arm64_big_sur: "743a282b475e87a4eaf11e545f761aef1b8e4bfe49eaee47251d7629a35a8ced" + sha256 cellar: :any_skip_relocation, monterey: "5d63ea4f47b2028b2ba68abe12a4176934193e058edd869270221b41cc946c76" + sha256 cellar: :any_skip_relocation, big_sur: "5a53221a680a35d1aa00cbadde279dbe4f562d22ed207c15bd4221cb8c3180f1" + sha256 cellar: :any_skip_relocation, catalina: "5feadb6d76f55d6f9681682e221008c282dccf0e46ae22a959b4bad2efde204a" + sha256 cellar: :any_skip_relocation, x86_64_linux: "d530ddbec49588b0d481f156d35f7e5bb7d3b6427d203f04750e55cd3eecc303" end depends_on "python@3.10" @@ -36,8 +35,13 @@ class Httpie < Formula end resource "idna" do - url "https://files.pythonhosted.org/packages/cb/38/4c4d00ddfa48abe616d7e572e02a04273603db446975ab46bbcd36552005/idna-3.2.tar.gz" - sha256 "467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" + url "https://files.pythonhosted.org/packages/62/08/e3fc7c8161090f742f504f40b1bccbfc544d4a4e09eb774bf40aafce5436/idna-3.3.tar.gz" + sha256 "9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + end + + resource "multidict" do + url "https://files.pythonhosted.org/packages/8e/7c/e12a69795b7b7d5071614af2c691c97fbf16a2a513c66ec52dd7d0a115bb/multidict-5.2.0.tar.gz" + sha256 "0dd1c93edb444b33ba2274b66f63def8a327d607c6c790772f448a53b6ea59ce" end resource "Pygments" do @@ -65,20 +69,14 @@ class Httpie < Formula sha256 "0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c" end - resource "multidict" do - url "https://files.pythonhosted.org/packages/8e/7c/e12a69795b7b7d5071614af2c691c97fbf16a2a513c66ec52dd7d0a115bb/multidict-5.2.0.tar.gz" - sha256 "0dd1c93edb444b33ba2274b66f63def8a327d607c6c790772f448a53b6ea59ce" - end - def install virtualenv_install_with_resources end test do - # shell_output() already checks the status code - shell_output("#{bin}/httpie -v") - shell_output("#{bin}/https -v") - shell_output("#{bin}/http -v") + assert_match version.to_s, shell_output("#{bin}/httpie --version") + assert_match version.to_s, shell_output("#{bin}/https --version") + assert_match version.to_s, shell_output("#{bin}/http --version") raw_url = "https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/httpie.rb" assert_match "PYTHONPATH", shell_output("#{bin}/http --ignore-stdin #{raw_url}") From caa8fb9058e73c8efe41b0da6159d47f5aa0d89f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jan 2022 14:35:20 +0100 Subject: [PATCH 0985/1182] Tweak response meta docs - expand response meta section - add examples - interlink sections --- docs/README.md | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/docs/README.md b/docs/README.md index a54b30feb4..694f7e7a47 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1442,7 +1442,7 @@ be printed via several options: |---------------------------:|----------------------------------------------------------------------------------------------------| | `--headers, -h` | Only the response headers are printed | | `--body, -b` | Only the response body is printed | -| `--meta, -m` | Only the response metadata is printed (various metrics like total elapsed time) | +| `--meta, -m` | Only the [response metadata](#response-meta) is printed | | `--verbose, -v` | Print the whole HTTP exchange (request and response). This option also enables `--all` (see below) | | `--verbose --verbose, -vv` | Just like `-v`, but also include the response metadata. | | `--print, -p` | Selects parts of the HTTP exchange | @@ -1453,13 +1453,13 @@ be printed via several options: All the other [output options](#output-options) are under the hood just shortcuts for the more powerful `--print, -p`. It accepts a string of characters each of which represents a specific part of the HTTP exchange: -| Character | Stands for | -|----------:|------------------| -| `H` | request headers | -| `B` | request body | -| `h` | response headers | -| `b` | response body | -| `m` | response meta | +| Character | Stands for | +|----------:|---------------------------------| +| `H` | request headers | +| `B` | request body | +| `h` | response headers | +| `b` | response body | +| `m` | [response meta](#response-meta) | Print request and response headers: @@ -1471,7 +1471,32 @@ $ http --print=Hh PUT pie.dev/put hello=world The response metadata section currently includes the total time elapsed. It’s the number of seconds between opening the network connection and downloading the last byte of response the body. -Please note that it also includes time spent on formatting the output, which adds a small penalty. Also, if the body is not part of the output, we don’t spend time downloading it — please see [conditional body download](#conditional-body-download). + +To _only_ show the response metadata, use `--meta, -m` (analogically to `--headers, -h` and `--body, -b`): + +```bash +$ http --meta pie.dev/delay/1 +``` + +```console +Elapsed time: 1.099171542s +``` + +The [extra verbose `-vv` output](#extra-verbose-output) includes the meta section by default. You can also show it in combination with other parts of the exchange via [`--print=m`](#what-parts-of-the-http-exchange-should-be-printed). For example, here we print it together with the response headers: + +```bash +$ http --print=hm pie.dev/get +``` + +```http +HTTP/1.1 200 OK +Content-Type: application/json + +Elapsed time: 0.077538375s +``` + + +Please note that it also includes time spent on formatting the output, which adds a small penalty. Also, if the body is not part of the output, [we don’t spend time downloading it](#conditional-body-download). If you [use `--style` with one of the Pie themes](#colors-and-formatting), you’ll see the time information color-coded (green/orange/red) based on how long the exchange took. @@ -1505,9 +1530,9 @@ Server: gunicorn/0.13.4 } ``` -#### Verbosity Level: 2 +#### Extra verbose output -If you run HTTPie with `-vv` or `--verbose --verbose`, then it would also display the response metadata. +If you run HTTPie with `-vv` or `--verbose --verbose`, then it would also display the [response metadata](#response-meta). ```bash # Just like the above, but with additional columns like the total elapsed time From 4e59bbfae647547c81b676bb27d49b28b4443c18 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jan 2022 16:52:31 +0100 Subject: [PATCH 0986/1182] Docs --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 694f7e7a47..03c3a00198 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1498,7 +1498,7 @@ Elapsed time: 0.077538375s Please note that it also includes time spent on formatting the output, which adds a small penalty. Also, if the body is not part of the output, [we don’t spend time downloading it](#conditional-body-download). -If you [use `--style` with one of the Pie themes](#colors-and-formatting), you’ll see the time information color-coded (green/orange/red) based on how long the exchange took. +If you [use `--style` with one of the Pie themes](#colors-and-formatting), you’ll see the time information color-coded (green/yellow/orange/red) based on how long the exchange took. ### Verbose output From 859e4420838b470e694460a9ba8a68962da2e833 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jan 2022 16:59:07 +0100 Subject: [PATCH 0987/1182] Docs --- docs/README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 03c3a00198..de82137c02 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1300,6 +1300,8 @@ Here are a few picks: - [httpie-oauth](https://github.com/httpie/httpie-oauth): OAuth - [requests-hawk](https://github.com/mozilla-services/requests-hawk): Hawk +See [plugin manager](#plugin-manager) for more details. + ## HTTP redirects By default, HTTP redirects are not followed and only the first @@ -2159,7 +2161,7 @@ However, it is not recommended modifying the default behavior in a way that woul #### `plugins_dir` The directory where the plugins will be installed. HTTPie needs to have read/write access on that directory, since -`httpie plugins install` will download new plugins to there. +`httpie plugins install` will download new plugins to there. See [plugin manager](#plugin-manager) for more information. ### Un-setting previously specified options @@ -2200,9 +2202,10 @@ And since there’s neither data nor `EOF`, it will get stuck. So unless you’r Also, it might be good to set a connection `--timeout` limit to prevent your program from hanging if the server never responds. -## Plugins Manager +## Plugin manager -HTTPie offers extensibility through plugins, and there are over 50+ of them available to try! +HTTPie offers extensibility through a [plugin API](https://github.com/httpie/httpie/blob/master/httpie/plugins/base.py), +and there are dozens of plugins available to try! They add things like new authentication methods ([akamai/httpie-edgegrid](https://github.com/akamai/httpie-edgegrid)), transport mechanisms ([httpie/httpie-unixsocket](https://github.com/httpie/httpie-unixsocket)), message convertors ([banteg/httpie-image](https://github.com/banteg/httpie-image)), or simply From 217cf8ddae3615a2a0d96f7842c5feb22e5d9d0f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jan 2022 17:17:58 +0100 Subject: [PATCH 0988/1182] Document auto-stream --- docs/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/README.md b/docs/README.md index de82137c02..9694e62855 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1954,6 +1954,8 @@ You can use the `--stream, -S` flag to make two things happen: 1. The output is flushed in much smaller chunks without any buffering, which makes HTTPie behave kind of like `tail -f` for URLs. 2. Streaming becomes enabled even when the output is prettified: It will be applied to each line of the response and flushed immediately. This makes it possible to have a nice output for long-lived requests, such as one to the [Twitter streaming API](https://developer.twitter.com/en/docs/tutorials/consuming-streaming-data). +The `--stream` option is automatically enabled when the response headers include `Content-Type: text/event-stream`. + ### Example use cases Prettified streamed response: From ba0c1ab25835631a53eaf68969945ddcca0ae588 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jan 2022 17:24:29 +0100 Subject: [PATCH 0989/1182] Tweak auth docs --- docs/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/README.md b/docs/README.md index 9694e62855..d14b3bfe90 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1247,12 +1247,18 @@ https -A bearer -a token pie.dev/bearer ### Password prompt +If you omit the password part of `--auth, -a`, HTTPie securely prompts you for it: + ```bash $ http -a username pie.dev/basic-auth/username/password ``` +Please note that when you use [`--session`](#sessions), prompted passwords are persisted in sessions files . + ### Empty password +To send an empty password without being prompted for it, include a trailing colon in the credentials: + ```bash $ http -a username: pie.dev/headers ``` From 202f59e04a97734d47de16c2f8a8a9ac0278f687 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jan 2022 18:36:18 +0100 Subject: [PATCH 0990/1182] Tweak nested JSON docs --- docs/README.md | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index d14b3bfe90..e9d6c14440 100644 --- a/docs/README.md +++ b/docs/README.md @@ -681,7 +681,40 @@ Other JSON types, however, are not allowed with `--form` or `--multipart`. If your use case involves sending complex JSON objects as part of the request body, HTTPie can help you build them right from your terminal. You still use the existing -data field operators (`=`/`:=`) but instead of specifying a top-level field name (like `key=value`), you specify a path declaration. This tells HTTPie where and how to put the given value inside an object. +data field operators (`=`/`:=`) but instead of specifying a top-level field name (like `key=value`), +you specify a path declaration. This tells HTTPie where and how to put the given value inside an object: + +```bash +http pie.dev/post \ + platform[name]=HTTPie \ + platform[about][mission]='Make APIs simple and intuitive' \ + platform[about][homepage]=httpie.io \ + platform[about][homepage]=httpie.io \ + platform[about][stars]:=54000 \ + platform[apps][]=Terminal \ + platform[apps][]=Desktop \ + platform[apps][]=Web \ + platform[apps][]=Mobile +``` + +```json +{ + "platform": { + "name": "HTTPie", + "about": { + "mission": "Make APIs simple and intuitive", + "homepage": "httpie.io", + "stars": 54000 + }, + "apps": [ + "Terminal", + "Desktop", + "Web", + "Mobile" + ] + } +} +``` #### Introduction From aedcad7e2a8803cd5620d38885650b8032ab6760 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jan 2022 15:14:31 -0800 Subject: [PATCH 0991/1182] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3b8e3f22a..caa27c055a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,14 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [3.0.1](https://github.com/httpie/httpie/compare/3.0.0...3.0.1) (2022-01-23) +[What’s new in HTTPie 3.0 →](https://httpie.io/blog/httpie-3.0.0) + - Changed the value shown as time elapsed from time-to-read-headers to total exchange time ([#1277](https://github.com/httpie/httpie/issues/1277)) ## [3.0.0](https://github.com/httpie/httpie/compare/2.6.0...3.0.0) (2022-01-21) +[What’s new in HTTPie 3.0 →](https://httpie.io/blog/httpie-3.0.0) + - Dropped support for Python 3.6. ([#1177](https://github.com/httpie/httpie/issues/1177)) - Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) - Added support for nested JSON syntax. ([#1169](https://github.com/httpie/httpie/issues/1169)) From 30a4d29f77b946fa5eac4d0a42a955e281c62e54 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 23 Jan 2022 15:15:16 -0800 Subject: [PATCH 0992/1182] Update CHANGELOG.md --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index caa27c055a..58dc677bcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,13 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [3.0.1](https://github.com/httpie/httpie/compare/3.0.0...3.0.1) (2022-01-23) -[What’s new in HTTPie 3.0 →](https://httpie.io/blog/httpie-3.0.0) +[What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) - Changed the value shown as time elapsed from time-to-read-headers to total exchange time ([#1277](https://github.com/httpie/httpie/issues/1277)) ## [3.0.0](https://github.com/httpie/httpie/compare/2.6.0...3.0.0) (2022-01-21) -[What’s new in HTTPie 3.0 →](https://httpie.io/blog/httpie-3.0.0) +[What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) - Dropped support for Python 3.6. ([#1177](https://github.com/httpie/httpie/issues/1177)) - Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) @@ -36,7 +36,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) -[What’s new in HTTPie 2.6.0 →](https://httpie.io/blog/httpie-2.6.0) +[What’s new in HTTPie for Terminal 2.6.0 →](https://httpie.io/blog/httpie-2.6.0) - Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) - Added charset auto-detection when `Content-Type` doesn’t include it. ([#1110](https://github.com/httpie/httpie/issues/1110), [#1168](https://github.com/httpie/httpie/issues/1168)) @@ -48,7 +48,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06) -[What’s new in HTTPie 2.5.0 →](https://httpie.io/blog/httpie-2.5.0) +[What’s new in HTTPie for Terminal 2.5.0 →](https://httpie.io/blog/httpie-2.5.0) - Added `--raw` to allow specifying the raw request body without extra processing as an alternative to `stdin`. ([#534](https://github.com/httpie/httpie/issues/534)) From 700dbeddb002a4bf8b00cd0cceede51d9c29d301 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 24 Jan 2022 01:51:45 +0100 Subject: [PATCH 0993/1182] Typos --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index e9d6c14440..aa6e2e6c64 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1286,7 +1286,7 @@ If you omit the password part of `--auth, -a`, HTTPie securely prompts you for i $ http -a username pie.dev/basic-auth/username/password ``` -Please note that when you use [`--session`](#sessions), prompted passwords are persisted in sessions files . +Please note that when you use [`--session`](#sessions), prompted passwords are persisted in session files. ### Empty password From 212000199e5cf0894401f41d7c63f3d8d07c4609 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:00:54 +0300 Subject: [PATCH 0994/1182] docs: fix the nested json example (#1278) --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index aa6e2e6c64..66bb4d6a9d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -772,7 +772,7 @@ $ http --offline --print=B pie.dev/post \ category=tools \ search[type]=keyword \ search[keywords][1]=APIs \ - search[keywords][2]=CLI + search[keywords][0]=CLI ``` ```json From ec521c461b09714ac0d6ca7a336abecb417ea18b Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:02:42 +0300 Subject: [PATCH 0995/1182] docs: add initial benchmark docs --- extras/profiling/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 extras/profiling/README.md diff --git a/extras/profiling/README.md b/extras/profiling/README.md new file mode 100644 index 0000000000..19e1635afd --- /dev/null +++ b/extras/profiling/README.md @@ -0,0 +1 @@ +# HTTPie Benchmarks From 738a6bea57b56a8340a638c48fdf7ebbba25b353 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:03:08 +0300 Subject: [PATCH 0996/1182] docs: fix the title to `benchmarking infrastructure` --- extras/profiling/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/profiling/README.md b/extras/profiling/README.md index 19e1635afd..103f81cbc2 100644 --- a/extras/profiling/README.md +++ b/extras/profiling/README.md @@ -1 +1 @@ -# HTTPie Benchmarks +# HTTPie Benchmarking Infrastructure From d56a1f216e3bdc8a9f52a4f66bf55ba70073bc3a Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:03:41 +0300 Subject: [PATCH 0997/1182] docs: give a brief description --- extras/profiling/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extras/profiling/README.md b/extras/profiling/README.md index 103f81cbc2..845d78a1e3 100644 --- a/extras/profiling/README.md +++ b/extras/profiling/README.md @@ -1 +1,4 @@ # HTTPie Benchmarking Infrastructure + +This directory includes the benchmarks +we use for testing HTTPie's speed. From 708608e1d419eed545773d9839b31a833577e29f Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:04:30 +0300 Subject: [PATCH 0998/1182] docs: mention about the runners --- extras/profiling/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/extras/profiling/README.md b/extras/profiling/README.md index 845d78a1e3..a8df4c8e6a 100644 --- a/extras/profiling/README.md +++ b/extras/profiling/README.md @@ -1,4 +1,7 @@ # HTTPie Benchmarking Infrastructure -This directory includes the benchmarks -we use for testing HTTPie's speed. +This directory includes the benchmarks we +use for testing HTTPie's speed and the infrastructure +to automate this testing accross versions. + + From 97bd9c2a8913851077d261c1b20376916073b2d6 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:05:49 +0300 Subject: [PATCH 0999/1182] docs: add requirements --- extras/profiling/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/extras/profiling/README.md b/extras/profiling/README.md index a8df4c8e6a..4548c40070 100644 --- a/extras/profiling/README.md +++ b/extras/profiling/README.md @@ -4,4 +4,10 @@ This directory includes the benchmarks we use for testing HTTPie's speed and the infrastructure to automate this testing accross versions. +## Usage + +### Requirements + +- Python 3.7+ +- `pyperf` From 6b5d96da7231102dc0a015255e6405037a1e4aea Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:11:09 +0300 Subject: [PATCH 1000/1182] Describe the usage for benchmarks --- extras/profiling/README.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/extras/profiling/README.md b/extras/profiling/README.md index 4548c40070..4e3c8588eb 100644 --- a/extras/profiling/README.md +++ b/extras/profiling/README.md @@ -6,8 +6,25 @@ to automate this testing accross versions. ## Usage -### Requirements - +Ensure the following requirements are satisfied: - Python 3.7+ - `pyperf` +Then, run the `extras/benchmarks/run.py`: +``` +$ python extras/profiling/run.py +``` + +Without any options, this command will initially create +an isolated environment and install `httpie` from the +latest commit. Then it will create a second environment +with the `master` of the current repository and run the +benchmarks on both of them. It will compare the results +and print it as a markdown table: + +| Benchmark | master | this_branch | +|----------------------------------------|:------:|:--------------------:| +| `http --version` (startup) | 201 ms | 174 ms: 1.16x faster | +| `http --offline pie.dev/get` (startup) | 200 ms | 174 ms: 1.15x faster | +| Geometric mean | (ref) | 1.10x faster | + From 640901146f8e9c0a01f96fadc572a5ce91178ac9 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:11:53 +0300 Subject: [PATCH 1001/1182] docs: document the --fresh option --- extras/profiling/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extras/profiling/README.md b/extras/profiling/README.md index 4e3c8588eb..df6ed1ea43 100644 --- a/extras/profiling/README.md +++ b/extras/profiling/README.md @@ -28,3 +28,7 @@ and print it as a markdown table: | `http --offline pie.dev/get` (startup) | 200 ms | 174 ms: 1.15x faster | | Geometric mean | (ref) | 1.10x faster | +If your `master` branch is not up-to-date, you can get +a fresh clone by passing `--fresh` option. This way, +the benchmark runner will clone the `httpie/httpie` repo +from `GitHub` and use it as the baseline. From df6843b15a4e052e7df5354ad776cb8afdc7e1cb Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:14:40 +0300 Subject: [PATCH 1002/1182] docs: add --{local, target}-{repo, branch} / format --- extras/profiling/README.md | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/extras/profiling/README.md b/extras/profiling/README.md index df6ed1ea43..6a03c032bf 100644 --- a/extras/profiling/README.md +++ b/extras/profiling/README.md @@ -1,34 +1,32 @@ # HTTPie Benchmarking Infrastructure -This directory includes the benchmarks we -use for testing HTTPie's speed and the infrastructure -to automate this testing accross versions. +This directory includes the benchmarks we use for testing HTTPie's speed and the infrastructure to automate this testing accross versions. ## Usage Ensure the following requirements are satisfied: + - Python 3.7+ - `pyperf` Then, run the `extras/benchmarks/run.py`: + ``` $ python extras/profiling/run.py ``` -Without any options, this command will initially create -an isolated environment and install `httpie` from the -latest commit. Then it will create a second environment -with the `master` of the current repository and run the -benchmarks on both of them. It will compare the results -and print it as a markdown table: +Without any options, this command will initially create an isolated environment and install `httpie` from the latest commit. Then it will create a +second environment with the `master` of the current repository and run the benchmarks on both of them. It will compare the results and print it as a +markdown table: -| Benchmark | master | this_branch | -|----------------------------------------|:------:|:--------------------:| +| Benchmark | master | this_branch | +| -------------------------------------- | :----: | :------------------: | | `http --version` (startup) | 201 ms | 174 ms: 1.16x faster | | `http --offline pie.dev/get` (startup) | 200 ms | 174 ms: 1.15x faster | -| Geometric mean | (ref) | 1.10x faster | +| Geometric mean | (ref) | 1.10x faster | + +If your `master` branch is not up-to-date, you can get a fresh clone by passing `--fresh` option. This way, the benchmark runner will clone the +`httpie/httpie` repo from `GitHub` and use it as the baseline. -If your `master` branch is not up-to-date, you can get -a fresh clone by passing `--fresh` option. This way, -the benchmark runner will clone the `httpie/httpie` repo -from `GitHub` and use it as the baseline. +You can customize these branches by passing `--local-repo`/`--target-branch`, and customize the repos by passing `--local-repo`/`--target-repo` (can +either take a URL or a path). From 378a1f513edcd732ad4a9cde1b8fe4d2dfc2023b Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:14:57 +0300 Subject: [PATCH 1003/1182] Document the pyOpenSSL option --- extras/profiling/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extras/profiling/README.md b/extras/profiling/README.md index 6a03c032bf..087ab5bce0 100644 --- a/extras/profiling/README.md +++ b/extras/profiling/README.md @@ -30,3 +30,5 @@ If your `master` branch is not up-to-date, you can get a fresh clone by passing You can customize these branches by passing `--local-repo`/`--target-branch`, and customize the repos by passing `--local-repo`/`--target-repo` (can either take a URL or a path). + +If you want to run a third enviroment with additional dependencies (such as `pyOpenSSL`), you can pass `--complex`. From d5e3611e856a2ef0ec67736ff01353224b1c104c Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:16:38 +0300 Subject: [PATCH 1004/1182] fix lint errors --- extras/profiling/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/profiling/README.md b/extras/profiling/README.md index 087ab5bce0..f92feb76a3 100644 --- a/extras/profiling/README.md +++ b/extras/profiling/README.md @@ -11,7 +11,7 @@ Ensure the following requirements are satisfied: Then, run the `extras/benchmarks/run.py`: -``` +```console $ python extras/profiling/run.py ``` From 45fcd746d71d0ac019b37dd1de48ef68965c94a1 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 18:20:03 +0300 Subject: [PATCH 1005/1182] docs: format the benchmark docs --- extras/profiling/README.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/extras/profiling/README.md b/extras/profiling/README.md index f92feb76a3..c2487de4a6 100644 --- a/extras/profiling/README.md +++ b/extras/profiling/README.md @@ -1,6 +1,7 @@ # HTTPie Benchmarking Infrastructure -This directory includes the benchmarks we use for testing HTTPie's speed and the infrastructure to automate this testing accross versions. +This directory includes the benchmarks we use for testing HTTPie's speed and the +infrastructure to automate this testing accross versions. ## Usage @@ -15,9 +16,10 @@ Then, run the `extras/benchmarks/run.py`: $ python extras/profiling/run.py ``` -Without any options, this command will initially create an isolated environment and install `httpie` from the latest commit. Then it will create a -second environment with the `master` of the current repository and run the benchmarks on both of them. It will compare the results and print it as a -markdown table: +Without any options, this command will initially create an isolated environment +and install `httpie` from the latest commit. Then it will create a second +environment with the `master` of the current repository and run the benchmarks +on both of them. It will compare the results and print it as a markdown table: | Benchmark | master | this_branch | | -------------------------------------- | :----: | :------------------: | @@ -25,10 +27,13 @@ markdown table: | `http --offline pie.dev/get` (startup) | 200 ms | 174 ms: 1.15x faster | | Geometric mean | (ref) | 1.10x faster | -If your `master` branch is not up-to-date, you can get a fresh clone by passing `--fresh` option. This way, the benchmark runner will clone the -`httpie/httpie` repo from `GitHub` and use it as the baseline. +If your `master` branch is not up-to-date, you can get a fresh clone by passing +`--fresh` option. This way, the benchmark runner will clone the `httpie/httpie` +repo from `GitHub` and use it as the baseline. -You can customize these branches by passing `--local-repo`/`--target-branch`, and customize the repos by passing `--local-repo`/`--target-repo` (can -either take a URL or a path). +You can customize these branches by passing `--local-repo`/`--target-branch`, +and customize the repos by passing `--local-repo`/`--target-repo` (can either +take a URL or a path). -If you want to run a third enviroment with additional dependencies (such as `pyOpenSSL`), you can pass `--complex`. +If you want to run a third enviroment with additional dependencies (such as +`pyOpenSSL`), you can pass `--complex`. From 813e8864a1bfd6f9fc22b3ea2ad727c20cba6fac Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 21:13:47 +0300 Subject: [PATCH 1006/1182] Dont apply default options on the httpie command (#1280) * Mark tests with requires_installation * Dont apply default options on the httpie command * lint --- httpie/core.py | 5 +++-- httpie/manager/__main__.py | 3 ++- pytest.ini | 3 +++ tests/test_plugins_cli.py | 27 +++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 pytest.ini diff --git a/httpie/core.py b/httpie/core.py index 04cfa021f8..079de17d28 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -30,14 +30,15 @@ def raw_main( parser: argparse.ArgumentParser, main_program: Callable[[argparse.Namespace, Environment], ExitStatus], args: List[Union[str, bytes]] = sys.argv, - env: Environment = Environment() + env: Environment = Environment(), + use_default_options: bool = True, ) -> ExitStatus: program_name, *args = args env.program_name = os.path.basename(program_name) args = decode_raw_args(args, env.stdin_encoding) plugin_manager.load_installed_plugins(env.config.plugins_dir) - if env.config.default_options: + if use_default_options and env.config.default_options: args = env.config.default_options + args include_debug_info = '--debug' in args diff --git a/httpie/manager/__main__.py b/httpie/manager/__main__.py index 50a5fbd3e4..922e3d2a55 100644 --- a/httpie/manager/__main__.py +++ b/httpie/manager/__main__.py @@ -37,7 +37,8 @@ def main(args: List[Union[str, bytes]] = sys.argv, env: Environment = Environmen parser=parser, main_program=main_program, args=args, - env=env + env=env, + use_default_options=False, ) except argparse.ArgumentError: program_args = args[1:] diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000000..7c6209701b --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +markers = + requires_installation diff --git a/tests/test_plugins_cli.py b/tests/test_plugins_cli.py index af4a77469b..9f94821505 100644 --- a/tests/test_plugins_cli.py +++ b/tests/test_plugins_cli.py @@ -5,6 +5,7 @@ from tests.utils.plugins_cli import parse_listing +@pytest.mark.requires_installation def test_plugins_installation(httpie_plugins_success, interface, dummy_plugin): lines = httpie_plugins_success('install', dummy_plugin.path) assert lines[0].startswith( @@ -14,6 +15,20 @@ def test_plugins_installation(httpie_plugins_success, interface, dummy_plugin): assert interface.is_installed(dummy_plugin.name) +@pytest.mark.requires_installation +def test_plugin_installation_with_custom_config(httpie_plugins_success, interface, dummy_plugin): + interface.environment.config['default_options'] = ['--session-read-only', 'some-path.json', 'other', 'args'] + interface.environment.config.save() + + lines = httpie_plugins_success('install', dummy_plugin.path) + assert lines[0].startswith( + f'Installing {dummy_plugin.path}' + ) + assert f'Successfully installed {dummy_plugin.name}-{dummy_plugin.version}' in lines + assert interface.is_installed(dummy_plugin.name) + + +@pytest.mark.requires_installation def test_plugins_listing(httpie_plugins_success, interface, dummy_plugin): httpie_plugins_success('install', dummy_plugin.path) data = parse_listing(httpie_plugins_success('list')) @@ -23,6 +38,7 @@ def test_plugins_listing(httpie_plugins_success, interface, dummy_plugin): } +@pytest.mark.requires_installation def test_plugins_listing_multiple(interface, httpie_plugins_success, dummy_plugins): paths = [plugin.path for plugin in dummy_plugins] httpie_plugins_success('install', *paths) @@ -34,12 +50,14 @@ def test_plugins_listing_multiple(interface, httpie_plugins_success, dummy_plugi } +@pytest.mark.requires_installation def test_plugins_uninstall(interface, httpie_plugins_success, dummy_plugin): httpie_plugins_success('install', dummy_plugin.path) httpie_plugins_success('uninstall', dummy_plugin.name) assert not interface.is_installed(dummy_plugin.name) +@pytest.mark.requires_installation def test_plugins_listing_after_uninstall(interface, httpie_plugins_success, dummy_plugin): httpie_plugins_success('install', dummy_plugin.path) httpie_plugins_success('uninstall', dummy_plugin.name) @@ -48,6 +66,7 @@ def test_plugins_listing_after_uninstall(interface, httpie_plugins_success, dumm assert len(data) == 0 +@pytest.mark.requires_installation def test_plugins_uninstall_specific(interface, httpie_plugins_success): new_plugin_1 = interface.make_dummy_plugin() new_plugin_2 = interface.make_dummy_plugin() @@ -61,6 +80,7 @@ def test_plugins_uninstall_specific(interface, httpie_plugins_success): assert not interface.is_installed(target_plugin.name) +@pytest.mark.requires_installation def test_plugins_installation_failed(httpie_plugins, interface): plugin = interface.make_dummy_plugin(build=False) result = httpie_plugins('install', plugin.path) @@ -69,6 +89,7 @@ def test_plugins_installation_failed(httpie_plugins, interface): assert result.stderr.splitlines()[-1].strip().startswith("Can't install") +@pytest.mark.requires_installation def test_plugins_uninstall_non_existent(httpie_plugins, interface): plugin = interface.make_dummy_plugin(build=False) result = httpie_plugins('uninstall', plugin.name) @@ -80,6 +101,7 @@ def test_plugins_uninstall_non_existent(httpie_plugins, interface): ) +@pytest.mark.requires_installation def test_plugins_double_uninstall(httpie_plugins, httpie_plugins_success, dummy_plugin): httpie_plugins_success("install", dummy_plugin.path) httpie_plugins_success("uninstall", dummy_plugin.name) @@ -93,6 +115,7 @@ def test_plugins_double_uninstall(httpie_plugins, httpie_plugins_success, dummy_ ) +@pytest.mark.requires_installation def test_plugins_upgrade(httpie_plugins, httpie_plugins_success, dummy_plugin): httpie_plugins_success("install", dummy_plugin.path) @@ -105,6 +128,7 @@ def test_plugins_upgrade(httpie_plugins, httpie_plugins_success, dummy_plugin): assert data[dummy_plugin.name]['version'] == '2.0.0' +@pytest.mark.requires_installation def test_broken_plugins(httpie_plugins, httpie_plugins_success, dummy_plugin, broken_plugin): httpie_plugins_success("install", dummy_plugin.path, broken_plugin.path) @@ -127,6 +151,7 @@ def test_broken_plugins(httpie_plugins, httpie_plugins_success, dummy_plugin, br assert len(data) == 1 +@pytest.mark.requires_installation def test_plugins_cli_error_message_without_args(): # No arguments result = httpie(no_debug=True) @@ -143,6 +168,7 @@ def test_plugins_cli_error_message_without_args(): 'POST pie.dev/post header:value a=b header_2:value x:=1' ] ) +@pytest.mark.requires_installation def test_plugins_cli_error_messages_with_example(example): result = httpie(*example.split(), no_debug=True) assert result.exit_status == ExitStatus.ERROR @@ -158,6 +184,7 @@ def test_plugins_cli_error_messages_with_example(example): 'unknown.com UNPARSABLE????SYNTAX', ] ) +@pytest.mark.requires_installation def test_plugins_cli_error_messages_invalid_example(example): result = httpie(*example.split(), no_debug=True) assert result.exit_status == ExitStatus.ERROR From 559134de0ad655fbf3eded2e90e5f49bdc381bd5 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 24 Jan 2022 21:20:17 +0300 Subject: [PATCH 1007/1182] Release 3.0.2 (#1281) --- CHANGELOG.md | 6 ++++++ httpie/__init__.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58dc677bcd..3f793d3fbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). +## [3.0.2](https://github.com/httpie/httpie/compare/3.0.0...3.0.1) (2022-01-23) + +[What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) + +- Fixed usage of `httpie` when there is a presence of a config with `default_options` ([#1280](https://github.com/httpie/httpie/pull/1280)). + ## [3.0.1](https://github.com/httpie/httpie/compare/3.0.0...3.0.1) (2022-01-23) [What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) diff --git a/httpie/__init__.py b/httpie/__init__.py index 7861602703..7d48b3499c 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '3.0.1' +__version__ = '3.0.2' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From c8404493e5344b722cf7b565ce966391f7e3d461 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 24 Jan 2022 10:32:07 -0800 Subject: [PATCH 1008/1182] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f793d3fbb..f25973d633 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). -## [3.0.2](https://github.com/httpie/httpie/compare/3.0.0...3.0.1) (2022-01-23) +## [3.0.2](https://github.com/httpie/httpie/compare/3.0.1...3.0.2) (2022-01-23) [What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) From fde64d578df8926e027f9d6e9f7e954c23ef1e40 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 24 Jan 2022 10:32:24 -0800 Subject: [PATCH 1009/1182] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f25973d633..21ba01ad4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). -## [3.0.2](https://github.com/httpie/httpie/compare/3.0.1...3.0.2) (2022-01-23) +## [3.0.2](https://github.com/httpie/httpie/compare/3.0.1...3.0.2) (2022-01-24) [What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) From f756cad58df11f55585f1aa7512a27e13657d06b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 24 Jan 2022 16:54:50 -0800 Subject: [PATCH 1010/1182] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21ba01ad4f..045d406cfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,13 @@ This project adheres to [Semantic Versioning](https://semver.org/). [What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) -- Fixed usage of `httpie` when there is a presence of a config with `default_options` ([#1280](https://github.com/httpie/httpie/pull/1280)). +- Fixed usage of `httpie` when there is a presence of a config with `default_options`. ([#1280](https://github.com/httpie/httpie/pull/1280)) ## [3.0.1](https://github.com/httpie/httpie/compare/3.0.0...3.0.1) (2022-01-23) [What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) -- Changed the value shown as time elapsed from time-to-read-headers to total exchange time ([#1277](https://github.com/httpie/httpie/issues/1277)) +- Changed the value shown as time elapsed from time-to-read-headers to total exchange time. ([#1277](https://github.com/httpie/httpie/issues/1277)) ## [3.0.0](https://github.com/httpie/httpie/compare/2.6.0...3.0.0) (2022-01-21) From 770df02291dac25fcfc0b62b80bf3aa0c8b12967 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 26 Jan 2022 12:44:24 +0300 Subject: [PATCH 1011/1182] Add level parameter to the snap releaser (#1282) --- .github/workflows/release-snap.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-snap.yml b/.github/workflows/release-snap.yml index 9c6b009452..ff44ef3608 100644 --- a/.github/workflows/release-snap.yml +++ b/.github/workflows/release-snap.yml @@ -5,6 +5,10 @@ on: description: "The branch, tag or SHA to release from" required: true default: "master" + level: + description: "Release level: stable, candidate, beta, edge" + required: true + default: "edge" jobs: snap: @@ -19,4 +23,4 @@ jobs: with: store_login: ${{ secrets.SNAP_STORE_LOGIN }} snap: ${{ steps.build.outputs.snap }} - release: edge + release: ${{ github.event.inputs.level }} From fc383e9b78fc2ce232f67bd9ba755d0f59338401 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 26 Jan 2022 12:49:27 +0300 Subject: [PATCH 1012/1182] Add names to the CI runners --- .github/workflows/code-style.yml | 2 ++ .github/workflows/coverage.yml | 2 ++ .github/workflows/docs-check-markdown.yml | 2 ++ 3 files changed, 6 insertions(+) diff --git a/.github/workflows/code-style.yml b/.github/workflows/code-style.yml index 580bf467a1..3d220d72f0 100644 --- a/.github/workflows/code-style.yml +++ b/.github/workflows/code-style.yml @@ -1,3 +1,5 @@ +name: Code Style Check + on: pull_request: paths: diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index e178de17f9..5edb47fa46 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,3 +1,5 @@ +name: Coverage + on: pull_request: paths: diff --git a/.github/workflows/docs-check-markdown.yml b/.github/workflows/docs-check-markdown.yml index a2cb9fbfd3..f019bf7017 100644 --- a/.github/workflows/docs-check-markdown.yml +++ b/.github/workflows/docs-check-markdown.yml @@ -1,3 +1,5 @@ +name: Check Markdown Style + on: pull_request: paths: From a7d8187b212541458b2b55c57542ec77dec99833 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 26 Jan 2022 12:50:22 +0300 Subject: [PATCH 1013/1182] Proper naming for the release runs --- .github/workflows/docs-deploy.yml | 2 ++ .github/workflows/docs-update-install.yml | 2 ++ .github/workflows/release-snap.yml | 2 ++ 3 files changed, 6 insertions(+) diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index ff3217ac0b..62df9c0c0d 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -1,3 +1,5 @@ +name: Deploy Documentation + on: push: branches: diff --git a/.github/workflows/docs-update-install.yml b/.github/workflows/docs-update-install.yml index c7d13e0ba0..3a22aaa0bb 100644 --- a/.github/workflows/docs-update-install.yml +++ b/.github/workflows/docs-update-install.yml @@ -1,3 +1,5 @@ +name: Update & Install Docs + on: push: branches: diff --git a/.github/workflows/release-snap.yml b/.github/workflows/release-snap.yml index ff44ef3608..f67c0e2577 100644 --- a/.github/workflows/release-snap.yml +++ b/.github/workflows/release-snap.yml @@ -1,3 +1,5 @@ +name: Release snap + on: workflow_dispatch: inputs: From c03f081a7e49c5e8465af8ec00b2e8b89c680f1a Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 26 Jan 2022 12:51:10 +0300 Subject: [PATCH 1014/1182] Finish off the naming --- .github/workflows/release.yml | 4 +++- .github/workflows/test-package-linux-snap.yml | 3 +++ .github/workflows/test-package-mac-brew.yml | 2 ++ .github/workflows/tests.yml | 2 ++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e2dd258209..12753b49f5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,5 @@ +name: Release on PyPI + on: # Add a "Trigger" button to manually start the workflow. workflow_dispatch: @@ -19,7 +21,7 @@ jobs: - uses: actions/checkout@v2 with: ref: ${{ github.event.inputs.branch }} - - name: PyPi configuration + - name: PyPI configuration run: | echo "[distutils]\nindex-servers=\n httpie\n\n[httpie]\nrepository = https://upload.pypi.org/legacy/\n" > $HOME/.pypirc - uses: actions/setup-python@v2 diff --git a/.github/workflows/test-package-linux-snap.yml b/.github/workflows/test-package-linux-snap.yml index 17200074e2..12a2766a40 100644 --- a/.github/workflows/test-package-linux-snap.yml +++ b/.github/workflows/test-package-linux-snap.yml @@ -1,3 +1,6 @@ +name: Test Snap Package (Linux) + + on: pull_request: paths: diff --git a/.github/workflows/test-package-mac-brew.yml b/.github/workflows/test-package-mac-brew.yml index 064bafb0fa..6570a2afd9 100644 --- a/.github/workflows/test-package-mac-brew.yml +++ b/.github/workflows/test-package-mac-brew.yml @@ -1,3 +1,5 @@ +name: Test Brew Package (MacOS) + on: pull_request: paths: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 96289c603c..e3cde99669 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,3 +1,5 @@ +name: Tests + on: push: branches: From 86ba995ad881a1a09b04c8088211c40329932256 Mon Sep 17 00:00:00 2001 From: Marcos Chicote Date: Wed, 26 Jan 2022 15:45:03 +0100 Subject: [PATCH 1015/1182] 2022 (#1259) --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index a6270bbf89..4a53e9d679 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright © 2012-2021 Jakub Roztocil +Copyright © 2012-2022 Jakub Roztocil Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From 7abddfe3500a777240889529ce32f2ecbb55169c Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 1 Feb 2022 12:52:07 +0300 Subject: [PATCH 1016/1182] Mark stdin warning related tests with `requires_external_processes` (#1289) * Mark test_stdin_read_warning with requires_installation * Mark stdin tests with requires_external_processes Co-authored-by: Nilushan Costa <19643850+nilushancosta@users.noreply.github.com> --- pytest.ini | 4 ++++ tests/test_uploads.py | 3 +++ 2 files changed, 7 insertions(+) diff --git a/pytest.ini b/pytest.ini index 7c6209701b..ced65979b1 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,3 +1,7 @@ [pytest] markers = + # If you want to run tests without a full HTTPie installation + # we advise you to disable the markers below, e.g: + # pytest -m 'not requires_installation and not requires_external_processes' requires_installation + requires_external_processes diff --git a/tests/test_uploads.py b/tests/test_uploads.py index d9de3ac984..5695d0c8c2 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -121,6 +121,7 @@ def stdin_processes(httpbin, *args): @pytest.mark.parametrize("wait", (True, False)) +@pytest.mark.requires_external_processes @pytest.mark.skipif(is_windows, reason="Windows doesn't support select() calls into files") def test_reading_from_stdin(httpbin, wait): with stdin_processes(httpbin) as (process_1, process_2): @@ -138,6 +139,7 @@ def test_reading_from_stdin(httpbin, wait): assert b'> warning: no stdin data read in 0.1s' not in errs +@pytest.mark.requires_external_processes @pytest.mark.skipif(is_windows, reason="Windows doesn't support select() calls into files") def test_stdin_read_warning(httpbin): with stdin_processes(httpbin) as (process_1, process_2): @@ -153,6 +155,7 @@ def test_stdin_read_warning(httpbin): assert b'> warning: no stdin data read in 0.1s' in errs +@pytest.mark.requires_external_processes @pytest.mark.skipif(is_windows, reason="Windows doesn't support select() calls into files") def test_stdin_read_warning_with_quiet(httpbin): with stdin_processes(httpbin, "-qq") as (process_1, process_2): From f1ea4860254bebefb363d2fda2e5a75fc6226f3e Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 1 Feb 2022 13:10:55 +0300 Subject: [PATCH 1017/1182] Fix escaping of integer indexes with multiple backslashes (#1288) --- CHANGELOG.md | 4 ++++ httpie/cli/nested_json.py | 24 ++++++++++++------------ tests/test_json.py | 22 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 045d406cfe..b580104564 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). +## Unreleased + +- Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/httpie/issues/1285)) + ## [3.0.2](https://github.com/httpie/httpie/compare/3.0.1...3.0.2) (2022-01-24) [What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) diff --git a/httpie/cli/nested_json.py b/httpie/cli/nested_json.py index 501e3b594f..beb5205843 100644 --- a/httpie/cli/nested_json.py +++ b/httpie/cli/nested_json.py @@ -88,18 +88,18 @@ def send_buffer() -> Iterator[Token]: return None value = ''.join(buffer) - for variation, kind in [ - (int, TokenKind.NUMBER), - (check_escaped_int, TokenKind.TEXT), - ]: - try: - value = variation(value) - except ValueError: - continue - else: - break - else: - kind = TokenKind.TEXT + kind = TokenKind.TEXT + if not backslashes: + for variation, kind in [ + (int, TokenKind.NUMBER), + (check_escaped_int, TokenKind.TEXT), + ]: + try: + value = variation(value) + except ValueError: + continue + else: + break yield Token( kind, value, start=cursor - (len(buffer) + backslashes), end=cursor diff --git a/tests/test_json.py b/tests/test_json.py index b454c03408..7b4dff41e8 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -397,6 +397,28 @@ def test_complex_json_arguments_with_non_json(httpbin, request_type, value): '2012': {'x': 2, '[3]': 4}, }, ), + ( + [ + r'a[\0]:=0', + r'a[\\1]:=1', + r'a[\\\2]:=2', + r'a[\\\\\3]:=3', + r'a[-1\\]:=-1', + r'a[-2\\\\]:=-2', + r'a[\\-3\\\\]:=-3', + ], + { + "a": { + "0": 0, + r"\1": 1, + r"\\2": 2, + r"\\\3": 3, + "-1\\": -1, + "-2\\\\": -2, + "\\-3\\\\": -3, + } + } + ), ], ) def test_nested_json_syntax(input_json, expected_json, httpbin): From d45f413f12198137869e403a3a77ffdf073206db Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 3 Feb 2022 12:47:06 +0300 Subject: [PATCH 1018/1182] Make the version point to `3.0.3.dev0` (#1291) --- CHANGELOG.md | 2 +- docs/README.md | 2 +- httpie/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b580104564..fa90f10714 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). -## Unreleased +## [3.0.3.dev0](https://github.com/httpie/httpie/compare/3.0.2...HEAD) (Unreleased) - Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/httpie/issues/1285)) diff --git a/docs/README.md b/docs/README.md index 66bb4d6a9d..5b4f6493da 100644 --- a/docs/README.md +++ b/docs/README.md @@ -260,7 +260,7 @@ Verify that now you have the [current development version identifier](https://gi ```bash $ http --version -# 3.0.0 +# 3.0.3.dev0 ``` ## Usage diff --git a/httpie/__init__.py b/httpie/__init__.py index 7d48b3499c..683e7b98a7 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,6 +3,6 @@ """ -__version__ = '3.0.2' +__version__ = '3.0.3.dev0' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 42edb1eb767110d9dbe883f2ada469d798d675e0 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Sat, 5 Feb 2022 22:07:28 +0300 Subject: [PATCH 1019/1182] Use 3.0.0 blog post as the changelog --- docs/packaging/windows-chocolatey/httpie.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/packaging/windows-chocolatey/httpie.nuspec b/docs/packaging/windows-chocolatey/httpie.nuspec index ce69afa5a7..6a3e4fc8c5 100644 --- a/docs/packaging/windows-chocolatey/httpie.nuspec +++ b/docs/packaging/windows-chocolatey/httpie.nuspec @@ -33,7 +33,7 @@ Main features: https://raw.githubusercontent.com/httpie/httpie/master/LICENSE https://pie-assets.s3.eu-central-1.amazonaws.com/LogoIcons/GB.png false - See the [changelog](https://github.com/httpie/httpie/blob/2.6.0/CHANGELOG.md). + See the [changelog](https://httpie.io/blog/httpie-3.0.0). httpie http https rest api client curl python ssl cli foss oss url https://httpie.io https://github.com/httpie/httpie/tree/master/docs/packaging/windows-chocolatey From 46e782bf75092a94a7a4f966e29f4f9c2b1d2970 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Sat, 5 Feb 2022 22:07:51 +0300 Subject: [PATCH 1020/1182] Point package to 3.0.2 --- docs/packaging/windows-chocolatey/httpie.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/packaging/windows-chocolatey/httpie.nuspec b/docs/packaging/windows-chocolatey/httpie.nuspec index 6a3e4fc8c5..3dc8358727 100644 --- a/docs/packaging/windows-chocolatey/httpie.nuspec +++ b/docs/packaging/windows-chocolatey/httpie.nuspec @@ -2,7 +2,7 @@ httpie - 2.6.0 + 3.0.2 Modern, user-friendly command-line HTTP client for the API era HTTPie *aitch-tee-tee-pie* is a user-friendly command-line HTTP client for the API era. From 37ef6708760015ffed51d3197bd3ae5fba6df9ed Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Sat, 5 Feb 2022 22:08:03 +0300 Subject: [PATCH 1021/1182] Update copyright year --- docs/packaging/windows-chocolatey/httpie.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/packaging/windows-chocolatey/httpie.nuspec b/docs/packaging/windows-chocolatey/httpie.nuspec index 3dc8358727..0406a1f21e 100644 --- a/docs/packaging/windows-chocolatey/httpie.nuspec +++ b/docs/packaging/windows-chocolatey/httpie.nuspec @@ -29,7 +29,7 @@ Main features: HTTPie HTTPie jakubroztocil - 2012-2021 Jakub Roztocil + 2012-2022 Jakub Roztocil https://raw.githubusercontent.com/httpie/httpie/master/LICENSE https://pie-assets.s3.eu-central-1.amazonaws.com/LogoIcons/GB.png false From 5fd48e31377edd3083f06fa00759814ea7cd0c32 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 8 Feb 2022 12:21:58 +0300 Subject: [PATCH 1022/1182] Use the lastest fedora spec in the packit --- .packit.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.packit.yaml b/.packit.yaml index 8fc33379d6..afb1dc1a20 100644 --- a/.packit.yaml +++ b/.packit.yaml @@ -2,9 +2,9 @@ # https://packit.dev/docs/configuration/ specfile_path: httpie.spec actions: - # get the current Fedora Rawhide specfile: - # post-upstream-clone: "wget https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec -O httpie.spec" - post-upstream-clone: "cp docs/packaging/linux-fedora/httpie.spec.txt httpie.spec" + get the current Fedora Rawhide specfile: + post-upstream-clone: "wget https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec -O httpie.spec" + # post-upstream-clone: "cp docs/packaging/linux-fedora/httpie.spec.txt httpie.spec" jobs: - job: copr_build trigger: pull_request From 384d3869f6b8e9e926ca5be04d2154c4d4101ac9 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 8 Feb 2022 12:22:27 +0300 Subject: [PATCH 1023/1182] Update the local copy fore 3.0.2 --- docs/packaging/linux-fedora/httpie.spec.txt | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/packaging/linux-fedora/httpie.spec.txt b/docs/packaging/linux-fedora/httpie.spec.txt index b0ab5b7b3a..f18f487801 100644 --- a/docs/packaging/linux-fedora/httpie.spec.txt +++ b/docs/packaging/linux-fedora/httpie.spec.txt @@ -1,5 +1,5 @@ Name: httpie -Version: 2.6.0 +Version: 3.0.2 Release: 1%{?dist} Summary: A Curl-like tool for humans @@ -78,6 +78,21 @@ help2man %{buildroot}%{_bindir}/httpie > %{buildroot}%{_mandir}/man1/httpie.1 %changelog +* Mon Jan 24 2022 Miro Hrončok - 3.0.2-1 +- Update to 3.0.2 +- Fixes: rhbz#2044572 + +* Mon Jan 24 2022 Miro Hrončok - 3.0.1-1 +- Update to 3.0.1 +- Fixes: rhbz#2044058 + +* Fri Jan 21 2022 Miro Hrončok - 3.0.0-1 +- Update to 3.0.0 +- Fixes: rhbz#2043680 + +* Thu Jan 20 2022 Fedora Release Engineering - 2.6.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + * Fri Oct 15 2021 Miro Hrončok - 2.6.0-1 - Update to 2.6.0 - Fixes: rhbz#2014022 From e306667436f6a81054034c20297e137d4a433986 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 8 Feb 2022 12:23:35 +0300 Subject: [PATCH 1024/1182] Leave a note for the local spec --- .packit.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.packit.yaml b/.packit.yaml index afb1dc1a20..32eae1f0e0 100644 --- a/.packit.yaml +++ b/.packit.yaml @@ -4,6 +4,7 @@ specfile_path: httpie.spec actions: get the current Fedora Rawhide specfile: post-upstream-clone: "wget https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec -O httpie.spec" + # Use this when the latest spec is not up-to-date. # post-upstream-clone: "cp docs/packaging/linux-fedora/httpie.spec.txt httpie.spec" jobs: - job: copr_build From 0a9d3d3c54c316c17d3558443f44b5be7e2968f7 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 8 Feb 2022 12:28:45 +0300 Subject: [PATCH 1025/1182] Fix the packit syntax --- .packit.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.packit.yaml b/.packit.yaml index 32eae1f0e0..b002afa67e 100644 --- a/.packit.yaml +++ b/.packit.yaml @@ -2,7 +2,7 @@ # https://packit.dev/docs/configuration/ specfile_path: httpie.spec actions: - get the current Fedora Rawhide specfile: + # get the current Fedora Rawhide specfile: post-upstream-clone: "wget https://src.fedoraproject.org/rpms/httpie/raw/rawhide/f/httpie.spec -O httpie.spec" # Use this when the latest spec is not up-to-date. # post-upstream-clone: "cp docs/packaging/linux-fedora/httpie.spec.txt httpie.spec" From cafa11665b2d1d4f8d8e6358913a4a9c5a97a484 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 8 Feb 2022 12:37:45 +0300 Subject: [PATCH 1026/1182] Disable additional repos --- .packit.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.packit.yaml b/.packit.yaml index b002afa67e..0ae2100cbc 100644 --- a/.packit.yaml +++ b/.packit.yaml @@ -12,8 +12,6 @@ jobs: metadata: targets: - fedora-all - additional_repos: - - "https://kojipkgs.fedoraproject.org/repos/f$releasever-build/latest/$basearch/" - job: propose_downstream trigger: release metadata: From 225dccb2186f14f871695b6c4e0bfbcdb2e3aa28 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Wed, 9 Feb 2022 02:18:40 +0300 Subject: [PATCH 1027/1182] Regulate top-level arrays (#1292) * Redesign the starting path * Do not cast `:=[1,2,3]` to a top-level array --- docs/README.md | 41 +++++++++++++++++++++ httpie/cli/constants.py | 1 + httpie/cli/dicts.py | 4 ++ httpie/cli/nested_json.py | 76 +++++++++++++++++++++++++++++++------- httpie/client.py | 6 ++- tests/test_json.py | 77 +++++++++++++++++++++++++++++++++------ 6 files changed, 177 insertions(+), 28 deletions(-) diff --git a/docs/README.md b/docs/README.md index 5b4f6493da..bc7f0e7af7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -854,6 +854,47 @@ $ http PUT pie.dev/put \ #### Advanced usage +##### Top level arrays + +If you want to send an array instead of a regular object, you can simply +do that by omitting the starting key: + +```bash +$ http --offline --print=B pie.dev/post \ + []:=1 \ + []:=2 \ + []:=3 +``` + +```json +[ + 1, + 2, + 3 +] +``` + +You can also apply the nesting to the items by referencing their index: + +```bash +http --offline --print=B pie.dev/post \ + [0][type]=platform [0][name]=terminal \ + [1][type]=platform [1][name]=desktop +``` + +```json +[ + { + "type": "platform", + "name": "terminal" + }, + { + "type": "platform", + "name": "desktop" + } +] +``` + ##### Escaping behavior Nested JSON syntax uses the same [escaping rules](#escaping-rules) as diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index 897e806b4d..067aaabdf7 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -127,6 +127,7 @@ class RequestType(enum.Enum): JSON = enum.auto() +EMPTY_STRING = '' OPEN_BRACKET = '[' CLOSE_BRACKET = ']' BACKSLASH = '\\' diff --git a/httpie/cli/dicts.py b/httpie/cli/dicts.py index 3d0cab5a45..434a396672 100644 --- a/httpie/cli/dicts.py +++ b/httpie/cli/dicts.py @@ -82,3 +82,7 @@ class MultipartRequestDataDict(MultiValueOrderedDict): class RequestFilesDict(RequestDataDict): pass + + +class NestedJSONArray(list): + """Denotes a top-level JSON array.""" diff --git a/httpie/cli/nested_json.py b/httpie/cli/nested_json.py index beb5205843..c75798929d 100644 --- a/httpie/cli/nested_json.py +++ b/httpie/cli/nested_json.py @@ -9,7 +9,8 @@ Type, Union, ) -from httpie.cli.constants import OPEN_BRACKET, CLOSE_BRACKET, BACKSLASH, HIGHLIGHTER +from httpie.cli.dicts import NestedJSONArray +from httpie.cli.constants import EMPTY_STRING, OPEN_BRACKET, CLOSE_BRACKET, BACKSLASH, HIGHLIGHTER class HTTPieSyntaxError(ValueError): @@ -52,6 +53,7 @@ def to_name(self) -> str: OPERATORS = {OPEN_BRACKET: TokenKind.LEFT_BRACKET, CLOSE_BRACKET: TokenKind.RIGHT_BRACKET} SPECIAL_CHARS = OPERATORS.keys() | {BACKSLASH} +LITERAL_TOKENS = [TokenKind.TEXT, TokenKind.NUMBER] class Token(NamedTuple): @@ -171,8 +173,8 @@ def reconstruct(self) -> str: def parse(source: str) -> Iterator[Path]: """ - start: literal? path* - + start: root_path path* + root_path: (literal | index_path | append_path) literal: TEXT | NUMBER path: @@ -215,16 +217,47 @@ def expect(*kinds): message = f'Expecting {suffix}' raise HTTPieSyntaxError(source, token, message) - root = Path(PathAction.KEY, '', is_root=True) - if can_advance(): - token = tokens[cursor] - if token.kind in {TokenKind.TEXT, TokenKind.NUMBER}: - token = expect(TokenKind.TEXT, TokenKind.NUMBER) - root.accessor = str(token.value) - root.tokens.append(token) + def parse_root(): + tokens = [] + if not can_advance(): + return Path( + PathAction.KEY, + EMPTY_STRING, + is_root=True + ) + + # (literal | index_path | append_path)? + token = expect(*LITERAL_TOKENS, TokenKind.LEFT_BRACKET) + tokens.append(token) + + if token.kind in LITERAL_TOKENS: + action = PathAction.KEY + value = str(token.value) + elif token.kind is TokenKind.LEFT_BRACKET: + token = expect(TokenKind.NUMBER, TokenKind.RIGHT_BRACKET) + tokens.append(token) + if token.kind is TokenKind.NUMBER: + action = PathAction.INDEX + value = token.value + tokens.append(expect(TokenKind.RIGHT_BRACKET)) + elif token.kind is TokenKind.RIGHT_BRACKET: + action = PathAction.APPEND + value = None + else: + assert_cant_happen() + else: + assert_cant_happen() + + return Path( + action, + value, + tokens=tokens, + is_root=True + ) - yield root + yield parse_root() + # path* while can_advance(): path_tokens = [] path_tokens.append(expect(TokenKind.LEFT_BRACKET)) @@ -296,6 +329,10 @@ def object_for(kind: str) -> Any: assert_cant_happen() for index, (path, next_path) in enumerate(zip(paths, paths[1:])): + # If there is no context yet, set it. + if cursor is None: + context = cursor = object_for(path.kind) + if path.kind is PathAction.KEY: type_check(index, path, dict) if next_path.kind is PathAction.SET: @@ -337,8 +374,19 @@ def object_for(kind: str) -> Any: return context +def wrap_with_dict(context): + if context is None: + return {} + elif isinstance(context, list): + return {EMPTY_STRING: NestedJSONArray(context)} + else: + assert isinstance(context, dict) + return context + + def interpret_nested_json(pairs): - context = {} + context = None for key, value in pairs: - interpret(context, key, value) - return context + context = interpret(context, key, value) + + return wrap_with_dict(context) diff --git a/httpie/client.py b/httpie/client.py index c2563cbc3e..06235d249b 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -13,7 +13,8 @@ from . import __version__ from .adapters import HTTPieHTTPAdapter from .context import Environment -from .cli.dicts import HTTPHeadersDict +from .cli.constants import EMPTY_STRING +from .cli.dicts import HTTPHeadersDict, NestedJSONArray from .encoding import UTF8 from .models import RequestsMessage from .plugins.registry import plugin_manager @@ -280,7 +281,8 @@ def json_dict_to_request_body(data: Dict[str, Any]) -> str: # item in the object, with an en empty key. if len(data) == 1: [(key, value)] = data.items() - if key == '' and isinstance(value, list): + if isinstance(value, NestedJSONArray): + assert key == EMPTY_STRING data = value if data: diff --git a/tests/test_json.py b/tests/test_json.py index 7b4dff41e8..2ba603a680 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -321,7 +321,7 @@ def test_complex_json_arguments_with_non_json(httpbin, request_type, value): 'foo[][key]=value', 'foo[2][key 2]=value 2', r'foo[2][key \[]=value 3', - r'[nesting][under][!][empty][?][\\key]:=4', + r'bar[nesting][under][!][empty][?][\\key]:=4', ], { 'foo': [ @@ -329,7 +329,7 @@ def test_complex_json_arguments_with_non_json(httpbin, request_type, value): 2, {'key': 'value', 'key 2': 'value 2', 'key [': 'value 3'}, ], - '': { + 'bar': { 'nesting': {'under': {'!': {'empty': {'?': {'\\key': 4}}}}} }, }, @@ -408,17 +408,47 @@ def test_complex_json_arguments_with_non_json(httpbin, request_type, value): r'a[\\-3\\\\]:=-3', ], { - "a": { - "0": 0, - r"\1": 1, - r"\\2": 2, - r"\\\3": 3, - "-1\\": -1, - "-2\\\\": -2, - "\\-3\\\\": -3, + 'a': { + '0': 0, + r'\1': 1, + r'\\2': 2, + r'\\\3': 3, + '-1\\': -1, + '-2\\\\': -2, + '\\-3\\\\': -3, } - } + }, + ), + ( + ['[]:=0', '[]:=1', '[5]:=5', '[]:=6', '[9]:=9'], + [0, 1, None, None, None, 5, 6, None, None, 9], + ), + ( + ['=empty', 'foo=bar', 'bar[baz][quux]=tuut'], + {'': 'empty', 'foo': 'bar', 'bar': {'baz': {'quux': 'tuut'}}}, + ), + ( + [ + r'\1=top level int', + r'\\1=escaped top level int', + r'\2[\3][\4]:=5', + ], + { + '1': 'top level int', + '\\1': 'escaped top level int', + '2': {'3': {'4': 5}}, + }, + ), + ( + [':={"foo": {"bar": "baz"}}', 'top=val'], + {'': {'foo': {'bar': 'baz'}}, 'top': 'val'}, + ), + ( + ['[][a][b][]:=1', '[0][a][b][]:=2', '[][]:=2'], + [{'a': {'b': [1, 2]}}, [2]], ), + ([':=[1,2,3]'], {'': [1, 2, 3]}), + ([':=[1,2,3]', 'foo=bar'], {'': [1, 2, 3], 'foo': 'bar'}), ], ) def test_nested_json_syntax(input_json, expected_json, httpbin): @@ -516,13 +546,36 @@ def test_nested_json_syntax(input_json, expected_json, httpbin): ['foo[\\1]:=2', 'foo[5]:=3'], "HTTPie Type Error: Can't perform 'index' based access on 'foo' which has a type of 'object' but this operation requires a type of 'array'.\nfoo[5]\n ^^^", ), + ( + ['x=y', '[]:=2'], + "HTTPie Type Error: Can't perform 'append' based access on '' which has a type of 'object' but this operation requires a type of 'array'.", + ), + ( + ['[]:=2', 'x=y'], + "HTTPie Type Error: Can't perform 'key' based access on '' which has a type of 'array' but this operation requires a type of 'object'.", + ), + ( + [':=[1,2,3]', '[]:=4'], + "HTTPie Type Error: Can't perform 'append' based access on '' which has a type of 'object' but this operation requires a type of 'array'.", + ), + ( + ['[]:=4', ':=[1,2,3]'], + "HTTPie Type Error: Can't perform 'key' based access on '' which has a type of 'array' but this operation requires a type of 'object'.", + ), ], ) def test_nested_json_errors(input_json, expected_error, httpbin): with pytest.raises(HTTPieSyntaxError) as exc: http(httpbin + '/post', *input_json) - assert str(exc.value) == expected_error + exc_lines = str(exc.value).splitlines() + expected_lines = expected_error.splitlines() + if len(expected_lines) == 1: + # When the error offsets are not important, we'll just compare the actual + # error message. + exc_lines = exc_lines[:1] + + assert expected_lines == exc_lines def test_nested_json_sparse_array(httpbin_both): From ad613f29d229d36f8b6b998c05e54bbd1d63a3a7 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 25 Feb 2022 12:51:34 +0300 Subject: [PATCH 1028/1182] Add a changelog entry for the top-level array regulation --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa90f10714..73186f6f79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [3.0.3.dev0](https://github.com/httpie/httpie/compare/3.0.2...HEAD) (Unreleased) - Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/httpie/issues/1285)) +- Improved regulation of top-level arrays. ([#1292](https://github.com/httpie/httpie/commit/225dccb2186f14f871695b6c4e0bfbcdb2e3aa28)) ## [3.0.2](https://github.com/httpie/httpie/compare/3.0.1...3.0.2) (2022-01-24) From 30cd862fc0e173698fc17487c4b96d8f64b701ea Mon Sep 17 00:00:00 2001 From: Sebastian Stasiak Date: Mon, 28 Feb 2022 22:57:23 +0100 Subject: [PATCH 1029/1182] Update commands for Arch (#1306) --- docs/README.md | 4 ++-- docs/installation/methods.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/README.md b/docs/README.md index bc7f0e7af7..590e0de4a4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -205,12 +205,12 @@ Also works for other Arch-derived distributions like ArcoLinux, EndeavourOS, Art ```bash # Install httpie -$ pacman -Sy httpie +$ pacman -Syu httpie ``` ```bash # Upgrade httpie -$ pacman -Syu httpie +$ pacman -Syu ``` ### FreeBSD diff --git a/docs/installation/methods.yml b/docs/installation/methods.yml index 1583b2364a..0828b0d603 100644 --- a/docs/installation/methods.yml +++ b/docs/installation/methods.yml @@ -106,9 +106,9 @@ tools: package: https://archlinux.org/packages/community/any/httpie/ commands: install: - - pacman -Sy httpie - upgrade: - pacman -Syu httpie + upgrade: + - pacman -Syu pkg: title: FreshPorts From 6bf39e469faf08ea74bb40875da2fd5cbbb23226 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Mar 2022 17:17:41 +0300 Subject: [PATCH 1030/1182] Bump actions/setup-python from 2 to 3 (#1307) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2 to 3. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/benchmark.yml | 2 +- .github/workflows/code-style.yml | 2 +- .github/workflows/coverage.yml | 2 +- .github/workflows/docs-update-install.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/tests.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 560835dab2..e5b40a95be 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v3 with: python-version: "3.9" diff --git a/.github/workflows/code-style.yml b/.github/workflows/code-style.yml index 3d220d72f0..e25e9515e3 100644 --- a/.github/workflows/code-style.yml +++ b/.github/workflows/code-style.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v3 with: python-version: 3.9 - run: make venv diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5edb47fa46..de0063f604 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v3 with: python-version: "3.10" - run: make install diff --git a/.github/workflows/docs-update-install.yml b/.github/workflows/docs-update-install.yml index 3a22aaa0bb..d92f76c11e 100644 --- a/.github/workflows/docs-update-install.yml +++ b/.github/workflows/docs-update-install.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v3 with: python-version: 3.9 - run: make install diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 12753b49f5..944d3a3faa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: - name: PyPI configuration run: | echo "[distutils]\nindex-servers=\n httpie\n\n[httpie]\nrepository = https://upload.pypi.org/legacy/\n" > $HOME/.pypirc - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v3 with: python-version: 3.9 - run: make publish diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e3cde99669..f8946c0904 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,7 +27,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} - name: Windows setup From 6f77e144e4e2ed73ace47cb7547c006861917c11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Mar 2022 08:16:56 -0800 Subject: [PATCH 1031/1182] Bump actions/checkout from 2 to 3 (#1311) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/benchmark.yml | 2 +- .github/workflows/code-style.yml | 2 +- .github/workflows/coverage.yml | 2 +- .github/workflows/docs-check-markdown.yml | 2 +- .github/workflows/docs-update-install.yml | 2 +- .github/workflows/release-snap.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/test-package-linux-snap.yml | 2 +- .github/workflows/test-package-mac-brew.yml | 2 +- .github/workflows/tests.yml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index e5b40a95be..08d24700ea 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -13,7 +13,7 @@ jobs: if: github.event.label.name == 'benchmark' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-python@v3 with: python-version: "3.9" diff --git a/.github/workflows/code-style.yml b/.github/workflows/code-style.yml index e25e9515e3..b53b353b04 100644 --- a/.github/workflows/code-style.yml +++ b/.github/workflows/code-style.yml @@ -13,7 +13,7 @@ jobs: code-style: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-python@v3 with: python-version: 3.9 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index de0063f604..acd9aeb9da 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -12,7 +12,7 @@ jobs: coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-python@v3 with: python-version: "3.10" diff --git a/.github/workflows/docs-check-markdown.yml b/.github/workflows/docs-check-markdown.yml index f019bf7017..a19c25916a 100644 --- a/.github/workflows/docs-check-markdown.yml +++ b/.github/workflows/docs-check-markdown.yml @@ -10,7 +10,7 @@ jobs: doc: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Ruby uses: ruby/setup-ruby@v1 with: diff --git a/.github/workflows/docs-update-install.yml b/.github/workflows/docs-update-install.yml index d92f76c11e..2d3fbe09d9 100644 --- a/.github/workflows/docs-update-install.yml +++ b/.github/workflows/docs-update-install.yml @@ -15,7 +15,7 @@ jobs: doc: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-python@v3 with: python-version: 3.9 diff --git a/.github/workflows/release-snap.yml b/.github/workflows/release-snap.yml index f67c0e2577..149adc50e7 100644 --- a/.github/workflows/release-snap.yml +++ b/.github/workflows/release-snap.yml @@ -16,7 +16,7 @@ jobs: snap: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: ref: ${{ github.event.inputs.branch }} - uses: snapcore/action-build@v1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 944d3a3faa..30561369d1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: new-release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: ref: ${{ github.event.inputs.branch }} - name: PyPI configuration diff --git a/.github/workflows/test-package-linux-snap.yml b/.github/workflows/test-package-linux-snap.yml index 12a2766a40..ac9640a06d 100644 --- a/.github/workflows/test-package-linux-snap.yml +++ b/.github/workflows/test-package-linux-snap.yml @@ -12,7 +12,7 @@ jobs: snap: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build uses: snapcore/action-build@v1 id: snapcraft diff --git a/.github/workflows/test-package-mac-brew.yml b/.github/workflows/test-package-mac-brew.yml index 6570a2afd9..babdaa5def 100644 --- a/.github/workflows/test-package-mac-brew.yml +++ b/.github/workflows/test-package-mac-brew.yml @@ -11,7 +11,7 @@ jobs: brew: runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup brew run: | brew developer on diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f8946c0904..17d03d3eef 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,7 +26,7 @@ jobs: pyopenssl: [0, 1] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} From 25bd817bb2ea3dddbb9682766948495bb0b4efe3 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 3 Mar 2022 19:28:04 +0300 Subject: [PATCH 1032/1182] Fix displaying of status code without a status message. (#1301) Co-authored-by: Jakub Roztocil --- CHANGELOG.md | 2 ++ httpie/output/lexers/http.py | 2 +- tests/test_output.py | 27 +++++++++++++++++++++++++-- tests/utils/__init__.py | 6 ++++++ tests/utils/http_server.py | 16 ++++++++++++++-- 5 files changed, 48 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73186f6f79..026916d2f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [3.0.3.dev0](https://github.com/httpie/httpie/compare/3.0.2...HEAD) (Unreleased) - Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/httpie/issues/1285)) +- Fixed displaying of status code without a status message on non-`auto` themes. ([#1300](https://github.com/httpie/httpie/issues/1300)) - Improved regulation of top-level arrays. ([#1292](https://github.com/httpie/httpie/commit/225dccb2186f14f871695b6c4e0bfbcdb2e3aa28)) + ## [3.0.2](https://github.com/httpie/httpie/compare/3.0.1...3.0.2) (2022-01-24) [What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) diff --git a/httpie/output/lexers/http.py b/httpie/output/lexers/http.py index f06a685380..aea827401e 100644 --- a/httpie/output/lexers/http.py +++ b/httpie/output/lexers/http.py @@ -2,7 +2,7 @@ import pygments from httpie.output.lexers.common import precise -RE_STATUS_LINE = re.compile(r'(\d{3})( +)(.+)') +RE_STATUS_LINE = re.compile(r'(\d{3})( +)?(.+)?') STATUS_TYPES = { '1': pygments.token.Number.HTTP.INFO, diff --git a/tests/test_output.py b/tests/test_output.py index c68bfa9e38..716ceb097d 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -17,10 +17,15 @@ ) from httpie.cli.definition import parser from httpie.encoding import UTF8 -from httpie.output.formatters.colors import get_lexer, PIE_STYLE_NAMES +from httpie.output.formatters.colors import get_lexer, PIE_STYLE_NAMES, BUNDLED_STYLES from httpie.status import ExitStatus from .fixtures import XML_DATA_RAW, XML_DATA_FORMATTED -from .utils import COLOR, CRLF, HTTP_OK, MockEnvironment, http, DUMMY_URL +from .utils import COLOR, CRLF, HTTP_OK, MockEnvironment, http, DUMMY_URL, strip_colors + + +# For ensuring test reproducibility, avoid using the unsorted +# BUNDLED_STYLES set. +SORTED_BUNDLED_STYLES = sorted(BUNDLED_STYLES) @pytest.mark.parametrize('stdout_isatty', [True, False]) @@ -234,6 +239,24 @@ def test_ensure_meta_is_colored(httpbin, style): assert COLOR in r +@pytest.mark.parametrize('style', SORTED_BUNDLED_STYLES) +@pytest.mark.parametrize('msg', [ + '', + ' ', + ' OK', + ' OK ', + ' CUSTOM ', +]) +def test_ensure_status_code_is_shown_on_all_themes(http_server, style, msg): + env = MockEnvironment(colors=256) + r = http('--style', style, + http_server + '/status/msg', + '--raw', msg, env=env) + + # Trailing space is stripped away. + assert 'HTTP/1.0 200' + msg.rstrip() in strip_colors(r) + + class TestPrettyOptions: """Test the --pretty handling.""" diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index f8954565c5..2bd376eef4 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -27,6 +27,8 @@ TESTS_ROOT = Path(__file__).parent.parent CRLF = '\r\n' COLOR = '\x1b[' +COLOR_RE = re.compile(r'\x1b\[\d+(;\d+)*?m', re.MULTILINE) + HTTP_OK = '200 OK' # noinspection GrazieInspection HTTP_OK_COLOR = ( @@ -38,6 +40,10 @@ DUMMY_URL = 'http://this-should.never-resolve' # Note: URL never fetched +def strip_colors(colorized_msg: str) -> str: + return COLOR_RE.sub('', colorized_msg) + + def mk_config_dir() -> Path: dirname = tempfile.mkdtemp(prefix='httpie_config_') return Path(dirname) diff --git a/tests/utils/http_server.py b/tests/utils/http_server.py index fc8f2b07a2..0a96dd8b07 100644 --- a/tests/utils/http_server.py +++ b/tests/utils/http_server.py @@ -18,14 +18,17 @@ def inner(func): return func return inner - def do_GET(self): + def do_generic(self): parse_result = urlparse(self.path) - func = self.handlers['GET'].get(parse_result.path) + func = self.handlers[self.command].get(parse_result.path) if func is None: return self.send_error(HTTPStatus.NOT_FOUND) return func(self) + do_GET = do_generic + do_POST = do_generic + @TestHandler.handler('GET', '/headers') def get_headers(handler): @@ -73,6 +76,15 @@ def random_encoding(handler): handler.wfile.write('0\r\n\r\n'.encode('utf-8')) +@TestHandler.handler('POST', '/status/msg') +def status_custom_msg(handler): + content_len = int(handler.headers.get('content-length', 0)) + post_body = handler.rfile.read(content_len).decode() + + handler.send_response(200, post_body) + handler.end_headers() + + @pytest.fixture(scope="function") def http_server(): """A custom HTTP server implementation for our tests, that is From c901e704633cb79c686b3edaae497ed38b2978ba Mon Sep 17 00:00:00 2001 From: Hoylen Sue Date: Fri, 4 Mar 2022 02:31:06 +1000 Subject: [PATCH 1033/1182] Replaced unmaintained OAuth plugin with new httpie-oauth1 plugin. (#1302) --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 590e0de4a4..b5d139aad9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1377,7 +1377,7 @@ Here are a few picks: - [httpie-jwt-auth](https://github.com/teracyhq/httpie-jwt-auth): JWTAuth (JSON Web Tokens) - [httpie-negotiate](https://github.com/ndzou/httpie-negotiate): SPNEGO (GSS Negotiate) - [httpie-ntlm](https://github.com/httpie/httpie-ntlm): NTLM (NT LAN Manager) -- [httpie-oauth](https://github.com/httpie/httpie-oauth): OAuth +- [httpie-oauth1](https://github.com/qcif/httpie-oauth1): OAuth 1.0a - [requests-hawk](https://github.com/mozilla-services/requests-hawk): Hawk See [plugin manager](#plugin-manager) for more details. From 55087a901e86eeda2a62e33765bb48299f004a78 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 7 Mar 2022 15:40:35 +0300 Subject: [PATCH 1034/1182] Introduce a mode to suppress all warnings (#1283) --- CHANGELOG.md | 2 +- httpie/cli/argparser.py | 2 ++ httpie/context.py | 29 ++++++++++++++++++++++++++--- httpie/core.py | 4 ++-- tests/test_output.py | 26 ++++++++++++++++++++++++++ tests/utils/__init__.py | 2 ++ 6 files changed, 59 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 026916d2f4..e74b331772 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/httpie/issues/1285)) - Fixed displaying of status code without a status message on non-`auto` themes. ([#1300](https://github.com/httpie/httpie/issues/1300)) - Improved regulation of top-level arrays. ([#1292](https://github.com/httpie/httpie/commit/225dccb2186f14f871695b6c4e0bfbcdb2e3aa28)) - +- Double `--quiet` flags will now suppress all python level warnings. ([#1271](https://github.com/httpie/httpie/issues/1271)) ## [3.0.2](https://github.com/httpie/httpie/compare/3.0.1...3.0.2) (2022-01-24) diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 64481096c7..b1ab8de155 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -230,9 +230,11 @@ def _setup_standard_streams(self): self.env.stdout_isatty = False if self.args.quiet: + self.env.quiet = self.args.quiet self.env.stderr = self.env.devnull if not (self.args.output_file_specified and not self.args.download): self.env.stdout = self.env.devnull + self.env.apply_warnings_filter() def _process_auth(self): # TODO: refactor & simplify this method. diff --git a/httpie/context.py b/httpie/context.py index 7a6e6a865c..50a8f772cd 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -1,8 +1,10 @@ import sys import os +import warnings from contextlib import contextmanager from pathlib import Path from typing import Iterator, IO, Optional +from enum import Enum try: @@ -17,6 +19,17 @@ from .utils import repr_dict +class Levels(str, Enum): + WARNING = 'warning' + ERROR = 'error' + + +DISPLAY_THRESHOLDS = { + Levels.WARNING: 2, + Levels.ERROR: float('inf'), # Never hide errors. +} + + class Environment: """ Information about the execution context @@ -87,6 +100,8 @@ def __init__(self, devnull=None, **kwargs): self.stdout_encoding = getattr( actual_stdout, 'encoding', None) or UTF8 + self.quiet = kwargs.pop('quiet', 0) + def __str__(self): defaults = dict(type(self).__dict__) actual = dict(defaults) @@ -134,6 +149,14 @@ def as_silent(self) -> Iterator[None]: self.stdout = original_stdout self.stderr = original_stderr - def log_error(self, msg, level='error'): - assert level in ['error', 'warning'] - self._orig_stderr.write(f'\n{self.program_name}: {level}: {msg}\n\n') + def log_error(self, msg: str, level: Levels = Levels.ERROR) -> None: + if self.stdout_isatty and self.quiet >= DISPLAY_THRESHOLDS[level]: + stderr = self.stderr # Not directly /dev/null, since stderr might be mocked + else: + stderr = self._orig_stderr + + stderr.write(f'\n{self.program_name}: {level}: {msg}\n\n') + + def apply_warnings_filter(self) -> None: + if self.quiet >= DISPLAY_THRESHOLDS[Levels.WARNING]: + warnings.simplefilter("ignore") diff --git a/httpie/core.py b/httpie/core.py index 079de17d28..3dbed19523 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -13,7 +13,7 @@ from .cli.constants import OUT_REQ_BODY from .cli.nested_json import HTTPieSyntaxError from .client import collect_messages -from .context import Environment +from .context import Environment, Levels from .downloads import Downloader from .models import ( RequestsMessageKind, @@ -221,7 +221,7 @@ def request_body_read_callback(chunk: bytes): if args.check_status or downloader: exit_status = http_status_to_exit_status(http_status=message.status_code, follow=args.follow) if exit_status != ExitStatus.SUCCESS and (not env.stdout_isatty or args.quiet == 1): - env.log_error(f'HTTP {message.raw.status} {message.raw.reason}', level='warning') + env.log_error(f'HTTP {message.raw.status} {message.raw.reason}', level=Levels.WARNING) write_message(requests_message=message, env=env, args=args, output_options=output_options._replace( body=do_write_body )) diff --git a/tests/test_output.py b/tests/test_output.py index 716ceb097d..470673bf91 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -5,6 +5,7 @@ import json import os import io +import warnings from urllib.request import urlopen import pytest @@ -90,6 +91,31 @@ def test_quiet_quiet_with_check_status_non_zero_pipe(self, httpbin): ) assert 'http: warning: HTTP 500' in r.stderr + @mock.patch('httpie.core.program') + @pytest.mark.parametrize('flags, expected_warnings', [ + ([], 1), + (['-q'], 1), + (['-qq'], 0), + ]) + def test_quiet_on_python_warnings(self, test_patch, httpbin, flags, expected_warnings): + def warn_and_run(*args, **kwargs): + warnings.warn('warning!!') + return ExitStatus.SUCCESS + + test_patch.side_effect = warn_and_run + with pytest.warns(None) as record: + http(*flags, httpbin + '/get') + + assert len(record) == expected_warnings + + def test_double_quiet_on_error(self, httpbin): + r = http( + '-qq', '--check-status', '$$$this.does.not.exist$$$', + tolerate_error_exit_status=True, + ) + assert not r + assert 'Couldn’t resolve the given hostname' in r.stderr + @pytest.mark.parametrize('quiet_flags', QUIET_SCENARIOS) @mock.patch('httpie.cli.argtypes.AuthCredentials._getpass', new=lambda self, prompt: 'password') diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index 2bd376eef4..cf90d684b9 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -5,6 +5,7 @@ import time import json import tempfile +import warnings from io import BytesIO from pathlib import Path from typing import Any, Optional, Union, List, Iterable @@ -96,6 +97,7 @@ def create_temp_config_dir(self): def cleanup(self): self.stdout.close() self.stderr.close() + warnings.resetwarnings() if self._delete_config_dir: assert self._temp_dir in self.config_dir.parents from shutil import rmtree From b0f5b8ab2600016b9ecf479abd4eb8961ea8fbf3 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 25 Feb 2022 15:42:13 +0300 Subject: [PATCH 1035/1182] Prevent data race happening between `select.select` and `file.read()` --- httpie/uploads.py | 59 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/httpie/uploads.py b/httpie/uploads.py index 4fdb79222d..9ddc89c0ca 100644 --- a/httpie/uploads.py +++ b/httpie/uploads.py @@ -2,6 +2,8 @@ import os import zlib import functools +import time +import threading from typing import Any, Callable, IO, Iterable, Optional, Tuple, Union, TYPE_CHECKING from urllib.parse import urlencode @@ -22,12 +24,20 @@ def __iter__(self) -> Iterable[Union[str, bytes]]: class ChunkedUploadStream(ChunkedStream): - def __init__(self, stream: Iterable, callback: Callable): + def __init__( + self, + stream: Iterable, + callback: Callable, + event: Optional[threading.Event] = None + ) -> None: self.callback = callback self.stream = stream + self.event = event def __iter__(self) -> Iterable[Union[str, bytes]]: for chunk in self.stream: + if self.event: + self.event.set() self.callback(chunk) yield chunk @@ -35,12 +45,19 @@ def __iter__(self) -> Iterable[Union[str, bytes]]: class ChunkedMultipartUploadStream(ChunkedStream): chunk_size = 100 * 1024 - def __init__(self, encoder: 'MultipartEncoder'): + def __init__( + self, + encoder: 'MultipartEncoder', + event: Optional[threading.Event] = None + ) -> None: self.encoder = encoder + self.event = event def __iter__(self) -> Iterable[Union[str, bytes]]: while True: chunk = self.encoder.read(self.chunk_size) + if self.event: + self.event.set() if not chunk: break yield chunk @@ -80,7 +97,7 @@ def is_stdin(file: IO) -> bool: READ_THRESHOLD = float(os.getenv("HTTPIE_STDIN_READ_WARN_THRESHOLD", 10.0)) -def observe_stdin_for_data_thread(env: Environment, file: IO) -> None: +def observe_stdin_for_data_thread(env: Environment, file: IO, read_event: threading.Event) -> None: # Windows unfortunately does not support select() operation # on regular files, like stdin in our use case. # https://docs.python.org/3/library/select.html#select.select @@ -92,12 +109,9 @@ def observe_stdin_for_data_thread(env: Environment, file: IO) -> None: if READ_THRESHOLD == 0: return None - import select - import threading - - def worker(): - can_read, _, _ = select.select([file], [], [], READ_THRESHOLD) - if not can_read: + def worker(event: threading.Event) -> None: + time.sleep(READ_THRESHOLD) + if not event.is_set(): env.stderr.write( f'> warning: no stdin data read in {READ_THRESHOLD}s ' f'(perhaps you want to --ignore-stdin)\n' @@ -105,11 +119,28 @@ def worker(): ) thread = threading.Thread( - target=worker + target=worker, + args=(read_event,) ) thread.start() +def _read_file_with_selectors(file: IO, read_event: threading.Event) -> bytes: + if is_windows or not is_stdin(file): + return as_bytes(file.read()) + + import select + + # Try checking whether there is any incoming data for READ_THRESHOLD + # seconds. If there isn't anything in the given period, issue + # a warning about a misusage. + read_selectors, _, _ = select.select([file], [], [], READ_THRESHOLD) + if read_selectors: + read_event.set() + + return as_bytes(file.read()) + + def _prepare_file_for_upload( env: Environment, file: Union[IO, 'MultipartEncoder'], @@ -117,9 +148,11 @@ def _prepare_file_for_upload( chunked: bool = False, content_length_header_value: Optional[int] = None, ) -> Union[bytes, IO, ChunkedStream]: + read_event = threading.Event() if not super_len(file): if is_stdin(file): - observe_stdin_for_data_thread(env, file) + observe_stdin_for_data_thread(env, file, read_event) + # Zero-length -> assume stdin. if content_length_header_value is None and not chunked: # Read the whole stdin to determine `Content-Length`. @@ -129,7 +162,7 @@ def _prepare_file_for_upload( # something like --no-chunked. # This would be backwards-incompatible so wait until v3.0.0. # - file = as_bytes(file.read()) + file = _read_file_with_selectors(file, read_event) else: file.read = _wrap_function_with_callback( file.read, @@ -141,11 +174,13 @@ def _prepare_file_for_upload( if isinstance(file, MultipartEncoder): return ChunkedMultipartUploadStream( encoder=file, + event=read_event, ) else: return ChunkedUploadStream( stream=file, callback=callback, + event=read_event ) else: return file From 5c982533777ed054a7cef2398b542473f8df3b3d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Thu, 3 Mar 2022 08:22:17 -0800 Subject: [PATCH 1036/1182] Update httpie/uploads.py --- httpie/uploads.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/uploads.py b/httpie/uploads.py index 9ddc89c0ca..c9a763df78 100644 --- a/httpie/uploads.py +++ b/httpie/uploads.py @@ -94,7 +94,7 @@ def is_stdin(file: IO) -> bool: return file_no == sys.stdin.fileno() -READ_THRESHOLD = float(os.getenv("HTTPIE_STDIN_READ_WARN_THRESHOLD", 10.0)) +READ_THRESHOLD = float(os.getenv('HTTPIE_STDIN_READ_WARN_THRESHOLD', 10.0)) def observe_stdin_for_data_thread(env: Environment, file: IO, read_event: threading.Event) -> None: From 5ac05e95149eaafb9dd1a1c1f3971da00ce0d466 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 7 Mar 2022 15:51:15 +0300 Subject: [PATCH 1037/1182] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e74b331772..4a05cbc9ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/httpie/issues/1285)) - Fixed displaying of status code without a status message on non-`auto` themes. ([#1300](https://github.com/httpie/httpie/issues/1300)) +- Fixed redundant issuance of stdin detection warnings on some rare cases due to underlying implementation. ([#1303](https://github.com/httpie/httpie/pull/1303)) - Improved regulation of top-level arrays. ([#1292](https://github.com/httpie/httpie/commit/225dccb2186f14f871695b6c4e0bfbcdb2e3aa28)) - Double `--quiet` flags will now suppress all python level warnings. ([#1271](https://github.com/httpie/httpie/issues/1271)) From 98688b2f2dec7d0f3fb78a5d14c41e94dce58cb3 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 7 Mar 2022 15:51:51 +0300 Subject: [PATCH 1038/1182] Style fix on the changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a05cbc9ca..fa83b97232 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/httpie/issues/1285)) - Fixed displaying of status code without a status message on non-`auto` themes. ([#1300](https://github.com/httpie/httpie/issues/1300)) -- Fixed redundant issuance of stdin detection warnings on some rare cases due to underlying implementation. ([#1303](https://github.com/httpie/httpie/pull/1303)) +- Fixed redundant issuance of stdin detection warnings on some rare cases due to underlying implementation. ([#1303](https://github.com/httpie/httpie/pull/1303)) - Improved regulation of top-level arrays. ([#1292](https://github.com/httpie/httpie/commit/225dccb2186f14f871695b6c4e0bfbcdb2e3aa28)) - Double `--quiet` flags will now suppress all python level warnings. ([#1271](https://github.com/httpie/httpie/issues/1271)) From 15013fd609db6b23551a4691429a61d8e2632fe2 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 1 Mar 2022 17:16:37 +0300 Subject: [PATCH 1039/1182] Implement support for private key passphrases --- CHANGELOG.md | 1 + docs/README.md | 15 +++++++ httpie/cli/argparser.py | 17 ++++++- httpie/cli/argtypes.py | 33 ++++++++++---- httpie/cli/definition.py | 13 +++++- httpie/client.py | 11 ++++- httpie/ssl_.py | 33 ++++++++++++++ .../password_protected/client.key | 42 +++++++++++++++++ .../password_protected/client.pem | 26 +++++++++++ tests/test_ssl.py | 45 +++++++++++++++++++ 10 files changed, 223 insertions(+), 13 deletions(-) create mode 100644 tests/client_certs/password_protected/client.key create mode 100644 tests/client_certs/password_protected/client.pem diff --git a/CHANGELOG.md b/CHANGELOG.md index fa83b97232..77a1d1f9a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [3.0.3.dev0](https://github.com/httpie/httpie/compare/3.0.2...HEAD) (Unreleased) +- Added support for specifying certificate private key passphrases through `--cert-key-pass` and prompts. ([#946](https://github.com/httpie/httpie/issues/946)) - Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/httpie/issues/1285)) - Fixed displaying of status code without a status message on non-`auto` themes. ([#1300](https://github.com/httpie/httpie/issues/1300)) - Fixed redundant issuance of stdin detection warnings on some rare cases due to underlying implementation. ([#1303](https://github.com/httpie/httpie/pull/1303)) diff --git a/docs/README.md b/docs/README.md index b5d139aad9..00aff4b842 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1489,6 +1489,21 @@ path of the key file with `--cert-key`: $ http --cert=client.crt --cert-key=client.key https://example.org ``` +If the given private key requires a passphrase, HTTPie will automatically detect it +and ask it through a prompt: + +```bash +$ http --cert=client.pem --cert-key=client.key https://example.org +http: passphrase for client.key: **** +``` + +If you don't want to see a prompt, you can supply the passphrase with the `--cert-key-pass` +argument: + +```bash +$ http --cert=client.pem --cert-key=client.key --cert-key-pass=my_password https://example.org +``` + ### SSL version Use the `--ssl=` option to specify the desired protocol version to use. diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index b1ab8de155..f9d6674b7e 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -10,7 +10,8 @@ from requests.utils import get_netrc_auth from .argtypes import ( - AuthCredentials, KeyValueArgType, PARSED_DEFAULT_FORMAT_OPTIONS, + AuthCredentials, SSLCredentials, KeyValueArgType, + PARSED_DEFAULT_FORMAT_OPTIONS, parse_auth, parse_format_options, ) @@ -148,6 +149,7 @@ def parse_args( self._parse_items() self._process_url() self._process_auth() + self._process_ssl_cert() if self.args.raw is not None: self._body_from_input(self.args.raw) @@ -236,6 +238,19 @@ def _setup_standard_streams(self): self.env.stdout = self.env.devnull self.env.apply_warnings_filter() + def _process_ssl_cert(self): + from httpie.ssl_ import _is_key_file_encrypted + + if self.args.cert_key_pass is None: + self.args.cert_key_pass = SSLCredentials(None) + + if ( + self.args.cert_key is not None + and self.args.cert_key_pass.value is None + and _is_key_file_encrypted(self.args.cert_key) + ): + self.args.cert_key_pass.prompt_password(self.args.cert_key) + def _process_auth(self): # TODO: refactor & simplify this method. self.args.auth_plugin = None diff --git a/httpie/cli/argtypes.py b/httpie/cli/argtypes.py index 7bc487ea81..8f19c3c51e 100644 --- a/httpie/cli/argtypes.py +++ b/httpie/cli/argtypes.py @@ -130,16 +130,11 @@ def tokenize(self, s: str) -> List[Union[str, Escaped]]: return tokens -class AuthCredentials(KeyValueArg): - """Represents parsed credentials.""" - - def has_password(self) -> bool: - return self.value is not None - - def prompt_password(self, host: str): - prompt_text = f'http: password for {self.key}@{host}: ' +class PromptMixin: + def _prompt_password(self, prompt: str) -> str: + prompt_text = f'http: {prompt}: ' try: - self.value = self._getpass(prompt_text) + return self._getpass(prompt_text) except (EOFError, KeyboardInterrupt): sys.stderr.write('\n') sys.exit(0) @@ -150,6 +145,26 @@ def _getpass(prompt): return getpass.getpass(str(prompt)) +class SSLCredentials(PromptMixin): + """Represents the passphrase for the certificate's key.""" + + def __init__(self, value: Optional[str]) -> None: + self.value = value + + def prompt_password(self, key_file: str) -> None: + self.value = self._prompt_password(f'passphrase for {key_file}') + + +class AuthCredentials(KeyValueArg, PromptMixin): + """Represents parsed credentials.""" + + def has_password(self) -> bool: + return self.value is not None + + def prompt_password(self, host: str) -> None: + self.value = self._prompt_password(f'password for {self.key}@{host}:') + + class AuthCredentialsArgType(KeyValueArgType): """A key-value arg type that parses credentials.""" diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 5ccc3a16f9..0a0efafa6f 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -8,7 +8,7 @@ from .. import __doc__, __version__ from .argparser import HTTPieArgumentParser from .argtypes import ( - KeyValueArgType, SessionNameValidator, + KeyValueArgType, SessionNameValidator, SSLCredentials, readable_file_arg, response_charset_type, response_mime_type, ) from .constants import ( @@ -803,6 +803,17 @@ def format_auth_help(auth_plugins_mapping): ''' ) +ssl.add_argument( + '--cert-key-pass', + default=None, + type=SSLCredentials, + help=''' + The passphrase to be used to with the given private key. Only needed if --cert-key + is given and the key file requires a passphrase. + + ''' +) + ####################################################################### # Troubleshooting ####################################################################### diff --git a/httpie/client.py b/httpie/client.py index 06235d249b..1984537c2b 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -19,7 +19,7 @@ from .models import RequestsMessage from .plugins.registry import plugin_manager from .sessions import get_httpie_session -from .ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieHTTPSAdapter +from .ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, HTTPieCertificate, HTTPieHTTPSAdapter from .uploads import ( compress_request, prepare_request_body, get_multipart_data_and_content_type, @@ -262,7 +262,14 @@ def make_send_kwargs_mergeable_from_env(args: argparse.Namespace) -> dict: if args.cert: cert = args.cert if args.cert_key: - cert = cert, args.cert_key + # Having a client certificate key passphrase is not supported + # by requests. So we are using our own transportation structure + # which is compatible with their format (a tuple of minimum two + # items). + # + # See: https://github.com/psf/requests/issues/2519 + cert = HTTPieCertificate(cert, args.cert_key, args.cert_key_pass.value) + return { 'proxies': {p.key: p.value for p in args.proxy}, 'stream': True, diff --git a/httpie/ssl_.py b/httpie/ssl_.py index cdec18f87b..b9438543eb 100644 --- a/httpie/ssl_.py +++ b/httpie/ssl_.py @@ -1,4 +1,5 @@ import ssl +from typing import NamedTuple, Optional from httpie.adapters import HTTPAdapter # noinspection PyPackageRequirements @@ -24,6 +25,17 @@ } +class HTTPieCertificate(NamedTuple): + cert_file: Optional[str] = None + key_file: Optional[str] = None + key_password: Optional[str] = None + + def to_raw_cert(self): + """Synthesize a requests-compatible (2-item tuple of cert and key file) + object from HTTPie's internal representation of a certificate.""" + return (self.cert_file, self.key_file) + + class HTTPieHTTPSAdapter(HTTPAdapter): def __init__( self, @@ -47,6 +59,13 @@ def proxy_manager_for(self, *args, **kwargs): kwargs['ssl_context'] = self._ssl_context return super().proxy_manager_for(*args, **kwargs) + def cert_verify(self, conn, url, verify, cert): + if isinstance(cert, HTTPieCertificate): + conn.key_password = cert.key_password + cert = cert.to_raw_cert() + + return super().cert_verify(conn, url, verify, cert) + @staticmethod def _create_ssl_context( verify: bool, @@ -61,3 +80,17 @@ def _create_ssl_context( # in `super().cert_verify()`. cert_reqs=ssl.CERT_REQUIRED if verify else ssl.CERT_NONE ) + + +def _is_key_file_encrypted(key_file): + """Detects if a key file is encrypted or not. + + Copy of the internal urllib function (urllib3.util.ssl_)""" + + with open(key_file, "r") as f: + for line in f: + # Look for Proc-Type: 4,ENCRYPTED + if "ENCRYPTED" in line: + return True + + return False diff --git a/tests/client_certs/password_protected/client.key b/tests/client_certs/password_protected/client.key new file mode 100644 index 0000000000..1634352f90 --- /dev/null +++ b/tests/client_certs/password_protected/client.key @@ -0,0 +1,42 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,93DA845817852FB576163AA829C232E9 + +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 +-----END RSA PRIVATE KEY----- diff --git a/tests/client_certs/password_protected/client.pem b/tests/client_certs/password_protected/client.pem new file mode 100644 index 0000000000..08ee652254 --- /dev/null +++ b/tests/client_certs/password_protected/client.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEazCCAtOgAwIBAgIUIWojJySwCenyvcJrZY1aKOMQfTUwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjAzMDExMzM5MzRaFw00OTA3 +MTcxMzM5MzRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggGiMA0GCSqGSIb3DQEB +AQUAA4IBjwAwggGKAoIBgQC0+8GOIhknLgLmWEQGgdDJffntbDfGdtG7JFUFfvuN +sibTHL4RPNhe+UrT/LR+JBfIfmdeb+NlmKzsTeR0+8PkX5ZjXMShf5icghVukK7G +OoQS7olQqlGzpIX76VqktVr4tFNXmMJeBO0NIaXHm0ASsoz3fIfDx9ttJETPs6lm +Wv/PUPemvtUgcbAb+kjz9QqcUV8B1xcCvQma6NSpxcmJHqAuI6HkdbDzyedKuuSi +M6yNFjh3EJjsufReQgkcfDsqh+RA3zQoIyPXLNqjzGD71z24jUtvIxb5ZNEtv0xp +5zCOCavuRNNyKGvvnlIeyup7bMe0QIds566miG49osVpPVvVmg+q+w2YYAE+7svb +nJp7NYn2tryRqsmvnASLVQD6T9wTWUa8w/tT1+ltnhfqbwDcVACzsw/U4FFwcfWw +5BnUcJacoDkj/3TCqgkA8XFe1/DVU8XCcsvEaoLzwHhHu2+QDpqal8rNouyTpFGA +/wioVBQGpksPZjl8lumsz3kCAwEAAaNTMFEwHQYDVR0OBBYEFGJhl1BPOXCVqRo3 +U/ruuedvlDqsMB8GA1UdIwQYMBaAFGJhl1BPOXCVqRo3U/ruuedvlDqsMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggGBAE9NtrE5qSHlK9DXdH6bPW6z +GO9uWBl3rJVtqVvPoH8RxJG/jtaD/Pnc3MkIxMoliCleNK6BdYVGV9u8x9W1jQo8 +H+mnH3/Ise8ZY1zpblZJF0z9xs5sWW7qO8U06GmJWRSPn3LKEZjLsNmThhUW09wN +8EZX914zCWtzCrUTNg8Au1Dz9zA9ScfpCVPhKORTCnrpoTL6iXsPxmCx+5awmNLE +uh9kw4NScEyq33RTPosMpwSMlXGRuASltx/J7Rn0DNR0r1p0XzDS4CG1iDwXHlEF +MwsOvSahNyz5RInrU3cgN70tafoRIHScLYycnRml8dydxrDoFgdJk5sI4zgq24Sg +TktTq9ShrT4yQX+lrGS6eZQK/YZEBPD7BdTLYp3vlfYQMJ4Jz9SyQ8b9/9jIFVFS +dFfWiCqEuhTvGfptAzYX+K9OaegZnIk3X7R6O+YQ3oHCbLbnV3bpKlgNnOKBwa2X +kJ5GRp+rZOJ97yjrspKjpR5tNCiJnp7NnnA5VA6mfw== +-----END CERTIFICATE----- diff --git a/tests/test_ssl.py b/tests/test_ssl.py index f930bf2826..fc587064d7 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -6,6 +6,8 @@ import requests.exceptions import urllib3 +from unittest import mock + from httpie.ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS from httpie.status import ExitStatus @@ -32,6 +34,15 @@ CLIENT_KEY = str(CERTS_ROOT / 'client.key') CLIENT_PEM = str(CERTS_ROOT / 'client.pem') +# In case of a regeneration, use the following commands +# in the PWD_TESTS_ROOT: +# $ openssl genrsa -aes128 -passout pass:password 3072 > client.pem +# $ openssl req -new -x509 -nodes -days 10000 -key client.pem > client.pem +PWD_TESTS_ROOT = CERTS_ROOT / 'password_protected' +PWD_CLIENT_PEM = str(PWD_TESTS_ROOT / 'client.pem') +PWD_CLIENT_KEY = str(PWD_TESTS_ROOT / 'client.key') +PWD_CLIENT_PASS = 'password' +PWD_CLIENT_INVALID_PASS = PWD_CLIENT_PASS + 'invalid' # We test against a local httpbin instance which uses a self-signed cert. # Requests without --verify= will fail with a verification error. @@ -165,3 +176,37 @@ def test_pyopenssl_presence(): else: assert urllib3.util.ssl_.IS_PYOPENSSL assert urllib3.util.IS_PYOPENSSL + + +@mock.patch('httpie.cli.argtypes.SSLCredentials._prompt_password', + new=lambda self, prompt: PWD_CLIENT_PASS) +def test_password_protected_cert_prompt(httpbin_secure): + r = http(httpbin_secure + '/get', + '--cert', PWD_CLIENT_PEM, + '--cert-key', PWD_CLIENT_KEY) + assert HTTP_OK in r + + +@mock.patch('httpie.cli.argtypes.SSLCredentials._prompt_password', + new=lambda self, prompt: PWD_CLIENT_INVALID_PASS) +def test_password_protected_cert_prompt_invalid(httpbin_secure): + with pytest.raises(ssl_errors): + http(httpbin_secure + '/get', + '--cert', PWD_CLIENT_PEM, + '--cert-key', PWD_CLIENT_KEY) + + +def test_password_protected_cert_cli_arg(httpbin_secure): + r = http(httpbin_secure + '/get', + '--cert', PWD_CLIENT_PEM, + '--cert-key', PWD_CLIENT_KEY, + '--cert-key-pass', PWD_CLIENT_PASS) + assert HTTP_OK in r + + +def test_password_protected_cert_cli_arg_invalid(httpbin_secure): + with pytest.raises(ssl_errors): + http(httpbin_secure + '/get', + '--cert', PWD_CLIENT_PEM, + '--cert-key', PWD_CLIENT_KEY, + '--cert-key-pass', PWD_CLIENT_INVALID_PASS) From 9241a093605cf6afbd6a52b42db4c946badea420 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 7 Mar 2022 16:05:13 +0300 Subject: [PATCH 1040/1182] Mention about interactive prompt on key passphrases --- httpie/cli/definition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 0a0efafa6f..806b04bc60 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -810,7 +810,7 @@ def format_auth_help(auth_plugins_mapping): help=''' The passphrase to be used to with the given private key. Only needed if --cert-key is given and the key file requires a passphrase. - + If not provided, you’ll be prompted interactively. ''' ) From 350abe30338ffb3fd29129ec12a94ddd69b64080 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 8 Feb 2022 12:13:17 +0300 Subject: [PATCH 1041/1182] Make the naked invocation display a compacted help --- CHANGELOG.md | 1 + httpie/cli/argparser.py | 53 ++++++++++++++++++++++++-- tests/test_cli_ui.py | 84 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 tests/test_cli_ui.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 77a1d1f9a9..7ecf797d29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed displaying of status code without a status message on non-`auto` themes. ([#1300](https://github.com/httpie/httpie/issues/1300)) - Fixed redundant issuance of stdin detection warnings on some rare cases due to underlying implementation. ([#1303](https://github.com/httpie/httpie/pull/1303)) - Improved regulation of top-level arrays. ([#1292](https://github.com/httpie/httpie/commit/225dccb2186f14f871695b6c4e0bfbcdb2e3aa28)) +- Improved UI layout for standalone invocations. ([#1296](https://github.com/httpie/httpie/pull/1296)) - Double `--quiet` flags will now suppress all python level warnings. ([#1271](https://github.com/httpie/httpie/issues/1271)) ## [3.0.2](https://github.com/httpie/httpie/compare/3.0.1...3.0.2) (2022-01-24) diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index f9d6674b7e..c632774d5d 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -48,12 +48,39 @@ def _split_lines(self, text, width): text = dedent(text).strip() + '\n\n' return text.splitlines() + def add_usage(self, usage, actions, groups, prefix=None): + # Only display the positional arguments + displayed_actions = [ + action + for action in actions + if not action.option_strings + ] + + _, exception, _ = sys.exc_info() + if ( + isinstance(exception, argparse.ArgumentError) + and len(exception.args) >= 1 + and isinstance(exception.args[0], argparse.Action) + ): + # add_usage path is also taken when you pass an invalid option, + # e.g --style=invalid. If something like that happens, we want + # to include to action that caused to the invalid usage into + # the list of actions we are displaying. + displayed_actions.insert(0, exception.args[0]) + + super().add_usage( + usage, + displayed_actions, + groups, + prefix="usage:\n " + ) + # TODO: refactor and design type-annotated data structures # for raw args + parsed args and keep things immutable. class BaseHTTPieArgumentParser(argparse.ArgumentParser): - def __init__(self, *args, formatter_class=HTTPieHelpFormatter, **kwargs): - super().__init__(*args, formatter_class=formatter_class, **kwargs) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self.env = None self.args = None self.has_stdin_data = False @@ -116,9 +143,9 @@ class HTTPieArgumentParser(BaseHTTPieArgumentParser): """ - def __init__(self, *args, **kwargs): + def __init__(self, *args, formatter_class=HTTPieHelpFormatter, **kwargs): kwargs.setdefault('add_help', False) - super().__init__(*args, **kwargs) + super().__init__(*args, formatter_class=formatter_class, **kwargs) # noinspection PyMethodOverriding def parse_args( @@ -529,3 +556,21 @@ def _process_format_options(self): for options_group in format_options: parsed_options = parse_format_options(options_group, defaults=parsed_options) self.args.format_options = parsed_options + + def error(self, message): + """Prints a usage message incorporating the message to stderr and + exits.""" + self.print_usage(sys.stderr) + self.exit( + 2, + dedent( + f''' + error: + {message} + + For more information: + - Try running {self.prog} --help + - Or visiting https://httpie.io/docs/cli + ''' + ) + ) diff --git a/tests/test_cli_ui.py b/tests/test_cli_ui.py new file mode 100644 index 0000000000..35faf37f3e --- /dev/null +++ b/tests/test_cli_ui.py @@ -0,0 +1,84 @@ +import pytest +import shutil +import os +import sys +from tests.utils import http + + +if sys.version_info >= (3, 9): + REQUEST_ITEM_MSG = "[REQUEST_ITEM ...]" +else: + REQUEST_ITEM_MSG = "[REQUEST_ITEM [REQUEST_ITEM ...]]" + + +NAKED_HELP_MESSAGE = f"""\ +usage: + http [METHOD] URL {REQUEST_ITEM_MSG} + +error: + the following arguments are required: URL + +For more information: + - Try running http --help + - Or visiting https://httpie.io/docs/cli + +""" + +NAKED_HELP_MESSAGE_PRETTY_WITH_NO_ARG = f"""\ +usage: + http [--pretty {{all,colors,format,none}}] [METHOD] URL {REQUEST_ITEM_MSG} + +error: + argument --pretty: expected one argument + +For more information: + - Try running http --help + - Or visiting https://httpie.io/docs/cli + +""" + +NAKED_HELP_MESSAGE_PRETTY_WITH_INVALID_ARG = f"""\ +usage: + http [--pretty {{all,colors,format,none}}] [METHOD] URL {REQUEST_ITEM_MSG} + +error: + argument --pretty: invalid choice: '$invalid' (choose from 'all', 'colors', 'format', 'none') + +For more information: + - Try running http --help + - Or visiting https://httpie.io/docs/cli + +""" + + +PREDEFINED_TERMINAL_SIZE = (160, 80) + + +@pytest.fixture(scope="function") +def ignore_terminal_size(monkeypatch): + """Some tests wrap/crop the output depending on the + size of the executed terminal, which might not be consistent + through all runs. + + This fixture ensures every run uses the same exact configuration. + """ + + def fake_terminal_size(*args, **kwargs): + return os.terminal_size(PREDEFINED_TERMINAL_SIZE) + + # Setting COLUMNS as an env var is required for 3.8< + monkeypatch.setitem(os.environ, 'COLUMNS', str(PREDEFINED_TERMINAL_SIZE[0])) + monkeypatch.setattr(shutil, 'get_terminal_size', fake_terminal_size) + + +@pytest.mark.parametrize( + 'args, expected_msg', [ + ([], NAKED_HELP_MESSAGE), + (['--pretty'], NAKED_HELP_MESSAGE_PRETTY_WITH_NO_ARG), + (['pie.dev', '--pretty'], NAKED_HELP_MESSAGE_PRETTY_WITH_NO_ARG), + (['--pretty', '$invalid'], NAKED_HELP_MESSAGE_PRETTY_WITH_INVALID_ARG), + ] +) +def test_naked_invocation(ignore_terminal_size, args, expected_msg): + result = http(*args, tolerate_error_exit_status=True) + assert result.stderr == expected_msg From ec203b1face4fb7e606a60880b6e80b4051bc41c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 7 Mar 2022 16:52:04 +0100 Subject: [PATCH 1042/1182] Tweak compact help --- httpie/cli/argparser.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index c632774d5d..a312b8ba10 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -568,9 +568,8 @@ def error(self, message): error: {message} - For more information: - - Try running {self.prog} --help - - Or visiting https://httpie.io/docs/cli + for more information: + run '{self.prog} --help' or visit https://httpie.io/docs/cli ''' ) ) From b5623ccc8797312de60e4ca37dea249fa0a1ea39 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 7 Mar 2022 19:01:37 +0300 Subject: [PATCH 1043/1182] Fix the tests with the latest layout --- tests/test_cli_ui.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/test_cli_ui.py b/tests/test_cli_ui.py index 35faf37f3e..760077a47f 100644 --- a/tests/test_cli_ui.py +++ b/tests/test_cli_ui.py @@ -18,9 +18,8 @@ error: the following arguments are required: URL -For more information: - - Try running http --help - - Or visiting https://httpie.io/docs/cli +for more information: + run 'http --help' or visit https://httpie.io/docs/cli """ @@ -31,9 +30,8 @@ error: argument --pretty: expected one argument -For more information: - - Try running http --help - - Or visiting https://httpie.io/docs/cli +for more information: + run 'http --help' or visit https://httpie.io/docs/cli """ @@ -44,9 +42,8 @@ error: argument --pretty: invalid choice: '$invalid' (choose from 'all', 'colors', 'format', 'none') -For more information: - - Try running http --help - - Or visiting https://httpie.io/docs/cli +for more information: + run 'http --help' or visit https://httpie.io/docs/cli """ From 65ab7d5caaaf2f95e61f9dd65441801c2ddee38b Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 1 Feb 2022 12:14:24 +0300 Subject: [PATCH 1044/1182] Implement new style cookies --- docs/README.md | 140 ++++++++++ httpie/client.py | 6 +- httpie/config.py | 60 ++-- httpie/manager/cli.py | 43 ++- httpie/manager/core.py | 11 + httpie/manager/tasks.py | 134 +++++++++ httpie/sessions.py | 206 +++++++++++--- httpie/utils.py | 5 + setup.py | 1 + tests/conftest.py | 6 +- tests/fixtures/__init__.py | 24 ++ .../session_data/new/cookies_dict.json | 31 +++ .../new/cookies_dict_dev_version.json | 31 +++ .../new/cookies_dict_with_extras.json | 33 +++ .../session_data/new/empty_cookies_dict.json | 14 + .../session_data/new/empty_cookies_list.json | 14 + .../session_data/old/cookies_dict.json | 27 ++ .../old/cookies_dict_dev_version.json | 27 ++ .../old/cookies_dict_with_extras.json | 29 ++ .../session_data/old/empty_cookies_dict.json | 14 + .../session_data/old/empty_cookies_list.json | 14 + tests/test_cookie_on_redirects.py | 262 ++++++++++++++++++ tests/test_httpie_cli.py | 125 +++++++++ tests/test_plugins_cli.py | 43 --- tests/test_sessions.py | 186 ++++++++++++- tests/utils/__init__.py | 24 +- tests/utils/http_server.py | 13 + 27 files changed, 1406 insertions(+), 117 deletions(-) create mode 100644 httpie/manager/tasks.py create mode 100644 tests/fixtures/session_data/new/cookies_dict.json create mode 100644 tests/fixtures/session_data/new/cookies_dict_dev_version.json create mode 100644 tests/fixtures/session_data/new/cookies_dict_with_extras.json create mode 100644 tests/fixtures/session_data/new/empty_cookies_dict.json create mode 100644 tests/fixtures/session_data/new/empty_cookies_list.json create mode 100644 tests/fixtures/session_data/old/cookies_dict.json create mode 100644 tests/fixtures/session_data/old/cookies_dict_dev_version.json create mode 100644 tests/fixtures/session_data/old/cookies_dict_with_extras.json create mode 100644 tests/fixtures/session_data/old/empty_cookies_dict.json create mode 100644 tests/fixtures/session_data/old/empty_cookies_list.json create mode 100644 tests/test_cookie_on_redirects.py create mode 100644 tests/test_httpie_cli.py diff --git a/docs/README.md b/docs/README.md index 00aff4b842..efd579a343 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2157,6 +2157,85 @@ $ http --session-read-only=./ro-session.json pie.dev/headers Custom-Header:orig- $ http --session-read-only=./ro-session.json pie.dev/headers Custom-Header:new-value ``` +### Host-based Cookie Policy + +Cookies in stored HTTPie sessions have a `domain` field which is binding them to the +specified hostname. For example, in the following session: + +```json +{ + "cookies": [ + { + "domain": "pie.dev", + "name": "secret_cookie", + "value": "value_1" + }, + { + "domain": "httpbin.org", + "name": "secret_cookie", + "value": "value_2" + } + ] +} +``` + +we will send `Cookie:secret_cookie=value_1` only when you are making a request against `pie.dev` (it +also includes the domains, like `api.pie.dev`), and `Cookie:secret_cookie=value_2` when you use `httpbin.org`. + +```bash +$ http --session=./session.json pie.dev/cookies +``` + +```json +{ + "cookies": { + "secret_cookie": "value_1" + } +} +``` + +```bash +$ http --session=./session.json httpbin.org/cookies +``` + +```json +{ + "cookies": { + "secret_cookie": "value_2" + } +} +``` + +If you want to make a cookie domain unbound, you can simply set the `domain` +field to `null` by editing the session file directly: + +```json +{ + "cookies": [ + { + "domain": null, + "expires": null, + "name": "generic_cookie", + "path": "/", + "secure": false, + "value": "generic_value" + } + ] +} +``` + +```bash +$ http --session=./session.json pie.dev/cookies +``` + +```json +{ + "cookies": { + "generic_cookie": "generic_value" + } +} +``` + ### Cookie Storage Behavior **TL;DR:** Cookie storage priority: Server response > Command line request > Session file @@ -2208,6 +2287,50 @@ Expired cookies are never stored. If a cookie in a session file expires, it will be removed before sending a new request. If the server expires an existing cookie, it will also be removed from the session file. +### Upgrading Sessions + +In rare circumstances, HTTPie makes changes in it's session layout. For allowing a smoother transition of existing files +from the old layout to the new layout we offer 2 interfaces: + +- `httpie cli sessions upgrade` +- `httpie cli sessions upgrade-all` + + +With `httpie cli sessions upgrade`, you can upgrade a single session with it's name (or it's path, if it is an +[anonymous session](#anonymous-sessions)) and the hostname it belongs to. For example: + +([named session](#named-sessions)) + +```bash +$ httpie cli sessions upgrade pie.dev api_auth +Refactored 'api_auth' (for 'pie.dev') to the version 3.1.0. +``` + +([anonymous session](#anonymous-sessions)) + +```bash +$ httpie cli sessions upgrade pie.dev ./session.json +Refactored 'session' (for 'pie.dev') to the version 3.1.0. +``` + +If you want to upgrade every existing [named session](#named-sessions), you can use `httpie cli sessions upgrade-all` (be aware +that this won't upgrade [anonymous sessions](#anonymous-sessions)): + +```bash +$ httpie cli sessions upgrade-all +Refactored 'api_auth' (for 'pie.dev') to the version 3.1.0. +Refactored 'login_cookies' (for 'httpie.io') to the version 3.1.0. +``` + +#### Additional Customizations + +| Flag | Description | +|------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `--bind-cookies` | Bind all the unbound cookies to the hostname that session belongs. By default, if the cookie is unbound (the `domain` attribute does not exist / set to an empty string) then it will still continue to be a generic cookie. | + +These flags can be used to customize the defaults during an `upgrade` operation. They can +be used in both `sessions upgrade` and `sessions upgrade-all`. + ## Config HTTPie uses a simple `config.json` file. @@ -2299,6 +2422,23 @@ And since there’s neither data nor `EOF`, it will get stuck. So unless you’r Also, it might be good to set a connection `--timeout` limit to prevent your program from hanging if the server never responds. +### Security + +#### Exposure of Cookies To The 3rd Party Hosts On Redirects + +*Vulnerability Type*: [CWE-200](https://cwe.mitre.org/data/definitions/200.html) +*Severity Level*: LOW +*Affected Versions*: `<3.1.0` + +The handling of [cookies](#cookies) was not compatible with the [RFC 6265](https://datatracker.ietf.org/doc/html/rfc6265) +on the point of handling the `Domain` attribute when they were saved into [session](#sessions) files. All cookies were shared +across all hosts during the runtime, including redirects to the 3rd party hosts. + +This vulnerability has been fixed in [3.1.0](https://github.com/httpie/httpie/releases/tag/3.1.0) and the +[`httpie cli sessions upgrade`](#upgrading-sessions)/[`httpie cli sessions upgrade-all`]((#upgrading-sessions) commands +have been put in place in order to allow a smooth transition to the new session layout from the existing [session](#sessions) +files. + ## Plugin manager HTTPie offers extensibility through a [plugin API](https://github.com/httpie/httpie/blob/master/httpie/plugins/base.py), diff --git a/httpie/client.py b/httpie/client.py index 1984537c2b..530d589cae 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -44,6 +44,7 @@ def collect_messages( httpie_session_headers = None if args.session or args.session_read_only: httpie_session = get_httpie_session( + env=env, config_dir=env.config.directory, session_name=args.session or args.session_read_only, host=args.headers.get('Host'), @@ -130,10 +131,7 @@ def collect_messages( if httpie_session: if httpie_session.is_new() or not args.session_read_only: httpie_session.cookies = requests_session.cookies - httpie_session.remove_cookies( - # TODO: take path & domain into account? - cookie['name'] for cookie in expired_cookies - ) + httpie_session.remove_cookies(expired_cookies) httpie_session.save() diff --git a/httpie/config.py b/httpie/config.py index 28574e4ae7..f7fee5bdab 100644 --- a/httpie/config.py +++ b/httpie/config.py @@ -1,7 +1,7 @@ import json import os from pathlib import Path -from typing import Union +from typing import Any, Dict, Union from . import __version__ from .compat import is_windows @@ -62,6 +62,21 @@ class ConfigFileError(Exception): pass +def read_raw_config(config_type: str, path: Path) -> Dict[str, Any]: + try: + with path.open(encoding=UTF8) as f: + try: + return json.load(f) + except ValueError as e: + raise ConfigFileError( + f'invalid {config_type} file: {e} [{path}]' + ) + except FileNotFoundError: + pass + except OSError as e: + raise ConfigFileError(f'cannot read {config_type} file: {e}') + + class BaseConfigDict(dict): name = None helpurl = None @@ -77,26 +92,25 @@ def ensure_directory(self): def is_new(self) -> bool: return not self.path.exists() + def pre_process_data(self, data: Dict[str, Any]) -> Dict[str, Any]: + """Hook for processing the incoming config data.""" + return data + + def post_process_data(self, data: Dict[str, Any]) -> Dict[str, Any]: + """Hook for processing the outgoing config data.""" + return data + def load(self): config_type = type(self).__name__.lower() - try: - with self.path.open(encoding=UTF8) as f: - try: - data = json.load(f) - except ValueError as e: - raise ConfigFileError( - f'invalid {config_type} file: {e} [{self.path}]' - ) - self.update(data) - except FileNotFoundError: - pass - except OSError as e: - raise ConfigFileError(f'cannot read {config_type} file: {e}') - - def save(self): - self['__meta__'] = { - 'httpie': __version__ - } + data = read_raw_config(config_type, self.path) + if data is not None: + data = self.pre_process_data(data) + self.update(data) + + def save(self, *, bump_version: bool = False): + self.setdefault('__meta__', {}) + if bump_version or 'httpie' not in self['__meta__']: + self['__meta__']['httpie'] = __version__ if self.helpurl: self['__meta__']['help'] = self.helpurl @@ -106,13 +120,19 @@ def save(self): self.ensure_directory() json_string = json.dumps( - obj=self, + obj=self.post_process_data(self), indent=4, sort_keys=True, ensure_ascii=True, ) self.path.write_text(json_string + '\n', encoding=UTF8) + @property + def version(self): + return self.get( + '__meta__', {} + ).get('httpie', __version__) + class Config(BaseConfigDict): FILENAME = 'config.json' diff --git a/httpie/manager/cli.py b/httpie/manager/cli.py index 11c63d0a31..9ad4eca6ba 100644 --- a/httpie/manager/cli.py +++ b/httpie/manager/cli.py @@ -2,6 +2,15 @@ from httpie.cli.argparser import HTTPieManagerArgumentParser from httpie import __version__ +CLI_SESSION_UPGRADE_FLAGS = [ + { + 'variadic': ['--bind-cookies'], + 'action': 'store_true', + 'default': False, + 'help': 'Bind domainless cookies to the host that session belongs.' + } +] + COMMANDS = { 'plugins': { 'help': 'Manage HTTPie plugins.', @@ -34,6 +43,34 @@ 'List all installed HTTPie plugins.' ], }, + 'cli': { + 'help': 'Manage HTTPie for Terminal', + 'sessions': { + 'help': 'Manage HTTPie sessions', + 'upgrade': [ + 'Upgrade the given HTTPie session with the latest ' + 'layout. A list of changes between different session versions ' + 'can be found in the official documentation.', + { + 'dest': 'hostname', + 'metavar': 'HOSTNAME', + 'help': 'The host this session belongs.' + }, + { + 'dest': 'session', + 'metavar': 'SESSION_NAME_OR_PATH', + 'help': 'The name or the path for the session that will be upgraded.' + }, + *CLI_SESSION_UPGRADE_FLAGS + ], + 'upgrade-all': [ + 'Upgrade all named sessions with the latest layout. A list of ' + 'changes between different session versions can be found in the official ' + 'documentation.', + *CLI_SESSION_UPGRADE_FLAGS + ], + } + } } @@ -54,6 +91,8 @@ def generate_subparsers(root, parent_parser, definitions): ) for command, properties in definitions.items(): is_subparser = isinstance(properties, dict) + properties = properties.copy() + descr = properties.pop('help', None) if is_subparser else properties.pop(0) command_parser = actions.add_parser(command, description=descr) command_parser.root = root @@ -62,7 +101,9 @@ def generate_subparsers(root, parent_parser, definitions): continue for argument in properties: - command_parser.add_argument(**argument) + argument = argument.copy() + variadic = argument.pop('variadic', []) + command_parser.add_argument(*variadic, **argument) parser = HTTPieManagerArgumentParser( diff --git a/httpie/manager/core.py b/httpie/manager/core.py index e2134b5527..1289fef1a4 100644 --- a/httpie/manager/core.py +++ b/httpie/manager/core.py @@ -1,9 +1,11 @@ import argparse +from typing import Optional from httpie.context import Environment from httpie.manager.plugins import PluginInstaller from httpie.status import ExitStatus from httpie.manager.cli import missing_subcommand, parser +from httpie.manager.tasks import CLI_TASKS MSG_COMMAND_CONFUSION = '''\ This command is only for managing HTTPie plugins. @@ -22,6 +24,13 @@ '''.rstrip("\n").format(args='POST pie.dev/post hello=world') +def dispatch_cli_task(env: Environment, action: Optional[str], args: argparse.Namespace) -> ExitStatus: + if action is None: + parser.error(missing_subcommand('cli')) + + return CLI_TASKS[action](env, args) + + def program(args: argparse.Namespace, env: Environment) -> ExitStatus: if args.action is None: parser.error(MSG_NAKED_INVOCATION) @@ -29,5 +38,7 @@ def program(args: argparse.Namespace, env: Environment) -> ExitStatus: if args.action == 'plugins': plugins = PluginInstaller(env, debug=args.debug) return plugins.run(args.plugins_action, args) + elif args.action == 'cli': + return dispatch_cli_task(env, args.cli_action, args) return ExitStatus.SUCCESS diff --git a/httpie/manager/tasks.py b/httpie/manager/tasks.py new file mode 100644 index 0000000000..c04ed9bc3d --- /dev/null +++ b/httpie/manager/tasks.py @@ -0,0 +1,134 @@ +import argparse +from typing import TypeVar, Callable, Tuple + +from httpie.sessions import SESSIONS_DIR_NAME, Session, get_httpie_session +from httpie.status import ExitStatus +from httpie.context import Environment +from httpie.manager.cli import missing_subcommand, parser + +T = TypeVar('T') + +CLI_TASKS = {} + + +def task(name: str) -> Callable[[T], T]: + def wrapper(func: T) -> T: + CLI_TASKS[name] = func + return func + return wrapper + + +@task('sessions') +def cli_sessions(env: Environment, args: argparse.Namespace) -> ExitStatus: + action = args.cli_sessions_action + if action is None: + parser.error(missing_subcommand('cli', 'sessions')) + + if action == 'upgrade': + return cli_upgrade_session(env, args) + elif action == 'upgrade-all': + return cli_upgrade_all_sessions(env, args) + else: + raise ValueError(f'Unexpected action: {action}') + + +def is_version_greater(version_1: str, version_2: str) -> bool: + # In an ideal scenerio, we would depend on `packaging` in order + # to offer PEP 440 compatible parsing. But since it might not be + # commonly available for outside packages, and since we are only + # going to parse HTTPie's own version it should be fine to compare + # this in a SemVer subset fashion. + + def split_version(version: str) -> Tuple[int, ...]: + parts = [] + for part in version.split('.')[:3]: + try: + parts.append(int(part)) + except ValueError: + break + return tuple(parts) + + return split_version(version_1) > split_version(version_2) + + +def fix_cookie_layout(session: Session, hostname: str, args: argparse.Namespace) -> None: + if not isinstance(session['cookies'], dict): + return None + + session['cookies'] = [ + { + 'name': key, + **value + } + for key, value in session['cookies'].items() + ] + for cookie in session.cookies: + if cookie.domain == '': + if args.bind_cookies: + cookie.domain = hostname + else: + cookie._rest['is_explicit_none'] = True + + +FIXERS_TO_VERSIONS = { + '3.1.0': fix_cookie_layout +} + + +def upgrade_session(env: Environment, args: argparse.Namespace, hostname: str, session_name: str): + session = get_httpie_session( + env=env, + config_dir=env.config.directory, + session_name=session_name, + host=hostname, + url=hostname, + refactor_mode=True + ) + + session_name = session.path.stem + if session.is_new(): + env.log_error(f'{session_name!r} (for {hostname!r}) does not exist.') + return ExitStatus.ERROR + + fixers = [ + fixer + for version, fixer in FIXERS_TO_VERSIONS.items() + if is_version_greater(version, session.version) + ] + + if len(fixers) == 0: + env.stdout.write(f'{session_name!r} (for {hostname!r}) is already up-to-date.\n') + return ExitStatus.SUCCESS + + for fixer in fixers: + fixer(session, hostname, args) + + session.save(bump_version=True) + env.stdout.write(f'Refactored {session_name!r} (for {hostname!r}) to the version {session.version}.\n') + return ExitStatus.SUCCESS + + +def cli_upgrade_session(env: Environment, args: argparse.Namespace) -> ExitStatus: + return upgrade_session( + env, + args=args, + hostname=args.hostname, + session_name=args.session + ) + + +def cli_upgrade_all_sessions(env: Environment, args: argparse.Namespace) -> ExitStatus: + session_dir_path = env.config_dir / SESSIONS_DIR_NAME + + status = ExitStatus.SUCCESS + for host_path in session_dir_path.iterdir(): + hostname = host_path.name + for session_path in host_path.glob("*.json"): + session_name = session_path.stem + status |= upgrade_session( + env, + args=args, + hostname=hostname, + session_name=session_name + ) + return status diff --git a/httpie/sessions.py b/httpie/sessions.py index 176c03e76d..c23cb56852 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -6,15 +6,17 @@ import re from http.cookies import SimpleCookie +from http.cookiejar import Cookie from pathlib import Path -from typing import Iterable, Optional, Union -from urllib.parse import urlsplit +from typing import Any, Dict, Optional, Union from requests.auth import AuthBase -from requests.cookies import RequestsCookieJar, create_cookie +from requests.cookies import RequestsCookieJar, remove_cookie_by_name +from .context import Environment from .cli.dicts import HTTPHeadersDict from .config import BaseConfigDict, DEFAULT_CONFIG_DIR +from .utils import url_as_host from .plugins.registry import plugin_manager @@ -26,27 +28,88 @@ # SESSION_IGNORED_HEADER_PREFIXES = ['Content-', 'If-'] +# Cookie related options +KEPT_COOKIE_OPTIONS = ['name', 'expires', 'path', 'value', 'domain', 'secure'] +DEFAULT_COOKIE_PATH = '/' + +INSECURE_COOKIE_JAR_WARNING = '''\ +Outdated layout detected for the current session. Please consider updating it, +in order to not get affected by potential security problems. + +For fixing the current session: + + With binding all cookies to the current host (secure): + $ httpie cli sessions upgrade --bind-cookies {hostname} {session_id} + + Without binding cookies (leaving them as is) (insecure): + $ httpie cli sessions upgrade {hostname} {session_id} +''' + +INSECURE_COOKIE_JAR_WARNING_FOR_NAMED_SESSIONS = '''\ + +For fixing all named sessions: + + With binding all cookies to the current host (secure): + $ httpie cli sessions upgrade-all --bind-cookies + + Without binding cookies (leaving them as is) (insecure): + $ httpie cli sessions upgrade-all + +See https://pie.co/docs/security for more information. +''' + + +def is_anonymous_session(session_name: str) -> bool: + return os.path.sep in session_name + + +def materialize_cookie(cookie: Cookie) -> Dict[str, Any]: + materialized_cookie = { + option: getattr(cookie, option) + for option in KEPT_COOKIE_OPTIONS + } + + if ( + cookie._rest.get('is_explicit_none') + and materialized_cookie['domain'] == '' + ): + materialized_cookie['domain'] = None + + return materialized_cookie + def get_httpie_session( + env: Environment, config_dir: Path, session_name: str, host: Optional[str], url: str, + *, + refactor_mode: bool = False ) -> 'Session': - if os.path.sep in session_name: + bound_hostname = host or url_as_host(url) + if not bound_hostname: + # HACK/FIXME: httpie-unixsocket's URLs have no hostname. + bound_hostname = 'localhost' + + # host:port => host_port + hostname = bound_hostname.replace(':', '_') + if is_anonymous_session(session_name): path = os.path.expanduser(session_name) + session_id = path else: - hostname = host or urlsplit(url).netloc.split('@')[-1] - if not hostname: - # HACK/FIXME: httpie-unixsocket's URLs have no hostname. - hostname = 'localhost' - - # host:port => host_port - hostname = hostname.replace(':', '_') path = ( config_dir / SESSIONS_DIR_NAME / hostname / f'{session_name}.json' ) - session = Session(path) + session_id = session_name + + session = Session( + path, + env=env, + session_id=session_id, + bound_host=bound_hostname.split(':')[0], + refactor_mode=refactor_mode + ) session.load() return session @@ -55,15 +118,86 @@ class Session(BaseConfigDict): helpurl = 'https://httpie.io/docs#sessions' about = 'HTTPie session file' - def __init__(self, path: Union[str, Path]): + def __init__( + self, + path: Union[str, Path], + env: Environment, + bound_host: str, + session_id: str, + refactor_mode: bool = False, + ): super().__init__(path=Path(path)) self['headers'] = {} - self['cookies'] = {} + self['cookies'] = [] self['auth'] = { 'type': None, 'username': None, 'password': None } + self.env = env + self.cookie_jar = RequestsCookieJar() + self.session_id = session_id + self.bound_host = bound_host + self.refactor_mode = refactor_mode + + def pre_process_data(self, data: Dict[str, Any]) -> Dict[str, Any]: + cookies = data.get('cookies') + if isinstance(cookies, dict): + normalized_cookies = [ + { + 'name': key, + **value + } + for key, value in cookies.items() + ] + elif isinstance(cookies, list): + normalized_cookies = cookies + else: + normalized_cookies = [] + + should_issue_warning = False + for cookie in normalized_cookies: + domain = cookie.get('domain', '') + if domain == '' and isinstance(cookies, dict): + should_issue_warning = True + elif domain is None: + # domain = None means explicitly lack of cookie, though + # requests requires domain to be string so we'll cast it + # manually. + cookie['domain'] = '' + cookie['rest'] = {'is_explicit_none': True} + + self.cookie_jar.set(**cookie) + + if should_issue_warning and not self.refactor_mode: + warning = INSECURE_COOKIE_JAR_WARNING.format(hostname=self.bound_host, session_id=self.session_id) + if not is_anonymous_session(self.session_id): + warning += INSECURE_COOKIE_JAR_WARNING_FOR_NAMED_SESSIONS + + self.env.log_error( + warning, + level='warning' + ) + + return data + + def post_process_data(self, data: Dict[str, Any]) -> Dict[str, Any]: + cookies = data.get('cookies') + # Save in the old-style fashion + + normalized_cookies = [ + materialize_cookie(cookie) + for cookie in self.cookie_jar + ] + if isinstance(cookies, dict): + data['cookies'] = { + cookie.pop('name'): cookie + for cookie in normalized_cookies + } + else: + data['cookies'] = normalized_cookies + + return data def update_headers(self, request_headers: HTTPHeadersDict): """ @@ -73,10 +207,10 @@ def update_headers(self, request_headers: HTTPHeadersDict): """ headers = self.headers for name, value in request_headers.copy().items(): - if value is None: continue # Ignore explicitly unset headers + original_value = value if type(value) is not str: value = value.decode() @@ -85,8 +219,15 @@ def update_headers(self, request_headers: HTTPHeadersDict): if name.lower() == 'cookie': for cookie_name, morsel in SimpleCookie(value).items(): - self['cookies'][cookie_name] = {'value': morsel.value} - del request_headers[name] + if not morsel['path']: + morsel['path'] = DEFAULT_COOKIE_PATH + self.cookie_jar.set(cookie_name, morsel) + + all_cookie_headers = request_headers.getall(name) + if len(all_cookie_headers) > 1: + all_cookie_headers.remove(original_value) + else: + request_headers.popall(name) continue for prefix in SESSION_IGNORED_HEADER_PREFIXES: @@ -103,23 +244,21 @@ def headers(self) -> HTTPHeadersDict: @property def cookies(self) -> RequestsCookieJar: - jar = RequestsCookieJar() - for name, cookie_dict in self['cookies'].items(): - jar.set_cookie(create_cookie( - name, cookie_dict.pop('value'), **cookie_dict)) - jar.clear_expired_cookies() - return jar + self.cookie_jar.clear_expired_cookies() + return self.cookie_jar @cookies.setter def cookies(self, jar: RequestsCookieJar): - # - stored_attrs = ['value', 'path', 'secure', 'expires'] - self['cookies'] = {} - for cookie in jar: - self['cookies'][cookie.name] = { - attname: getattr(cookie, attname) - for attname in stored_attrs - } + self.cookie_jar = jar + + def remove_cookies(self, cookies: Dict[str, str]): + for cookie in cookies: + remove_cookie_by_name( + self.cookie_jar, + cookie['name'], + domain=cookie.get('domain', None), + path=cookie.get('path', None) + ) @property def auth(self) -> Optional[AuthBase]: @@ -154,8 +293,3 @@ def auth(self) -> Optional[AuthBase]: def auth(self, auth: dict): assert {'type', 'raw_auth'} == auth.keys() self['auth'] = auth - - def remove_cookies(self, names: Iterable[str]): - for name in names: - if name in self['cookies']: - del self['cookies'][name] diff --git a/httpie/utils.py b/httpie/utils.py index fa19fa7cde..4fffb2826e 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -9,6 +9,7 @@ from http.cookiejar import parse_ns_headers from pathlib import Path from pprint import pformat +from urllib.parse import urlsplit from typing import Any, List, Optional, Tuple, Callable, Iterable, TypeVar import requests.auth @@ -237,3 +238,7 @@ def unwrap_context(exc: Exception) -> Optional[Exception]: return unwrap_context(context) else: return exc + + +def url_as_host(url: str) -> str: + return urlsplit(url).netloc.split('@')[-1] diff --git a/setup.py b/setup.py index 5316ff73d3..8f9a93140f 100644 --- a/setup.py +++ b/setup.py @@ -11,6 +11,7 @@ tests_require = [ 'pytest', 'pytest-httpbin>=0.0.6', + 'pytest-lazy-fixture>=0.0.6', 'responses', ] dev_require = [ diff --git a/tests/conftest.py b/tests/conftest.py index 5e8c511072..7ca0e60440 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,7 +4,11 @@ import pytest from pytest_httpbin import certs -from .utils import HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN, HTTPBIN_WITH_CHUNKED_SUPPORT +from .utils import ( # noqa + HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN, + HTTPBIN_WITH_CHUNKED_SUPPORT, + mock_env +) from .utils.plugins_cli import ( # noqa broken_plugin, dummy_plugin, diff --git a/tests/fixtures/__init__.py b/tests/fixtures/__init__.py index 126b13276e..6e6e73676e 100644 --- a/tests/fixtures/__init__.py +++ b/tests/fixtures/__init__.py @@ -1,6 +1,9 @@ """Test data""" +import json from pathlib import Path +from typing import Optional, Dict, Any +import httpie from httpie.encoding import UTF8 from httpie.output.formatters.xml import pretty_xml, parse_xml @@ -19,10 +22,20 @@ def patharg(path): JSON_FILE_PATH = FIXTURES_ROOT / 'test.json' JSON_WITH_DUPE_KEYS_FILE_PATH = FIXTURES_ROOT / 'test_with_dupe_keys.json' BIN_FILE_PATH = FIXTURES_ROOT / 'test.bin' + XML_FILES_PATH = FIXTURES_ROOT / 'xmldata' XML_FILES_VALID = list((XML_FILES_PATH / 'valid').glob('*_raw.xml')) XML_FILES_INVALID = list((XML_FILES_PATH / 'invalid').glob('*.xml')) +SESSION_FILES_PATH = FIXTURES_ROOT / 'session_data' +SESSION_FILES_OLD = sorted((SESSION_FILES_PATH / 'old').glob('*.json')) +SESSION_FILES_NEW = sorted((SESSION_FILES_PATH / 'new').glob('*.json')) + +SESSION_VARIABLES = { + '__version__': httpie.__version__, + '__host__': 'null', +} + FILE_PATH_ARG = patharg(FILE_PATH) BIN_FILE_PATH_ARG = patharg(BIN_FILE_PATH) JSON_FILE_PATH_ARG = patharg(JSON_FILE_PATH) @@ -40,3 +53,14 @@ def patharg(path): UNICODE = FILE_CONTENT XML_DATA_RAW = 'text' XML_DATA_FORMATTED = pretty_xml(parse_xml(XML_DATA_RAW)) + + +def read_session_file(session_file: Path, *, extra_variables: Optional[Dict[str, str]] = None) -> Any: + with open(session_file) as stream: + data = stream.read() + + session_vars = {**SESSION_VARIABLES, **(extra_variables or {})} + for variable, value in session_vars.items(): + data = data.replace(variable, value) + + return json.loads(data) diff --git a/tests/fixtures/session_data/new/cookies_dict.json b/tests/fixtures/session_data/new/cookies_dict.json new file mode 100644 index 0000000000..8a4d5f2e13 --- /dev/null +++ b/tests/fixtures/session_data/new/cookies_dict.json @@ -0,0 +1,31 @@ +{ + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.io/docs#sessions", + "httpie": "__version__" + }, + "auth": { + "password": null, + "type": null, + "username": null + }, + "cookies": [ + { + "domain": __host__, + "expires": null, + "name": "baz", + "path": "/", + "secure": false, + "value": "quux" + }, + { + "domain": __host__, + "expires": null, + "name": "foo", + "path": "/", + "secure": false, + "value": "bar" + } + ], + "headers": {} +} diff --git a/tests/fixtures/session_data/new/cookies_dict_dev_version.json b/tests/fixtures/session_data/new/cookies_dict_dev_version.json new file mode 100644 index 0000000000..8a4d5f2e13 --- /dev/null +++ b/tests/fixtures/session_data/new/cookies_dict_dev_version.json @@ -0,0 +1,31 @@ +{ + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.io/docs#sessions", + "httpie": "__version__" + }, + "auth": { + "password": null, + "type": null, + "username": null + }, + "cookies": [ + { + "domain": __host__, + "expires": null, + "name": "baz", + "path": "/", + "secure": false, + "value": "quux" + }, + { + "domain": __host__, + "expires": null, + "name": "foo", + "path": "/", + "secure": false, + "value": "bar" + } + ], + "headers": {} +} diff --git a/tests/fixtures/session_data/new/cookies_dict_with_extras.json b/tests/fixtures/session_data/new/cookies_dict_with_extras.json new file mode 100644 index 0000000000..9a99f15268 --- /dev/null +++ b/tests/fixtures/session_data/new/cookies_dict_with_extras.json @@ -0,0 +1,33 @@ +{ + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.io/docs#sessions", + "httpie": "__version__" + }, + "auth": { + "raw_auth": "foo:bar", + "type": "basic" + }, + "cookies": [ + { + "domain": __host__, + "expires": null, + "name": "baz", + "path": "/", + "secure": false, + "value": "quux" + }, + { + "domain": __host__, + "expires": null, + "name": "foo", + "path": "/", + "secure": false, + "value": "bar" + } + ], + "headers": { + "X-Data": "value", + "X-Foo": "bar" + } +} diff --git a/tests/fixtures/session_data/new/empty_cookies_dict.json b/tests/fixtures/session_data/new/empty_cookies_dict.json new file mode 100644 index 0000000000..1d01661a06 --- /dev/null +++ b/tests/fixtures/session_data/new/empty_cookies_dict.json @@ -0,0 +1,14 @@ +{ + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.io/docs#sessions", + "httpie": "__version__" + }, + "auth": { + "password": null, + "type": null, + "username": null + }, + "cookies": [], + "headers": {} +} diff --git a/tests/fixtures/session_data/new/empty_cookies_list.json b/tests/fixtures/session_data/new/empty_cookies_list.json new file mode 100644 index 0000000000..1d01661a06 --- /dev/null +++ b/tests/fixtures/session_data/new/empty_cookies_list.json @@ -0,0 +1,14 @@ +{ + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.io/docs#sessions", + "httpie": "__version__" + }, + "auth": { + "password": null, + "type": null, + "username": null + }, + "cookies": [], + "headers": {} +} diff --git a/tests/fixtures/session_data/old/cookies_dict.json b/tests/fixtures/session_data/old/cookies_dict.json new file mode 100644 index 0000000000..9c4fd21476 --- /dev/null +++ b/tests/fixtures/session_data/old/cookies_dict.json @@ -0,0 +1,27 @@ +{ + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.io/docs#sessions", + "httpie": "3.0.2" + }, + "auth": { + "password": null, + "type": null, + "username": null + }, + "cookies": { + "baz": { + "expires": null, + "path": "/", + "secure": false, + "value": "quux" + }, + "foo": { + "expires": null, + "path": "/", + "secure": false, + "value": "bar" + } + }, + "headers": {} +} diff --git a/tests/fixtures/session_data/old/cookies_dict_dev_version.json b/tests/fixtures/session_data/old/cookies_dict_dev_version.json new file mode 100644 index 0000000000..935b43f083 --- /dev/null +++ b/tests/fixtures/session_data/old/cookies_dict_dev_version.json @@ -0,0 +1,27 @@ +{ + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.io/docs#sessions", + "httpie": "2.7.0.dev0" + }, + "auth": { + "password": null, + "type": null, + "username": null + }, + "cookies": { + "baz": { + "expires": null, + "path": "/", + "secure": false, + "value": "quux" + }, + "foo": { + "expires": null, + "path": "/", + "secure": false, + "value": "bar" + } + }, + "headers": {} +} diff --git a/tests/fixtures/session_data/old/cookies_dict_with_extras.json b/tests/fixtures/session_data/old/cookies_dict_with_extras.json new file mode 100644 index 0000000000..42968e52a9 --- /dev/null +++ b/tests/fixtures/session_data/old/cookies_dict_with_extras.json @@ -0,0 +1,29 @@ +{ + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.io/docs#sessions", + "httpie": "3.0.2" + }, + "auth": { + "raw_auth": "foo:bar", + "type": "basic" + }, + "cookies": { + "baz": { + "expires": null, + "path": "/", + "secure": false, + "value": "quux" + }, + "foo": { + "expires": null, + "path": "/", + "secure": false, + "value": "bar" + } + }, + "headers": { + "X-Data": "value", + "X-Foo": "bar" + } +} diff --git a/tests/fixtures/session_data/old/empty_cookies_dict.json b/tests/fixtures/session_data/old/empty_cookies_dict.json new file mode 100644 index 0000000000..8de1a9217c --- /dev/null +++ b/tests/fixtures/session_data/old/empty_cookies_dict.json @@ -0,0 +1,14 @@ +{ + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.io/docs#sessions", + "httpie": "3.0.2" + }, + "auth": { + "password": null, + "type": null, + "username": null + }, + "cookies": {}, + "headers": {} +} diff --git a/tests/fixtures/session_data/old/empty_cookies_list.json b/tests/fixtures/session_data/old/empty_cookies_list.json new file mode 100644 index 0000000000..12194f7ed2 --- /dev/null +++ b/tests/fixtures/session_data/old/empty_cookies_list.json @@ -0,0 +1,14 @@ +{ + "__meta__": { + "about": "HTTPie session file", + "help": "https://httpie.io/docs#sessions", + "httpie": "3.0.2" + }, + "auth": { + "password": null, + "type": null, + "username": null + }, + "cookies": [], + "headers": {} +} diff --git a/tests/test_cookie_on_redirects.py b/tests/test_cookie_on_redirects.py new file mode 100644 index 0000000000..e22f833048 --- /dev/null +++ b/tests/test_cookie_on_redirects.py @@ -0,0 +1,262 @@ +import pytest +from .utils import http + + +@pytest.fixture +def remote_httpbin(httpbin_with_chunked_support): + return httpbin_with_chunked_support + + +def _stringify(fixture): + return fixture + '' + + +@pytest.mark.parametrize('instance', [ + pytest.lazy_fixture('httpbin'), + pytest.lazy_fixture('remote_httpbin'), +]) +def test_explicit_user_set_cookie(httpbin, instance): + # User set cookies ARE NOT persisted within redirects + # when there is no session, even on the same domain. + + r = http( + '--follow', + httpbin + '/redirect-to', + f'url=={_stringify(instance)}/cookies', + 'Cookie:a=b' + ) + assert r.json == {'cookies': {}} + + +@pytest.mark.parametrize('instance', [ + pytest.lazy_fixture('httpbin'), + pytest.lazy_fixture('remote_httpbin'), +]) +def test_explicit_user_set_cookie_in_session(tmp_path, httpbin, instance): + # User set cookies ARE persisted within redirects + # when there is A session, even on the same domain. + + r = http( + '--follow', + '--session', + str(tmp_path / 'session.json'), + httpbin + '/redirect-to', + f'url=={_stringify(instance)}/cookies', + 'Cookie:a=b' + ) + assert r.json == {'cookies': {'a': 'b'}} + + +@pytest.mark.parametrize('instance', [ + pytest.lazy_fixture('httpbin'), + pytest.lazy_fixture('remote_httpbin'), +]) +def test_saved_user_set_cookie_in_session(tmp_path, httpbin, instance): + # User set cookies ARE persisted within redirects + # when there is A session, even on the same domain. + + http( + '--follow', + '--session', + str(tmp_path / 'session.json'), + httpbin + '/get', + 'Cookie:a=b' + ) + r = http( + '--follow', + '--session', + str(tmp_path / 'session.json'), + httpbin + '/redirect-to', + f'url=={_stringify(instance)}/cookies', + ) + assert r.json == {'cookies': {'a': 'b'}} + + +@pytest.mark.parametrize('instance', [ + pytest.lazy_fixture('httpbin'), + pytest.lazy_fixture('remote_httpbin'), +]) +@pytest.mark.parametrize('session', [True, False]) +def test_explicit_user_set_headers(httpbin, tmp_path, instance, session): + # User set headers ARE persisted within redirects + # even on different domains domain with or without + # an active session. + session_args = [] + if session: + session_args.extend([ + '--session', + str(tmp_path / 'session.json') + ]) + + r = http( + '--follow', + *session_args, + httpbin + '/redirect-to', + f'url=={_stringify(instance)}/get', + 'X-Custom-Header:value' + ) + assert 'X-Custom-Header' in r.json['headers'] + + +@pytest.mark.parametrize('session', [True, False]) +def test_server_set_cookie_on_redirect_same_domain(tmp_path, httpbin, session): + # Server set cookies ARE persisted on the same domain + # when they are forwarded. + + session_args = [] + if session: + session_args.extend([ + '--session', + str(tmp_path / 'session.json') + ]) + + r = http( + '--follow', + *session_args, + httpbin + '/cookies/set/a/b', + ) + assert r.json['cookies'] == {'a': 'b'} + + +@pytest.mark.parametrize('session', [True, False]) +def test_server_set_cookie_on_redirect_different_domain(tmp_path, http_server, httpbin, session): + # Server set cookies ARE persisted on different domains + # when they are forwarded. + + session_args = [] + if session: + session_args.extend([ + '--session', + str(tmp_path / 'session.json') + ]) + + r = http( + '--follow', + *session_args, + http_server + '/cookies/set-and-redirect', + f"X-Redirect-To:{httpbin + '/cookies'}", + 'X-Cookies:a=b' + ) + assert r.json['cookies'] == {'a': 'b'} + + +def test_saved_session_cookies_on_same_domain(tmp_path, httpbin): + # Saved session cookies ARE persisted when making a new + # request to the same domain. + http( + '--session', + str(tmp_path / 'session.json'), + httpbin + '/cookies/set/a/b' + ) + r = http( + '--session', + str(tmp_path / 'session.json'), + httpbin + '/cookies' + ) + assert r.json == {'cookies': {'a': 'b'}} + + +def test_saved_session_cookies_on_different_domain(tmp_path, httpbin, remote_httpbin): + # Saved session cookies ARE persisted when making a new + # request to a different domain. + http( + '--session', + str(tmp_path / 'session.json'), + httpbin + '/cookies/set/a/b' + ) + r = http( + '--session', + str(tmp_path / 'session.json'), + remote_httpbin + '/cookies' + ) + assert r.json == {'cookies': {}} + + +@pytest.mark.parametrize('initial_domain, first_request_domain, second_request_domain, expect_cookies', [ + ( + # Cookies are set by Domain A + # Initial domain is Domain A + # Redirected domain is Domain A + pytest.lazy_fixture('httpbin'), + pytest.lazy_fixture('httpbin'), + pytest.lazy_fixture('httpbin'), + True, + ), + ( + # Cookies are set by Domain A + # Initial domain is Domain B + # Redirected domain is Domain B + pytest.lazy_fixture('httpbin'), + pytest.lazy_fixture('remote_httpbin'), + pytest.lazy_fixture('remote_httpbin'), + False, + ), + ( + # Cookies are set by Domain A + # Initial domain is Domain A + # Redirected domain is Domain B + pytest.lazy_fixture('httpbin'), + pytest.lazy_fixture('httpbin'), + pytest.lazy_fixture('remote_httpbin'), + False, + ), + ( + # Cookies are set by Domain A + # Initial domain is Domain B + # Redirected domain is Domain A + pytest.lazy_fixture('httpbin'), + pytest.lazy_fixture('remote_httpbin'), + pytest.lazy_fixture('httpbin'), + True, + ), +]) +def test_saved_session_cookies_on_redirect(tmp_path, initial_domain, first_request_domain, second_request_domain, expect_cookies): + http( + '--session', + str(tmp_path / 'session.json'), + initial_domain + '/cookies/set/a/b' + ) + r = http( + '--session', + str(tmp_path / 'session.json'), + '--follow', + first_request_domain + '/redirect-to', + f'url=={_stringify(second_request_domain)}/cookies' + ) + if expect_cookies: + expected_data = {'cookies': {'a': 'b'}} + else: + expected_data = {'cookies': {}} + assert r.json == expected_data + + +def test_saved_session_cookie_pool(tmp_path, httpbin, remote_httpbin): + http( + '--session', + str(tmp_path / 'session.json'), + httpbin + '/cookies/set/a/b' + ) + http( + '--session', + str(tmp_path / 'session.json'), + remote_httpbin + '/cookies/set/a/c' + ) + http( + '--session', + str(tmp_path / 'session.json'), + remote_httpbin + '/cookies/set/b/d' + ) + + response = http( + '--session', + str(tmp_path / 'session.json'), + httpbin + '/cookies' + ) + assert response.json['cookies'] == {'a': 'b'} + + response = http( + '--session', + str(tmp_path / 'session.json'), + remote_httpbin + '/cookies' + ) + assert response.json['cookies'] == {'a': 'c', 'b': 'd'} diff --git a/tests/test_httpie_cli.py b/tests/test_httpie_cli.py new file mode 100644 index 0000000000..31c44d7f1f --- /dev/null +++ b/tests/test_httpie_cli.py @@ -0,0 +1,125 @@ +import pytest +import shutil +import json +from httpie.sessions import SESSIONS_DIR_NAME +from httpie.status import ExitStatus +from tests.utils import DUMMY_HOST, httpie +from tests.fixtures import SESSION_FILES_PATH, SESSION_FILES_NEW, SESSION_FILES_OLD, read_session_file + + +OLD_SESSION_FILES_PATH = SESSION_FILES_PATH / 'old' + + +@pytest.mark.requires_installation +def test_plugins_cli_error_message_without_args(): + # No arguments + result = httpie(no_debug=True) + assert result.exit_status == ExitStatus.ERROR + assert 'usage: ' in result.stderr + assert 'specify one of these' in result.stderr + assert 'please use the http/https commands:' in result.stderr + + +@pytest.mark.parametrize( + 'example', + [ + 'pie.dev/get', + 'DELETE localhost:8000/delete', + 'POST pie.dev/post header:value a=b header_2:value x:=1', + ], +) +@pytest.mark.requires_installation +def test_plugins_cli_error_messages_with_example(example): + result = httpie(*example.split(), no_debug=True) + assert result.exit_status == ExitStatus.ERROR + assert 'usage: ' in result.stderr + assert f'http {example}' in result.stderr + assert f'https {example}' in result.stderr + + +@pytest.mark.parametrize( + 'example', + [ + 'cli', + 'plugins', + 'cli foo', + 'plugins unknown', + 'plugins unknown.com A:B c=d', + 'unknown.com UNPARSABLE????SYNTAX', + ], +) +@pytest.mark.requires_installation +def test_plugins_cli_error_messages_invalid_example(example): + result = httpie(*example.split(), no_debug=True) + assert result.exit_status == ExitStatus.ERROR + assert 'usage: ' in result.stderr + assert f'http {example}' not in result.stderr + assert f'https {example}' not in result.stderr + + +HTTPIE_CLI_SESSIONS_UPGRADE_OPTIONS = [ + ( + # Default settings + [], + {'__host__': json.dumps(None)}, + ), + ( + # When --bind-cookies is applied, the __host__ becomes DUMMY_URL. + ['--bind-cookies'], + {'__host__': json.dumps(DUMMY_HOST)}, + ), +] + + +@pytest.mark.parametrize( + 'old_session_file, new_session_file', zip(SESSION_FILES_OLD, SESSION_FILES_NEW) +) +@pytest.mark.parametrize( + 'extra_args, extra_variables', + HTTPIE_CLI_SESSIONS_UPGRADE_OPTIONS, +) +def test_httpie_sessions_upgrade(tmp_path, old_session_file, new_session_file, extra_args, extra_variables): + session_path = tmp_path / 'session.json' + shutil.copyfile(old_session_file, session_path) + + result = httpie( + 'cli', 'sessions', 'upgrade', *extra_args, DUMMY_HOST, str(session_path) + ) + assert result.exit_status == ExitStatus.SUCCESS + assert read_session_file(session_path) == read_session_file( + new_session_file, extra_variables=extra_variables + ) + + +def test_httpie_sessions_upgrade_on_non_existent_file(tmp_path): + session_path = tmp_path / 'session.json' + result = httpie('cli', 'sessions', 'upgrade', DUMMY_HOST, str(session_path)) + assert result.exit_status == ExitStatus.ERROR + assert 'does not exist' in result.stderr + + +@pytest.mark.parametrize( + 'extra_args, extra_variables', + HTTPIE_CLI_SESSIONS_UPGRADE_OPTIONS, +) +def test_httpie_sessions_upgrade_all(tmp_path, mock_env, extra_args, extra_variables): + mock_env._create_temp_config_dir = False + mock_env.config_dir = tmp_path / "config" + + session_dir = mock_env.config_dir / SESSIONS_DIR_NAME / DUMMY_HOST + session_dir.mkdir(parents=True) + for original_session_file in SESSION_FILES_OLD: + shutil.copy(original_session_file, session_dir) + + result = httpie( + 'cli', 'sessions', 'upgrade-all', *extra_args, env=mock_env + ) + assert result.exit_status == ExitStatus.SUCCESS + + for refactored_session_file, expected_session_file in zip( + sorted(session_dir.glob("*.json")), + SESSION_FILES_NEW + ): + assert read_session_file(refactored_session_file) == read_session_file( + expected_session_file, extra_variables=extra_variables + ) diff --git a/tests/test_plugins_cli.py b/tests/test_plugins_cli.py index 9f94821505..70cecb1fb7 100644 --- a/tests/test_plugins_cli.py +++ b/tests/test_plugins_cli.py @@ -1,7 +1,6 @@ import pytest from httpie.status import ExitStatus -from tests.utils import httpie from tests.utils.plugins_cli import parse_listing @@ -149,45 +148,3 @@ def test_broken_plugins(httpie_plugins, httpie_plugins_success, dummy_plugin, br # No warning now, since it is uninstalled. data = parse_listing(httpie_plugins_success('list')) assert len(data) == 1 - - -@pytest.mark.requires_installation -def test_plugins_cli_error_message_without_args(): - # No arguments - result = httpie(no_debug=True) - assert result.exit_status == ExitStatus.ERROR - assert 'usage: ' in result.stderr - assert 'specify one of these' in result.stderr - assert 'please use the http/https commands:' in result.stderr - - -@pytest.mark.parametrize( - 'example', [ - 'pie.dev/get', - 'DELETE localhost:8000/delete', - 'POST pie.dev/post header:value a=b header_2:value x:=1' - ] -) -@pytest.mark.requires_installation -def test_plugins_cli_error_messages_with_example(example): - result = httpie(*example.split(), no_debug=True) - assert result.exit_status == ExitStatus.ERROR - assert 'usage: ' in result.stderr - assert f'http {example}' in result.stderr - assert f'https {example}' in result.stderr - - -@pytest.mark.parametrize( - 'example', [ - 'plugins unknown', - 'plugins unknown.com A:B c=d', - 'unknown.com UNPARSABLE????SYNTAX', - ] -) -@pytest.mark.requires_installation -def test_plugins_cli_error_messages_invalid_example(example): - result = httpie(*example.split(), no_debug=True) - assert result.exit_status == ExitStatus.ERROR - assert 'usage: ' in result.stderr - assert f'http {example}' not in result.stderr - assert f'https {example}' not in result.stderr diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 5835993605..8bcd906327 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -1,12 +1,16 @@ import json import os import shutil +from contextlib import contextmanager from datetime import datetime from unittest import mock +from pathlib import Path +from typing import Iterator import pytest from .fixtures import FILE_PATH_ARG, UNICODE +from httpie.context import Environment from httpie.encoding import UTF8 from httpie.plugins import AuthPlugin from httpie.plugins.builtin import HTTPBasicAuth @@ -14,7 +18,7 @@ from httpie.sessions import Session from httpie.utils import get_expired_cookies from .test_auth_plugins import basic_auth -from .utils import HTTP_OK, MockEnvironment, http, mk_config_dir +from .utils import DUMMY_HOST, HTTP_OK, MockEnvironment, http, mk_config_dir from base64 import b64encode @@ -203,9 +207,9 @@ def test_session_with_cookie_followed_by_another_header(self, httpbin): """ self.start_session(httpbin) session_data = { - "headers": { - "cookie": "...", - "zzz": "..." + 'headers': { + 'cookie': '...', + 'zzz': '...' } } session_path = self.config_dir / 'session-data.json' @@ -307,7 +311,7 @@ class Plugin(AuthPlugin): auth_type = 'test-prompted' def get_auth(self, username=None, password=None): - basic_auth_header = "Basic " + b64encode(self.raw_auth.encode()).strip().decode('latin1') + basic_auth_header = 'Basic ' + b64encode(self.raw_auth.encode()).strip().decode('latin1') return basic_auth(basic_auth_header) plugin_manager.register(Plugin) @@ -359,7 +363,7 @@ def get_auth(self, username=None, password=None): ) updated_session = json.loads(self.session_path.read_text(encoding=UTF8)) assert updated_session['auth']['type'] == 'test-saved' - assert updated_session['auth']['raw_auth'] == "user:password" + assert updated_session['auth']['raw_auth'] == 'user:password' plugin_manager.unregister(Plugin) @@ -368,12 +372,12 @@ class TestExpiredCookies(CookieTestBase): @pytest.mark.parametrize( 'initial_cookie, expired_cookie', [ - ({'id': {'value': 123}}, 'id'), - ({'id': {'value': 123}}, 'token') + ({'id': {'value': 123}}, {'name': 'id'}), + ({'id': {'value': 123}}, {'name': 'token'}) ] ) - def test_removes_expired_cookies_from_session_obj(self, initial_cookie, expired_cookie, httpbin): - session = Session(self.config_dir) + def test_removes_expired_cookies_from_session_obj(self, initial_cookie, expired_cookie, httpbin, mock_env): + session = Session(self.config_dir, env=mock_env, session_id=None, bound_host=None) session['cookies'] = initial_cookie session.remove_cookies([expired_cookie]) assert expired_cookie not in session.cookies @@ -524,3 +528,165 @@ def test_cookie_storage_priority(self, cli_cookie, set_cookie, expected, httpbin updated_session = json.loads(self.session_path.read_text(encoding=UTF8)) assert updated_session['cookies']['cookie1']['value'] == expected + + +@pytest.fixture +def basic_session(httpbin, tmp_path): + session_path = tmp_path / 'session.json' + http( + '--session', str(session_path), + httpbin + '/get' + ) + return session_path + + +@contextmanager +def open_session(path: Path, env: Environment, read_only: bool = False) -> Iterator[Session]: + session = Session(path, env, session_id='test', bound_host=DUMMY_HOST) + session.load() + yield session + if not read_only: + session.save() + + +@contextmanager +def open_raw_session(path: Path, read_only: bool = False) -> None: + with open(path) as stream: + raw_session = json.load(stream) + + yield raw_session + + if not read_only: + with open(path, 'w') as stream: + json.dump(raw_session, stream) + + +def read_stderr(env: Environment) -> bytes: + env.stderr.seek(0) + stderr_data = env.stderr.read() + if isinstance(stderr_data, str): + return stderr_data.encode() + else: + return stderr_data + + +def test_old_session_version_saved_as_is(basic_session, mock_env): + with open_session(basic_session, mock_env) as session: + session['__meta__'] = {'httpie': '0.0.1'} + + with open_session(basic_session, mock_env, read_only=True) as session: + assert session['__meta__']['httpie'] == '0.0.1' + + +def test_old_session_cookie_layout_warning(basic_session, mock_env): + with open_session(basic_session, mock_env) as session: + # Use the old layout & set a cookie + session['cookies'] = {} + session.cookies.set('foo', 'bar') + + assert read_stderr(mock_env) == b'' + + with open_session(basic_session, mock_env, read_only=True) as session: + assert b'Outdated layout detected' in read_stderr(mock_env) + + +@pytest.mark.parametrize('cookies, expect_warning', [ + # Old-style cookie format + ( + # Without 'domain' set + {'foo': {'value': 'bar'}}, + True + ), + ( + # With 'domain' set to empty string + {'foo': {'value': 'bar', 'domain': ''}}, + True + ), + ( + # With 'domain' set to null + {'foo': {'value': 'bar', 'domain': None}}, + False, + ), + ( + # With 'domain' set to a URL + {'foo': {'value': 'bar', 'domain': DUMMY_HOST}}, + False, + ), + # New style cookie format + ( + # Without 'domain' set + [{'name': 'foo', 'value': 'bar'}], + False + ), + ( + # With 'domain' set to empty string + [{'name': 'foo', 'value': 'bar', 'domain': ''}], + False + ), + ( + # With 'domain' set to null + [{'name': 'foo', 'value': 'bar', 'domain': None}], + False, + ), + ( + # With 'domain' set to a URL + [{'name': 'foo', 'value': 'bar', 'domain': DUMMY_HOST}], + False, + ), +]) +def test_cookie_security_warnings_on_raw_cookies(basic_session, mock_env, cookies, expect_warning): + with open_raw_session(basic_session) as raw_session: + raw_session['cookies'] = cookies + + with open_session(basic_session, mock_env, read_only=True): + warning = b'Outdated layout detected' + stderr = read_stderr(mock_env) + + if expect_warning: + assert warning in stderr + else: + assert warning not in stderr + + +def test_old_session_cookie_layout_loading(basic_session, httpbin, mock_env): + with open_session(basic_session, mock_env) as session: + # Use the old layout & set a cookie + session['cookies'] = {} + session.cookies.set('foo', 'bar') + + response = http( + '--session', str(basic_session), + httpbin + '/cookies' + ) + assert response.json['cookies'] == {'foo': 'bar'} + + +@pytest.mark.parametrize('layout_type', [ + dict, list +]) +def test_session_cookie_layout_preservance(basic_session, mock_env, layout_type): + with open_session(basic_session, mock_env) as session: + session['cookies'] = layout_type() + session.cookies.set('foo', 'bar') + session.save() + + with open_session(basic_session, mock_env, read_only=True) as session: + assert isinstance(session['cookies'], layout_type) + + +@pytest.mark.parametrize('layout_type', [ + dict, list +]) +def test_session_cookie_layout_preservance_on_new_cookies(basic_session, httpbin, mock_env, layout_type): + with open_session(basic_session, mock_env) as session: + session['cookies'] = layout_type() + session.cookies.set('foo', 'bar') + session.save() + + http( + '--session', str(basic_session), + httpbin + '/cookies/set/baz/quux' + ) + + with open_session(basic_session, mock_env, read_only=True) as session: + assert isinstance(session['cookies'], layout_type) diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index cf90d684b9..d3359820c1 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -6,6 +6,8 @@ import json import tempfile import warnings +import pytest +from contextlib import suppress from io import BytesIO from pathlib import Path from typing import Any, Optional, Union, List, Iterable @@ -16,6 +18,7 @@ from httpie.status import ExitStatus from httpie.config import Config from httpie.context import Environment +from httpie.utils import url_as_host # pytest-httpbin currently does not support chunked requests: @@ -39,6 +42,7 @@ ) DUMMY_URL = 'http://this-should.never-resolve' # Note: URL never fetched +DUMMY_HOST = url_as_host(DUMMY_URL) def strip_colors(colorized_msg: str) -> str: @@ -187,6 +191,13 @@ class ExitStatusError(Exception): pass +@pytest.fixture +def mock_env() -> MockEnvironment: + env = MockEnvironment(stdout_mode='') + yield env + env.cleanup() + + def normalize_args(args: Iterable[Any]) -> List[str]: return [str(arg) for arg in args] @@ -201,7 +212,7 @@ def httpie( status. """ - env = kwargs.setdefault('env', MockEnvironment()) + env = kwargs.setdefault('env', MockEnvironment(stdout_mode='')) cli_args = ['httpie'] if not kwargs.pop('no_debug', False): cli_args.append('--debug') @@ -214,7 +225,16 @@ def httpie( env.stdout.seek(0) env.stderr.seek(0) try: - response = StrCLIResponse(env.stdout.read()) + output = env.stdout.read() + if isinstance(output, bytes): + with suppress(UnicodeDecodeError): + output = output.decode() + + if isinstance(output, bytes): + response = BytesCLIResponse(output) + else: + response = StrCLIResponse(output) + response.stderr = env.stderr.read() response.exit_status = exit_status response.args = cli_args diff --git a/tests/utils/http_server.py b/tests/utils/http_server.py index 0a96dd8b07..ecc14966b9 100644 --- a/tests/utils/http_server.py +++ b/tests/utils/http_server.py @@ -85,6 +85,19 @@ def status_custom_msg(handler): handler.end_headers() +@TestHandler.handler('GET', '/cookies/set-and-redirect') +def set_cookie_and_redirect(handler): + handler.send_response(302) + + redirect_to = handler.headers.get('X-Redirect-To', '/headers') + handler.send_header('Location', redirect_to) + + raw_cookies = handler.headers.get('X-Cookies', 'a=b') + for cookie in raw_cookies.split(', '): + handler.send_header('Set-Cookie', cookie) + handler.end_headers() + + @pytest.fixture(scope="function") def http_server(): """A custom HTTP server implementation for our tests, that is From 395914fb4d439ce5220a44af231d3e16bf3fe18d Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Fri, 4 Mar 2022 14:09:16 +0300 Subject: [PATCH 1045/1182] Apply suggestions from the review --- SECURITY.md | 10 ++++ docs/README.md | 17 ------ httpie/legacy/__init__.py | 0 httpie/legacy/cookie_format.py | 103 +++++++++++++++++++++++++++++++++ httpie/manager/cli.py | 6 +- httpie/manager/tasks.py | 24 +------- httpie/sessions.py | 94 ++++++++++-------------------- 7 files changed, 148 insertions(+), 106 deletions(-) create mode 100644 SECURITY.md create mode 100644 httpie/legacy/__init__.py create mode 100644 httpie/legacy/cookie_format.py diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..b10980cbb6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,10 @@ +# Security Policy + +## Reporting a Vulnerability + +To report a vulnerability, please send an email to `security@httpie.io` describing the: + +- The description of the vulnerability itself +- A short reproducer to verify it (you can submit a small HTTP server, a shell script, a docker image etc.) +- The severity level classification (`LOW`/`MEDIUM`/`HIGH`/`CRITICAL`) +- If associated with any, the [CWE](https://cwe.mitre.org/) ID. diff --git a/docs/README.md b/docs/README.md index efd579a343..30daa4b678 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2422,23 +2422,6 @@ And since there’s neither data nor `EOF`, it will get stuck. So unless you’r Also, it might be good to set a connection `--timeout` limit to prevent your program from hanging if the server never responds. -### Security - -#### Exposure of Cookies To The 3rd Party Hosts On Redirects - -*Vulnerability Type*: [CWE-200](https://cwe.mitre.org/data/definitions/200.html) -*Severity Level*: LOW -*Affected Versions*: `<3.1.0` - -The handling of [cookies](#cookies) was not compatible with the [RFC 6265](https://datatracker.ietf.org/doc/html/rfc6265) -on the point of handling the `Domain` attribute when they were saved into [session](#sessions) files. All cookies were shared -across all hosts during the runtime, including redirects to the 3rd party hosts. - -This vulnerability has been fixed in [3.1.0](https://github.com/httpie/httpie/releases/tag/3.1.0) and the -[`httpie cli sessions upgrade`](#upgrading-sessions)/[`httpie cli sessions upgrade-all`]((#upgrading-sessions) commands -have been put in place in order to allow a smooth transition to the new session layout from the existing [session](#sessions) -files. - ## Plugin manager HTTPie offers extensibility through a [plugin API](https://github.com/httpie/httpie/blob/master/httpie/plugins/base.py), diff --git a/httpie/legacy/__init__.py b/httpie/legacy/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/httpie/legacy/cookie_format.py b/httpie/legacy/cookie_format.py new file mode 100644 index 0000000000..b5c6392b7c --- /dev/null +++ b/httpie/legacy/cookie_format.py @@ -0,0 +1,103 @@ +import argparse +from typing import Any, Type, List, Dict, TYPE_CHECKING + +if TYPE_CHECKING: + from httpie.sessions import Session + +INSECURE_COOKIE_JAR_WARNING = '''\ +Outdated layout detected for the current session. Please consider updating it, +in order to not get affected by potential security problems. + +For fixing the current session: + + With binding all cookies to the current host (secure): + $ httpie cli sessions upgrade --bind-cookies {hostname} {session_id} + + Without binding cookies (leaving them as is) (insecure): + $ httpie cli sessions upgrade {hostname} {session_id} +''' + + +INSECURE_COOKIE_JAR_WARNING_FOR_NAMED_SESSIONS = '''\ + +For fixing all named sessions: + + With binding all cookies to the current host (secure): + $ httpie cli sessions upgrade-all --bind-cookies + + Without binding cookies (leaving them as is) (insecure): + $ httpie cli sessions upgrade-all +''' + +INSECURE_COOKIE_SECURITY_LINK = '\nSee https://pie.co/docs/security for more information.' + + +def pre_process(session: 'Session', cookies: Any) -> List[Dict[str, Any]]: + """Load the given cookies to the cookie jar while maintaining + support for the old cookie layout.""" + + is_old_style = isinstance(cookies, dict) + if is_old_style: + normalized_cookies = [ + { + 'name': key, + **value + } + for key, value in cookies.items() + ] + else: + normalized_cookies = cookies + + should_issue_warning = is_old_style and any( + cookie.get('domain', '') == '' + for cookie in normalized_cookies + ) + + if should_issue_warning and not session.refactor_mode: + warning = INSECURE_COOKIE_JAR_WARNING.format(hostname=session.bound_host, session_id=session.session_id) + if not session.is_anonymous: + warning += INSECURE_COOKIE_JAR_WARNING_FOR_NAMED_SESSIONS + warning += INSECURE_COOKIE_SECURITY_LINK + + session.env.log_error( + warning, + level='warning' + ) + + return normalized_cookies + + +def post_process( + normalized_cookies: List[Dict[str, Any]], + *, + original_type: Type[Any] +) -> Any: + """Convert the cookies to their original format for + maximum compatibility.""" + + if issubclass(original_type, dict): + return { + cookie.pop('name'): cookie + for cookie in normalized_cookies + } + else: + return normalized_cookies + + +def fix_layout(session: 'Session', hostname: str, args: argparse.Namespace) -> None: + if not isinstance(session['cookies'], dict): + return None + + session['cookies'] = [ + { + 'name': key, + **value + } + for key, value in session['cookies'].items() + ] + for cookie in session.cookies: + if cookie.domain == '': + if args.bind_cookies: + cookie.domain = hostname + else: + cookie._rest['is_explicit_none'] = True diff --git a/httpie/manager/cli.py b/httpie/manager/cli.py index 9ad4eca6ba..1473ccf977 100644 --- a/httpie/manager/cli.py +++ b/httpie/manager/cli.py @@ -4,7 +4,7 @@ CLI_SESSION_UPGRADE_FLAGS = [ { - 'variadic': ['--bind-cookies'], + 'flags': ['--bind-cookies'], 'action': 'store_true', 'default': False, 'help': 'Bind domainless cookies to the host that session belongs.' @@ -102,8 +102,8 @@ def generate_subparsers(root, parent_parser, definitions): for argument in properties: argument = argument.copy() - variadic = argument.pop('variadic', []) - command_parser.add_argument(*variadic, **argument) + flags = argument.pop('flags', []) + command_parser.add_argument(*flags, **argument) parser = HTTPieManagerArgumentParser( diff --git a/httpie/manager/tasks.py b/httpie/manager/tasks.py index c04ed9bc3d..297767b025 100644 --- a/httpie/manager/tasks.py +++ b/httpie/manager/tasks.py @@ -1,9 +1,10 @@ import argparse from typing import TypeVar, Callable, Tuple -from httpie.sessions import SESSIONS_DIR_NAME, Session, get_httpie_session +from httpie.sessions import SESSIONS_DIR_NAME, get_httpie_session from httpie.status import ExitStatus from httpie.context import Environment +from httpie.legacy import cookie_format as legacy_cookies from httpie.manager.cli import missing_subcommand, parser T = TypeVar('T') @@ -51,27 +52,8 @@ def split_version(version: str) -> Tuple[int, ...]: return split_version(version_1) > split_version(version_2) -def fix_cookie_layout(session: Session, hostname: str, args: argparse.Namespace) -> None: - if not isinstance(session['cookies'], dict): - return None - - session['cookies'] = [ - { - 'name': key, - **value - } - for key, value in session['cookies'].items() - ] - for cookie in session.cookies: - if cookie.domain == '': - if args.bind_cookies: - cookie.domain = hostname - else: - cookie._rest['is_explicit_none'] = True - - FIXERS_TO_VERSIONS = { - '3.1.0': fix_cookie_layout + '3.1.0': legacy_cookies.fix_layout } diff --git a/httpie/sessions.py b/httpie/sessions.py index c23cb56852..e4a20a5344 100644 --- a/httpie/sessions.py +++ b/httpie/sessions.py @@ -8,7 +8,7 @@ from http.cookies import SimpleCookie from http.cookiejar import Cookie from pathlib import Path -from typing import Any, Dict, Optional, Union +from typing import Any, Dict, List, Optional, Union from requests.auth import AuthBase from requests.cookies import RequestsCookieJar, remove_cookie_by_name @@ -18,6 +18,7 @@ from .config import BaseConfigDict, DEFAULT_CONFIG_DIR from .utils import url_as_host from .plugins.registry import plugin_manager +from .legacy import cookie_format as legacy_cookies SESSIONS_DIR_NAME = 'sessions' @@ -32,35 +33,23 @@ KEPT_COOKIE_OPTIONS = ['name', 'expires', 'path', 'value', 'domain', 'secure'] DEFAULT_COOKIE_PATH = '/' -INSECURE_COOKIE_JAR_WARNING = '''\ -Outdated layout detected for the current session. Please consider updating it, -in order to not get affected by potential security problems. -For fixing the current session: - - With binding all cookies to the current host (secure): - $ httpie cli sessions upgrade --bind-cookies {hostname} {session_id} - - Without binding cookies (leaving them as is) (insecure): - $ httpie cli sessions upgrade {hostname} {session_id} -''' - -INSECURE_COOKIE_JAR_WARNING_FOR_NAMED_SESSIONS = '''\ - -For fixing all named sessions: - - With binding all cookies to the current host (secure): - $ httpie cli sessions upgrade-all --bind-cookies +def is_anonymous_session(session_name: str) -> bool: + return os.path.sep in session_name - Without binding cookies (leaving them as is) (insecure): - $ httpie cli sessions upgrade-all -See https://pie.co/docs/security for more information. -''' +def session_hostname_to_dirname(hostname: str, session_name: str) -> str: + # host:port => host_port + hostname = hostname.replace(':', '_') + return os.path.join( + SESSIONS_DIR_NAME, + hostname, + f'{session_name}.json' + ) -def is_anonymous_session(session_name: str) -> bool: - return os.path.sep in session_name +def strip_port(hostname: str) -> str: + return hostname.split(':')[0] def materialize_cookie(cookie: Cookie) -> Dict[str, Any]: @@ -92,22 +81,18 @@ def get_httpie_session( # HACK/FIXME: httpie-unixsocket's URLs have no hostname. bound_hostname = 'localhost' - # host:port => host_port - hostname = bound_hostname.replace(':', '_') if is_anonymous_session(session_name): path = os.path.expanduser(session_name) session_id = path else: - path = ( - config_dir / SESSIONS_DIR_NAME / hostname / f'{session_name}.json' - ) + path = config_dir / session_hostname_to_dirname(bound_hostname, session_name) session_id = session_name session = Session( path, env=env, session_id=session_id, - bound_host=bound_hostname.split(':')[0], + bound_host=strip_port(bound_hostname), refactor_mode=refactor_mode ) session.load() @@ -142,60 +127,35 @@ def __init__( def pre_process_data(self, data: Dict[str, Any]) -> Dict[str, Any]: cookies = data.get('cookies') - if isinstance(cookies, dict): - normalized_cookies = [ - { - 'name': key, - **value - } - for key, value in cookies.items() - ] - elif isinstance(cookies, list): - normalized_cookies = cookies + if cookies: + normalized_cookies = legacy_cookies.pre_process(self, cookies) else: normalized_cookies = [] - should_issue_warning = False for cookie in normalized_cookies: domain = cookie.get('domain', '') - if domain == '' and isinstance(cookies, dict): - should_issue_warning = True - elif domain is None: + if domain is None: # domain = None means explicitly lack of cookie, though - # requests requires domain to be string so we'll cast it + # requests requires domain to be a string so we'll cast it # manually. cookie['domain'] = '' cookie['rest'] = {'is_explicit_none': True} self.cookie_jar.set(**cookie) - if should_issue_warning and not self.refactor_mode: - warning = INSECURE_COOKIE_JAR_WARNING.format(hostname=self.bound_host, session_id=self.session_id) - if not is_anonymous_session(self.session_id): - warning += INSECURE_COOKIE_JAR_WARNING_FOR_NAMED_SESSIONS - - self.env.log_error( - warning, - level='warning' - ) - return data def post_process_data(self, data: Dict[str, Any]) -> Dict[str, Any]: cookies = data.get('cookies') - # Save in the old-style fashion normalized_cookies = [ materialize_cookie(cookie) for cookie in self.cookie_jar ] - if isinstance(cookies, dict): - data['cookies'] = { - cookie.pop('name'): cookie - for cookie in normalized_cookies - } - else: - data['cookies'] = normalized_cookies + data['cookies'] = legacy_cookies.post_process( + normalized_cookies, + original_type=type(cookies) + ) return data @@ -251,7 +211,7 @@ def cookies(self) -> RequestsCookieJar: def cookies(self, jar: RequestsCookieJar): self.cookie_jar = jar - def remove_cookies(self, cookies: Dict[str, str]): + def remove_cookies(self, cookies: List[Dict[str, str]]): for cookie in cookies: remove_cookie_by_name( self.cookie_jar, @@ -293,3 +253,7 @@ def auth(self) -> Optional[AuthBase]: def auth(self, auth: dict): assert {'type', 'raw_auth'} == auth.keys() self['auth'] = auth + + @property + def is_anonymous(self): + return is_anonymous_session(self.session_id) From 614866eeb237aebe01f467e64f58c1004ba780b2 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 7 Mar 2022 20:43:48 +0100 Subject: [PATCH 1046/1182] Polish sessions docs --- docs/README.md | 154 +++++++++++++++++++------------------------------ 1 file changed, 59 insertions(+), 95 deletions(-) diff --git a/docs/README.md b/docs/README.md index 30daa4b678..5091295536 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2157,30 +2157,28 @@ $ http --session-read-only=./ro-session.json pie.dev/headers Custom-Header:orig- $ http --session-read-only=./ro-session.json pie.dev/headers Custom-Header:new-value ``` -### Host-based Cookie Policy +### Host-based cookie policy -Cookies in stored HTTPie sessions have a `domain` field which is binding them to the -specified hostname. For example, in the following session: +Cookies persisted in sessions files have a `domain` field. This _binds_ them to a specified hostname. For example: ```json { "cookies": [ { "domain": "pie.dev", - "name": "secret_cookie", - "value": "value_1" + "name": "pie", + "value": "apple" }, { "domain": "httpbin.org", - "name": "secret_cookie", - "value": "value_2" + "name": "bin", + "value": "http" } ] } ``` -we will send `Cookie:secret_cookie=value_1` only when you are making a request against `pie.dev` (it -also includes the domains, like `api.pie.dev`), and `Cookie:secret_cookie=value_2` when you use `httpbin.org`. +Using this session file, we include `Cookie: pie=apple` only in requests against `pie.dev` and subdomains (e.g., `foo.pie.dev` or `foo.bar.pie.dev`): ```bash $ http --session=./session.json pie.dev/cookies @@ -2189,36 +2187,20 @@ $ http --session=./session.json pie.dev/cookies ```json { "cookies": { - "secret_cookie": "value_1" + "pie": "apple" } } ``` -```bash -$ http --session=./session.json httpbin.org/cookies -``` - -```json -{ - "cookies": { - "secret_cookie": "value_2" - } -} -``` - -If you want to make a cookie domain unbound, you can simply set the `domain` -field to `null` by editing the session file directly: +To make a cookie domain _unbound_ (i.e., to make it available to all hosts, including throughout a cross-domain redirect chain), you can set the `domain` field to `null` in the session file: ```json { "cookies": [ { "domain": null, - "expires": null, - "name": "generic_cookie", - "path": "/", - "secure": false, - "value": "generic_value" + "name": "unbound-cookie", + "value": "send-me-to-any-host" } ] } @@ -2231,105 +2213,87 @@ $ http --session=./session.json pie.dev/cookies ```json { "cookies": { - "generic_cookie": "generic_value" + "unbound-cookie": "send-me-to-any-host" } } ``` -### Cookie Storage Behavior -**TL;DR:** Cookie storage priority: Server response > Command line request > Session file +### Cookie storage behavior -To set a cookie within a Session there are three options: +There are three possible sources of persisted cookies within a session. They have the following storage priority: 1—response; 2—command line; 3—session file. -1. Get a `Set-Cookie` header in a response from a server +1. Receive a response with a `Set-Cookie` header: - ```bash - $ http --session=./session.json pie.dev/cookie/set?foo=bar - ``` +```bash +$ http --session=./session.json pie.dev/cookie/set?foo=bar +``` -2. Set the cookie name and value through the command line as seen in [cookies](#cookies) +2. Send a cookie specified on the command line as seen in [cookies](#cookies): - ```bash - $ http --session=./session.json pie.dev/headers Cookie:foo=bar - ``` +```bash +$ http --session=./session.json pie.dev/headers Cookie:foo=bar +``` -3. Manually set cookie parameters in the JSON file of the session +3. Manually set cookie parameters in the session file: - ```json - { - "__meta__": { - "about": "HTTPie session file", - "help": "https://httpie.org/doc#sessions", - "httpie": "2.2.0-dev" - }, - "auth": { - "password": null, - "type": null, - "username": null - }, - "cookies": { - "foo": { - "expires": null, - "path": "/", - "secure": false, - "value": "bar" - } - } +```json +{ + "cookies": { + "foo": { + "expires": null, + "path": "/", + "secure": false, + "value": "bar" + } } - ``` - -Cookies will be set in the session file with the priority specified above. -For example, a cookie set through the command line will overwrite a cookie of the same name stored in the session file. -If the server returns a `Set-Cookie` header with a cookie of the same name, the returned cookie will overwrite the preexisting cookie. +} +``` -Expired cookies are never stored. -If a cookie in a session file expires, it will be removed before sending a new request. -If the server expires an existing cookie, it will also be removed from the session file. +In summary: -### Upgrading Sessions +- Cookies set via the CLI overwrite cookies of the same name inside session files. +- Server-sent `Set-Cookie` header cookies overwrite any pre-existing ones with the same name. -In rare circumstances, HTTPie makes changes in it's session layout. For allowing a smoother transition of existing files -from the old layout to the new layout we offer 2 interfaces: +Cookie expiration handling: -- `httpie cli sessions upgrade` -- `httpie cli sessions upgrade-all` +- When the server expires an existing cookie, HTTPie removes it from the session file. +- When a cookie in a session file expires, HTTPie removes it before sending a new request. +### Upgrading sessions -With `httpie cli sessions upgrade`, you can upgrade a single session with it's name (or it's path, if it is an -[anonymous session](#anonymous-sessions)) and the hostname it belongs to. For example: +HTTPie may introduce changes in the session file format. When HTTPie detects an obsolete format, it shows a warning. You can upgrade your session files using the following commands: -([named session](#named-sessions)) +Upgrade all existing [named sessions](#named-sessions) inside the `sessions` subfolder of your [config directory](https://httpie.io/docs/cli/config-file-directory): ```bash -$ httpie cli sessions upgrade pie.dev api_auth -Refactored 'api_auth' (for 'pie.dev') to the version 3.1.0. +$ httpie cli sessions upgrade-all +Upgraded 'api_auth' @ 'pie.dev' to v3.1.0 +Upgraded 'login_cookies' @ 'httpie.io' to v3.1.0 ``` -([anonymous session](#anonymous-sessions)) +Upgrading individual sessions requires you to specify the session's hostname. That allows HTTPie to find the correct file in the case of name sessions. Additionally, it allows it to correctly bind cookies when upgrading with [`--bind-cookies`](#session-upgrade-options). + +Upgrade a single [named session](#named-sessions): ```bash -$ httpie cli sessions upgrade pie.dev ./session.json -Refactored 'session' (for 'pie.dev') to the version 3.1.0. +$ httpie cli sessions upgrade pie.dev api_auth +Upgraded 'api_auth' @ 'pie.dev' to v3.1.0 ``` -If you want to upgrade every existing [named session](#named-sessions), you can use `httpie cli sessions upgrade-all` (be aware -that this won't upgrade [anonymous sessions](#anonymous-sessions)): +Upgrade a single [anonymous session](#anonymous-sessions) using a file path: ```bash -$ httpie cli sessions upgrade-all -Refactored 'api_auth' (for 'pie.dev') to the version 3.1.0. -Refactored 'login_cookies' (for 'httpie.io') to the version 3.1.0. +$ httpie cli sessions upgrade pie.dev ./session.json +Upgraded 'session.json' @ 'pie.dev' to v3.1.0 ``` -#### Additional Customizations +#### Session upgrade options -| Flag | Description | -|------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `--bind-cookies` | Bind all the unbound cookies to the hostname that session belongs. By default, if the cookie is unbound (the `domain` attribute does not exist / set to an empty string) then it will still continue to be a generic cookie. | +These flags are available for both `sessions upgrade` and `sessions upgrade-all`: -These flags can be used to customize the defaults during an `upgrade` operation. They can -be used in both `sessions upgrade` and `sessions upgrade-all`. +------------------|------------------------------------------ +`--bind-cookies` | Bind all previously [unbound cookies](#host-based-cookie-policy) to the session’s host. ## Config @@ -2342,7 +2306,7 @@ To see the exact location for your installation, run `http --debug` and look for The default location of the configuration file on most platforms is `$XDG_CONFIG_HOME/httpie/config.json` (defaulting to `~/.config/httpie/config.json`). -For backwards compatibility, if the directory `~/.httpie` exists, the configuration file there will be used instead. +For backward compatibility, if the directory `~/.httpie` exists, the configuration file there will be used instead. On Windows, the config file is located at `%APPDATA%\httpie\config.json`. From 0a873172c95404b43387c1a4302eecc1cdb8379e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 7 Mar 2022 20:55:51 +0100 Subject: [PATCH 1047/1182] Tweak SECURITY and add a Security policy section to docs --- SECURITY.md | 18 +++++++++++------- docs/README.md | 8 ++++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index b10980cbb6..6d1b95da54 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,10 +1,14 @@ -# Security Policy +# Security policy -## Reporting a Vulnerability +## Reporting a vulnerability -To report a vulnerability, please send an email to `security@httpie.io` describing the: +When you identify a vulnerability in HTTPie, please report it privately using one of the following channels: -- The description of the vulnerability itself -- A short reproducer to verify it (you can submit a small HTTP server, a shell script, a docker image etc.) -- The severity level classification (`LOW`/`MEDIUM`/`HIGH`/`CRITICAL`) -- If associated with any, the [CWE](https://cwe.mitre.org/) ID. +- Email to [`security@httpie.io`](mailto:security@httpie.io) +- Report on [huntr.dev](https://huntr.dev/) + +In addition to the description of the vulnerability, please include also: + +- A short reproducer to verify it (it can be a small HTTP server, shell script, docker image, etc.) +- Your deemed severity level of the vulnerability (`LOW`/`MEDIUM`/`HIGH`/`CRITICAL`) +- [CWE](https://cwe.mitre.org/) ID, if available. diff --git a/docs/README.md b/docs/README.md index 5091295536..836c478dee 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2252,7 +2252,7 @@ $ http --session=./session.json pie.dev/headers Cookie:foo=bar In summary: -- Cookies set via the CLI overwrite cookies of the same name inside session files. +- Cookies set via the CLI overwrite cookies of the same name inside session files. - Server-sent `Set-Cookie` header cookies overwrite any pre-existing ones with the same name. Cookie expiration handling: @@ -2293,7 +2293,7 @@ Upgraded 'session.json' @ 'pie.dev' to v3.1.0 These flags are available for both `sessions upgrade` and `sessions upgrade-all`: ------------------|------------------------------------------ -`--bind-cookies` | Bind all previously [unbound cookies](#host-based-cookie-policy) to the session’s host. +`--bind-cookies` | Bind all previously [unbound cookies](#host-based-cookie-policy) to the session’s host. ## Config @@ -2532,6 +2532,10 @@ Helpers to convert from other client tools: See [CONTRIBUTING](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md). +### Security policy + +See [github.com/httpie/httpie/security/policy](https://github.com/httpie/httpie/security/policy). + ### Change log See [CHANGELOG](https://github.com/httpie/httpie/blob/master/CHANGELOG.md). From 59d9e928f8a6de4bd78e9e11adbabf9de9207d45 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 7 Mar 2022 20:57:03 +0100 Subject: [PATCH 1048/1182] Tweak --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 6d1b95da54..542bcd7854 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,7 +7,7 @@ When you identify a vulnerability in HTTPie, please report it privately using on - Email to [`security@httpie.io`](mailto:security@httpie.io) - Report on [huntr.dev](https://huntr.dev/) -In addition to the description of the vulnerability, please include also: +In addition to the description of the vulnerability, include the following information: - A short reproducer to verify it (it can be a small HTTP server, shell script, docker image, etc.) - Your deemed severity level of the vulnerability (`LOW`/`MEDIUM`/`HIGH`/`CRITICAL`) From f08c1bee178bade4a1a67213580dab2f6b00f6d5 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 7 Mar 2022 23:10:50 +0300 Subject: [PATCH 1049/1182] Change error messages to use a better format. --- httpie/manager/tasks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/httpie/manager/tasks.py b/httpie/manager/tasks.py index 297767b025..f039a142f1 100644 --- a/httpie/manager/tasks.py +++ b/httpie/manager/tasks.py @@ -69,7 +69,7 @@ def upgrade_session(env: Environment, args: argparse.Namespace, hostname: str, s session_name = session.path.stem if session.is_new(): - env.log_error(f'{session_name!r} (for {hostname!r}) does not exist.') + env.log_error(f'{session_name!r} @ {hostname!r} does not exist.') return ExitStatus.ERROR fixers = [ @@ -79,14 +79,14 @@ def upgrade_session(env: Environment, args: argparse.Namespace, hostname: str, s ] if len(fixers) == 0: - env.stdout.write(f'{session_name!r} (for {hostname!r}) is already up-to-date.\n') + env.stdout.write(f'{session_name!r} @ {hostname!r} is already up to date.\n') return ExitStatus.SUCCESS for fixer in fixers: fixer(session, hostname, args) session.save(bump_version=True) - env.stdout.write(f'Refactored {session_name!r} (for {hostname!r}) to the version {session.version}.\n') + env.stdout.write(f'Upgraded {session_name!r} @ {hostname!r} to v{session.version}\n') return ExitStatus.SUCCESS From 7509dd4e6cd8caae20b0ce50a855ff1ebfc48f62 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 7 Mar 2022 23:22:28 +0300 Subject: [PATCH 1050/1182] Fix documentation styling errors. --- docs/README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/README.md b/docs/README.md index 836c478dee..81b0aa7643 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2225,30 +2225,30 @@ There are three possible sources of persisted cookies within a session. They hav 1. Receive a response with a `Set-Cookie` header: -```bash -$ http --session=./session.json pie.dev/cookie/set?foo=bar -``` + ```bash + $ http --session=./session.json pie.dev/cookie/set?foo=bar + ``` 2. Send a cookie specified on the command line as seen in [cookies](#cookies): -```bash -$ http --session=./session.json pie.dev/headers Cookie:foo=bar -``` + ```bash + $ http --session=./session.json pie.dev/headers Cookie:foo=bar + ``` 3. Manually set cookie parameters in the session file: -```json -{ - "cookies": { - "foo": { - "expires": null, - "path": "/", - "secure": false, - "value": "bar" - } - } -} -``` + ```json + { + "cookies": { + "foo": { + "expires": null, + "path": "/", + "secure": false, + "value": "bar" + } + } + } + ``` In summary: From 77af4c7a5cb3d0b3e813c7f678099014c94ff6aa Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Tue, 8 Mar 2022 01:34:04 +0300 Subject: [PATCH 1051/1182] Decouple parser definition from argparse (#1293) --- docs/README.md | 21 ++ httpie/cli/constants.py | 8 +- httpie/cli/definition.py | 537 ++++++++++++++++++------------------ httpie/cli/options.py | 189 +++++++++++++ httpie/core.py | 29 +- httpie/manager/cli.py | 8 + httpie/manager/tasks.py | 25 ++ httpie/output/models.py | 44 +++ httpie/output/streams.py | 4 +- httpie/output/writer.py | 70 +++-- tests/test_httpie_cli.py | 13 + tests/test_parser_schema.py | 60 ++++ 12 files changed, 711 insertions(+), 297 deletions(-) create mode 100644 httpie/cli/options.py create mode 100644 httpie/output/models.py create mode 100644 tests/test_parser_schema.py diff --git a/docs/README.md b/docs/README.md index 81b0aa7643..1c171bd80d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2402,6 +2402,27 @@ For managing these plugins; starting with 3.0, we are offering a new plugin mana This command is currently in beta. +### `httpie cli` + +#### `httpie cli export-args` + +`httpie cli export-args` command can expose the parser specification of `http`/`https` commands +(like an API definition) to outside tools so that they can use this to build better interactions +over them (e.g offer auto-complete). + + +Available formats to export in include: +| format | Description | +|--------|---------------------------------------------------------------------------------------------------------------------------------------------------| +| `json` | Export the parser spec in JSON. The schema includes a top-level `version` parameter which should be interpreted in [semver](https://semver.org/). | + +You can use any of these formats with `--format` parameter, but the default one is `json`. + +```bash +$ httpie cli export-args | jq '"Program: " + .spec.name + ", Version: " + .version' +"Program: http, Version: 0.0.1a0" +``` + ### `httpie plugins` `plugins` interface is a very simple plugin manager for installing, listing and uninstalling HTTPie plugins. diff --git a/httpie/cli/constants.py b/httpie/cli/constants.py index 067aaabdf7..e8188938d5 100644 --- a/httpie/cli/constants.py +++ b/httpie/cli/constants.py @@ -90,13 +90,19 @@ }) # Pretty + + +class PrettyOptions(enum.Enum): + STDOUT_TTY_ONLY = enum.auto() + + PRETTY_MAP = { 'all': ['format', 'colors'], 'colors': ['colors'], 'format': ['format'], 'none': [] } -PRETTY_STDOUT_TTY_ONLY = object() +PRETTY_STDOUT_TTY_ONLY = PrettyOptions.STDOUT_TTY_ONLY DEFAULT_FORMAT_OPTIONS = [ diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 806b04bc60..5db5b390d2 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -1,67 +1,58 @@ -""" -CLI arguments definition. - -""" -from argparse import (FileType, OPTIONAL, SUPPRESS, ZERO_OR_MORE) -from textwrap import dedent, wrap - -from .. import __doc__, __version__ -from .argparser import HTTPieArgumentParser -from .argtypes import ( - KeyValueArgType, SessionNameValidator, SSLCredentials, - readable_file_arg, response_charset_type, response_mime_type, -) -from .constants import ( - DEFAULT_FORMAT_OPTIONS, BASE_OUTPUT_OPTIONS, OUTPUT_OPTIONS, - OUTPUT_OPTIONS_DEFAULT, OUT_REQ_BODY, OUT_REQ_HEAD, - OUT_RESP_BODY, OUT_RESP_HEAD, OUT_RESP_META, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, - RequestType, SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY, - SORTED_FORMAT_OPTIONS_STRING, - UNSORTED_FORMAT_OPTIONS_STRING, -) -from .utils import LazyChoices -from ..output.formatters.colors import ( - AUTO_STYLE, DEFAULT_STYLE, get_available_styles -) -from ..plugins.builtin import BuiltinAuthPlugin -from ..plugins.registry import plugin_manager -from ..sessions import DEFAULT_SESSIONS_DIR -from ..ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS - - -parser = HTTPieArgumentParser( - prog='http', +from __future__ import annotations + +import textwrap +from argparse import FileType + +from httpie import __doc__, __version__ +from httpie.cli.argtypes import (KeyValueArgType, SessionNameValidator, + SSLCredentials, readable_file_arg, + response_charset_type, response_mime_type) +from httpie.cli.constants import (BASE_OUTPUT_OPTIONS, DEFAULT_FORMAT_OPTIONS, + OUT_REQ_BODY, OUT_REQ_HEAD, OUT_RESP_BODY, + OUT_RESP_HEAD, OUT_RESP_META, OUTPUT_OPTIONS, + OUTPUT_OPTIONS_DEFAULT, PRETTY_MAP, + PRETTY_STDOUT_TTY_ONLY, + SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY, + SORTED_FORMAT_OPTIONS_STRING, + UNSORTED_FORMAT_OPTIONS_STRING, RequestType) +from httpie.cli.options import ParserSpec, Qualifiers, to_argparse +from httpie.output.formatters.colors import (AUTO_STYLE, DEFAULT_STYLE, + get_available_styles) +from httpie.plugins.builtin import BuiltinAuthPlugin +from httpie.plugins.registry import plugin_manager +from httpie.sessions import DEFAULT_SESSIONS_DIR +from httpie.ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS + +options = ParserSpec( + 'http', description=f'{__doc__.strip()} ', - epilog=dedent(''' + epilog=""" For every --OPTION there is also a --no-OPTION that reverts OPTION to its default value. - Suggestions and bug reports are greatly appreciated: - https://github.com/httpie/httpie/issues - - '''), + """, ) -parser.register('action', 'lazy_choices', LazyChoices) + ####################################################################### # Positional arguments. ####################################################################### -positional = parser.add_argument_group( - title='Positional Arguments', - description=dedent(''' +positional_arguments = options.add_group( + 'Positional Arguments', + description=""" These arguments come after any flags and in the order they are listed here. Only URL is required. - - ''') + """, ) -positional.add_argument( + +positional_arguments.add_argument( dest='method', metavar='METHOD', - nargs=OPTIONAL, + nargs=Qualifiers.OPTIONAL, default=None, - help=''' + help=""" The HTTP method to be used for the request (GET, POST, PUT, DELETE, ...). This argument can be omitted in which case HTTPie will use POST if there @@ -70,12 +61,12 @@ $ http example.org # => GET $ http example.org hello=world # => POST - ''' + """, ) -positional.add_argument( +positional_arguments.add_argument( dest='url', metavar='URL', - help=''' + help=""" The scheme defaults to 'http://' if the URL does not include one. (You can override this with: --default-scheme=https) @@ -84,15 +75,15 @@ $ http :3000 # => http://localhost:3000 $ http :/foo # => http://localhost/foo - ''' + """, ) -positional.add_argument( +positional_arguments.add_argument( dest='request_items', metavar='REQUEST_ITEM', - nargs=ZERO_OR_MORE, + nargs=Qualifiers.ZERO_OR_MORE, default=None, type=KeyValueArgType(*SEPARATOR_GROUP_ALL_ITEMS), - help=r''' + help=r""" Optional key-value pairs to be included in the request. The separator used determines the type: @@ -130,66 +121,65 @@ field-name-with\:colon=value - ''' + """, ) ####################################################################### # Content type. ####################################################################### -content_type = parser.add_argument_group( - title='Predefined Content Types', - description=None -) +content_types = options.add_group('Predefined Content Types') -content_type.add_argument( - '--json', '-j', +content_types.add_argument( + '--json', + '-j', action='store_const', const=RequestType.JSON, dest='request_type', - help=''' + help=""" (default) Data items from the command line are serialized as a JSON object. The Content-Type and Accept headers are set to application/json (if not specified). - ''' + """, ) -content_type.add_argument( - '--form', '-f', +content_types.add_argument( + '--form', + '-f', action='store_const', const=RequestType.FORM, dest='request_type', - help=''' + help=""" Data items from the command line are serialized as form fields. The Content-Type is set to application/x-www-form-urlencoded (if not specified). The presence of any file fields results in a multipart/form-data request. - ''' + """, ) -content_type.add_argument( +content_types.add_argument( '--multipart', action='store_const', const=RequestType.MULTIPART, dest='request_type', - help=''' + help=""" Similar to --form, but always sends a multipart/form-data request (i.e., even without files). - ''' + """, ) -content_type.add_argument( +content_types.add_argument( '--boundary', - help=''' + help=""" Specify a custom boundary string for multipart/form-data requests. Only has effect only together with --form. - ''' + """, ) -content_type.add_argument( +content_types.add_argument( '--raw', - help=''' + help=""" This option allows you to pass raw request data without extra processing (as opposed to the structured request items syntax): @@ -204,55 +194,37 @@ $ http pie.dev/post @data.txt - ''' + """, ) - ####################################################################### # Content processing. ####################################################################### -content_processing = parser.add_argument_group( - title='Content Processing Options', - description=None -) +processing_options = options.add_group('Content Processing Options') -content_processing.add_argument( - '--compress', '-x', +processing_options.add_argument( + '--compress', + '-x', action='count', default=0, - help=''' + help=""" Content compressed (encoded) with Deflate algorithm. The Content-Encoding header is set to deflate. Compression is skipped if it appears that compression ratio is negative. Compression can be forced by repeating the argument. - ''' + """, ) ####################################################################### # Output processing ####################################################################### -output_processing = parser.add_argument_group(title='Output Processing') - -output_processing.add_argument( - '--pretty', - dest='prettify', - default=PRETTY_STDOUT_TTY_ONLY, - choices=sorted(PRETTY_MAP.keys()), - help=''' - Controls output processing. The value can be "none" to not prettify - the output (default for redirected output), "all" to apply both colors - and formatting (default for terminal output), "colors", or "format". - - ''' -) - def format_style_help(available_styles): - return ''' + return """ Output coloring style (default is "{default}"). It can be one of: {available_styles} @@ -261,92 +233,109 @@ def format_style_help(available_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( + """.format( default=DEFAULT_STYLE, available_styles='\n'.join( f' {line.strip()}' - for line in wrap(', '.join(available_styles), 60) + for line in textwrap.wrap(', '.join(available_styles), 60) ).strip(), auto_style=AUTO_STYLE, ) -output_processing.add_argument( - '--style', '-s', - dest='style', - metavar='STYLE', - default=DEFAULT_STYLE, - action='lazy_choices', - getter=get_available_styles, - help_formatter=format_style_help -) - _sorted_kwargs = { 'action': 'append_const', 'const': SORTED_FORMAT_OPTIONS_STRING, - 'dest': 'format_options' + 'dest': 'format_options', } _unsorted_kwargs = { 'action': 'append_const', 'const': UNSORTED_FORMAT_OPTIONS_STRING, - 'dest': 'format_options' + 'dest': 'format_options', } + +output_processing = options.add_group('Output Processing') + +output_processing.add_argument( + '--pretty', + dest='prettify', + default=PRETTY_STDOUT_TTY_ONLY, + choices=sorted(PRETTY_MAP.keys()), + help=""" + Controls output processing. The value can be "none" to not prettify + the output (default for redirected output), "all" to apply both colors + and formatting (default for terminal output), "colors", or "format". + + """, +) +output_processing.add_argument( + '--style', + '-s', + dest='style', + metavar='STYLE', + default=DEFAULT_STYLE, + action='lazy_choices', + getter=get_available_styles, + help_formatter=format_style_help, +) + # The closest approx. of the documented resetting to default via --no-
      + +
      + +[![HTTPie for Desktop](https://img.shields.io/static/v1?label=HTTPie&message=for%20Desktop&color=4B78E6)](https://httpie.io/product) +[![](https://img.shields.io/static/v1?label=HTTPie&message=for%20Web%20%26%20Mobile&color=73DC8C)](https://httpie.io/app) +[![](https://img.shields.io/static/v1?label=HTTPie&message=for%20Terminal&color=FA9BFA)](https://httpie.io/cli) + +
      HTTPie (pronounced _aitch-tee-tee-pie_) is a command-line HTTP client. Its goal is to make CLI interaction with web services as human-friendly as possible. @@ -13,14 +20,22 @@ HTTPie is designed for testing, debugging, and generally interacting with APIs & The `http` & `https` commands allow for creating and sending arbitrary HTTP requests. They use simple and natural syntax and provide formatted and colorized output. +
      + +HTTPie in action + +
      + [![Docs](https://img.shields.io/badge/stable%20docs-httpie.io%2Fdocs-brightgreen?style=flat&color=%2373DC8C&label=Docs)](https://httpie.org/docs) [![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/httpie) [![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions) [![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/httpie) [![Twitter](https://img.shields.io/twitter/follow/httpie?style=flat&color=%234B78E6&logoColor=%234B78E6)](https://twitter.com/httpie) [![Chat](https://img.shields.io/badge/chat-Discord-brightgreen?style=flat&label=Chat%20on&color=%23FA9BFA)](https://httpie.io/discord) + +
      + -HTTPie in action ## We lost 54k GitHub stars From c3a2f87dd27d325633310b73085c51f5bc4d9d2e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 10 Aug 2022 07:41:13 -0700 Subject: [PATCH 1114/1182] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ee4307532..4f2fe73f80 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ They use simple and natural syntax and provide formatted and colorized output.
      -[![Docs](https://img.shields.io/badge/stable%20docs-httpie.io%2Fdocs-brightgreen?style=flat&color=%2373DC8C&label=Docs)](https://httpie.org/docs) +[![Docs](https://img.shields.io/badge/stable%20docs-httpie.io%2Fdocs%2Fcli-brightgreen?style=flat&color=%2373DC8C&label=Docs)](https://httpie.org/docs/cli) [![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/httpie) [![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions) [![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/httpie) From 1236793272794fd6e741c74924b1ad70c9839bba Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 10 Aug 2022 07:48:57 -0700 Subject: [PATCH 1115/1182] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f2fe73f80..28d5676522 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ They use simple and natural syntax and provide formatted and colorized output. [![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions) [![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/httpie) [![Twitter](https://img.shields.io/twitter/follow/httpie?style=flat&color=%234B78E6&logoColor=%234B78E6)](https://twitter.com/httpie) -[![Chat](https://img.shields.io/badge/chat-Discord-brightgreen?style=flat&label=Chat%20on&color=%23FA9BFA)](https://httpie.io/discord) +[![Chat](https://img.shields.io/discord/725351238698270761?style=flat&label=Chat%20on%20Discord&color=%23FA9BFA)](https://httpie.io/discord) From 767f3c3a19196bbb5ed9d6707f72f83d8b556d40 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 10 Aug 2022 07:58:09 -0700 Subject: [PATCH 1116/1182] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 28d5676522..bc28569a5c 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ [![HTTPie for Desktop](https://img.shields.io/static/v1?label=HTTPie&message=for%20Desktop&color=4B78E6)](https://httpie.io/product) [![](https://img.shields.io/static/v1?label=HTTPie&message=for%20Web%20%26%20Mobile&color=73DC8C)](https://httpie.io/app) [![](https://img.shields.io/static/v1?label=HTTPie&message=for%20Terminal&color=FA9BFA)](https://httpie.io/cli) +[![Twitter](https://img.shields.io/twitter/follow/httpie?style=flat&color=%234B78E6&logoColor=%234B78E6)](https://twitter.com/httpie) +[![Chat](https://img.shields.io/discord/725351238698270761?style=flat&label=Chat%20on%20Discord&color=%23FA9BFA)](https://httpie.io/discord) @@ -30,8 +32,6 @@ They use simple and natural syntax and provide formatted and colorized output. [![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/httpie) [![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions) [![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/httpie) -[![Twitter](https://img.shields.io/twitter/follow/httpie?style=flat&color=%234B78E6&logoColor=%234B78E6)](https://twitter.com/httpie) -[![Chat](https://img.shields.io/discord/725351238698270761?style=flat&label=Chat%20on%20Discord&color=%23FA9BFA)](https://httpie.io/discord) From 810bb1c77b9ab3942d7aac76ab6ff8b9f796f403 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 10 Aug 2022 09:13:49 -0700 Subject: [PATCH 1117/1182] Update README.md --- README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bc28569a5c..ff929e221b 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,16 @@ + +
      + +[![Docs](https://img.shields.io/badge/stable%20docs-httpie.io%2Fdocs%2Fcli-brightgreen?style=flat&color=%2373DC8C&label=Docs)](https://httpie.org/docs/cli) +[![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/httpie) +[![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions) +[![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/httpie) + +
      + HTTPie (pronounced _aitch-tee-tee-pie_) is a command-line HTTP client. Its goal is to make CLI interaction with web services as human-friendly as possible. HTTPie is designed for testing, debugging, and generally interacting with APIs & HTTP servers. @@ -26,13 +36,7 @@ They use simple and natural syntax and provide formatted and colorized output. HTTPie in action -
      -[![Docs](https://img.shields.io/badge/stable%20docs-httpie.io%2Fdocs%2Fcli-brightgreen?style=flat&color=%2373DC8C&label=Docs)](https://httpie.org/docs/cli) -[![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/httpie) -[![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions) -[![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/httpie) - From 3549ee8342e1bf971a1103341595a2690a152a09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 03:31:54 -0700 Subject: [PATCH 1118/1182] Bump actions/stale from 5 to 6 (#1437) Bumps [actions/stale](https://github.com/actions/stale) from 5 to 6. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 417609674e..3e4d8998b7 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/stale@v5 + - uses: actions/stale@v6 with: close-pr-message: 'Thanks for the pull request, but since it was stale for more than a 30 days we are closing it. If you want to work back on it, feel free to re-open it or create a new one.' stale-pr-label: 'stale' From 930cd9081af01c8f2f4bc506cd0123f3862e11ba Mon Sep 17 00:00:00 2001 From: a1346054 <36859588+a1346054@users.noreply.github.com> Date: Sat, 1 Oct 2022 10:32:17 +0000 Subject: [PATCH 1119/1182] Use `grep -E` instead of `egrep` (#1436) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dff8fc21d2..a447b233a2 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ default: list-tasks list-tasks: @echo Available tasks: @echo ---------------- - @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' + @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | grep -E -v -e '^[^[:alnum:]]' -e '^$@$$' @echo From d9a73cd8eb66de4e6f75a0c883d6b29f4eea3831 Mon Sep 17 00:00:00 2001 From: Kian-Meng Ang Date: Sat, 1 Oct 2022 18:34:41 +0800 Subject: [PATCH 1120/1182] Fix typos (#1431) Found via `codespell -L datas`. --- docs/contributors/README.md | 2 +- docs/installation/generate.py | 2 +- extras/profiling/benchmarks.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/contributors/README.md b/docs/contributors/README.md index 20b3c278fb..9a739cd543 100644 --- a/docs/contributors/README.md +++ b/docs/contributors/README.md @@ -1,3 +1,3 @@ -Here we maintain a database of contributors, from which we generate credits on release blog posts and social medias. +Here we maintain a database of contributors, from which we generate credits on release blog posts and social media. For the HTTPie blog see: . diff --git a/docs/installation/generate.py b/docs/installation/generate.py index a67389ddd5..0597a3a429 100644 --- a/docs/installation/generate.py +++ b/docs/installation/generate.py @@ -55,7 +55,7 @@ def build_docs_structure(database: Database): tree = database[KEY_DOC_STRUCTURE] structure = [] for platform, tools_ids in tree.items(): - assert platform.isalnum(), f'{platform=} must be alpha-numeric for generated links to work' + assert platform.isalnum(), f'{platform=} must be alphanumeric for generated links to work' platform_tools = [tools[tool_id] for tool_id in tools_ids] structure.append((platform, platform_tools)) return structure diff --git a/extras/profiling/benchmarks.py b/extras/profiling/benchmarks.py index c7374f6abe..9d409debbe 100644 --- a/extras/profiling/benchmarks.py +++ b/extras/profiling/benchmarks.py @@ -13,7 +13,7 @@ Examples: - # Run everything as usual, the default is that we do 3 warmup runs + # Run everything as usual, the default is that we do 3 warm-up runs # and 5 actual runs. $ python extras/profiling/benchmarks.py @@ -188,7 +188,7 @@ def run(self, context: Context) -> pyperf.Benchmark: def main() -> None: # PyPerf will bring it's own argument parser, so configure the script. # The somewhat fast and also precise enough configuration is this. We run - # benchmarks 3 times to warmup (e.g especially for download benchmark, this + # benchmarks 3 times to warm up (e.g especially for download benchmark, this # is important). And then 5 actual runs where we record. sys.argv.extend( ['--worker', '--loops=1', '--warmup=3', '--values=5', '--processes=2'] From a7321d8ac41f55ca932210ec412c18eb3c50421a Mon Sep 17 00:00:00 2001 From: Ben Chatelain Date: Sat, 1 Oct 2022 04:37:50 -0600 Subject: [PATCH 1121/1182] =?UTF-8?q?=F0=9F=94=A5=20Remove=20$=20from=20co?= =?UTF-8?q?de=20fenced=20examples=20on=20readme=20(#1435)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔥 Remove $ from code fenced examples on readme * 🚨 FIx markdownlint errors README.md:8: MD009 Trailing spaces README.md:10: MD009 Trailing spaces --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ff929e221b..d1a90e329a 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@
      HTTPie: human-friendly CLI HTTP client for the API era - +
      - + [![HTTPie for Desktop](https://img.shields.io/static/v1?label=HTTPie&message=for%20Desktop&color=4B78E6)](https://httpie.io/product) [![](https://img.shields.io/static/v1?label=HTTPie&message=for%20Web%20%26%20Mobile&color=73DC8C)](https://httpie.io/app) [![](https://img.shields.io/static/v1?label=HTTPie&message=for%20Terminal&color=FA9BFA)](https://httpie.io/cli) @@ -73,25 +73,25 @@ Please note we recently accidentally made this repo private for a moment, and Gi Hello World: ```bash -$ https httpie.io/hello +https httpie.io/hello ``` Custom [HTTP method](https://httpie.io/docs#http-method), [HTTP headers](https://httpie.io/docs#http-headers) and [JSON](https://httpie.io/docs#json) data: ```bash -$ http PUT pie.dev/put X-API-Token:123 name=John +http PUT pie.dev/put X-API-Token:123 name=John ``` Build and print a request without sending it using [offline mode](https://httpie.io/docs#offline-mode): ```bash -$ http --offline pie.dev/post hello=offline +http --offline pie.dev/post hello=offline ``` Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comment) to post a comment on an [Issue](https://github.com/httpie/httpie/issues/83) with [authentication](https://httpie.io/docs#authentication): ```bash -$ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comments body='HTTPie is awesome! :heart:' +http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comments body='HTTPie is awesome! :heart:' ``` [See more examples →](https://httpie.io/docs#examples) From 0689b55e1d0a16385b7e275db4458c155d746b6a Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 1 Oct 2022 12:38:19 +0200 Subject: [PATCH 1122/1182] Clean up and refactor nested JSON parsing & interpreting (#1440) --- extras/scripts/generate_man_pages.py | 2 +- httpie/cli/dicts.py | 4 - httpie/cli/nested_json.py | 404 --------------------------- httpie/cli/nested_json/__init__.py | 20 ++ httpie/cli/nested_json/errors.py | 27 ++ httpie/cli/nested_json/interpret.py | 129 +++++++++ httpie/cli/nested_json/parse.py | 193 +++++++++++++ httpie/cli/nested_json/tokens.py | 80 ++++++ httpie/cli/requestitems.py | 64 +++-- httpie/client.py | 17 +- httpie/core.py | 4 +- httpie/utils.py | 2 +- tests/test_json.py | 30 +- 13 files changed, 507 insertions(+), 469 deletions(-) delete mode 100644 httpie/cli/nested_json.py create mode 100644 httpie/cli/nested_json/__init__.py create mode 100644 httpie/cli/nested_json/errors.py create mode 100644 httpie/cli/nested_json/interpret.py create mode 100644 httpie/cli/nested_json/parse.py create mode 100644 httpie/cli/nested_json/tokens.py diff --git a/extras/scripts/generate_man_pages.py b/extras/scripts/generate_man_pages.py index 530348866b..71e0100f39 100644 --- a/extras/scripts/generate_man_pages.py +++ b/extras/scripts/generate_man_pages.py @@ -9,7 +9,7 @@ from httpie.manager.cli import options as manager_options from httpie.output.ui.rich_help import OptionsHighlighter, to_usage from httpie.output.ui.rich_utils import render_as_string -from httpie.utils import split +from httpie.utils import split_iterable # Escape certain characters so they are rendered properly on diff --git a/httpie/cli/dicts.py b/httpie/cli/dicts.py index 074cd9e758..6b6d4736d2 100644 --- a/httpie/cli/dicts.py +++ b/httpie/cli/dicts.py @@ -92,7 +92,3 @@ class MultipartRequestDataDict(MultiValueOrderedDict): class RequestFilesDict(RequestDataDict): pass - - -class NestedJSONArray(list): - """Denotes a top-level JSON array.""" diff --git a/httpie/cli/nested_json.py b/httpie/cli/nested_json.py deleted file mode 100644 index 6616e9acda..0000000000 --- a/httpie/cli/nested_json.py +++ /dev/null @@ -1,404 +0,0 @@ -from enum import Enum, auto -from typing import ( - Any, - Iterator, - NamedTuple, - Optional, - List, - NoReturn, - Type, - Union, -) -from .dicts import NestedJSONArray - - -EMPTY_STRING = '' -HIGHLIGHTER = '^' -OPEN_BRACKET = '[' -CLOSE_BRACKET = ']' -BACKSLASH = '\\' - - -class HTTPieSyntaxError(ValueError): - def __init__( - self, - source: str, - token: Optional['Token'], - message: str, - message_kind: str = 'Syntax', - ) -> None: - self.source = source - self.token = token - self.message = message - self.message_kind = message_kind - - def __str__(self): - lines = [f'HTTPie {self.message_kind} Error: {self.message}'] - if self.token is not None: - lines.append(self.source) - lines.append( - ' ' * self.token.start - + HIGHLIGHTER * (self.token.end - self.token.start) - ) - return '\n'.join(lines) - - -class TokenKind(Enum): - TEXT = auto() - NUMBER = auto() - LEFT_BRACKET = auto() - RIGHT_BRACKET = auto() - - def to_name(self) -> str: - for key, value in OPERATORS.items(): - if value is self: - return repr(key) - else: - return 'a ' + self.name.lower() - - -OPERATORS = { - OPEN_BRACKET: TokenKind.LEFT_BRACKET, - CLOSE_BRACKET: TokenKind.RIGHT_BRACKET, -} -SPECIAL_CHARS = OPERATORS.keys() | {BACKSLASH} -LITERAL_TOKENS = [ - TokenKind.TEXT, - TokenKind.NUMBER, -] - - -class Token(NamedTuple): - kind: TokenKind - value: Union[str, int] - start: int - end: int - - -def assert_cant_happen() -> NoReturn: - raise ValueError('Unexpected value') - - -def check_escaped_int(value: str) -> str: - if not value.startswith(BACKSLASH): - raise ValueError('Not an escaped int') - - try: - int(value[1:]) - except ValueError as exc: - raise ValueError('Not an escaped int') from exc - else: - return value[1:] - - -def tokenize(source: str) -> Iterator[Token]: - cursor = 0 - backslashes = 0 - buffer = [] - - def send_buffer() -> Iterator[Token]: - nonlocal backslashes - if not buffer: - return None - - value = ''.join(buffer) - kind = TokenKind.TEXT - if not backslashes: - for variation, kind in [ - (int, TokenKind.NUMBER), - (check_escaped_int, TokenKind.TEXT), - ]: - try: - value = variation(value) - except ValueError: - continue - else: - break - - yield Token( - kind, value, start=cursor - (len(buffer) + backslashes), end=cursor - ) - buffer.clear() - backslashes = 0 - - def can_advance() -> bool: - return cursor < len(source) - - while can_advance(): - index = source[cursor] - if index in OPERATORS: - yield from send_buffer() - yield Token(OPERATORS[index], index, cursor, cursor + 1) - elif index == BACKSLASH and can_advance(): - if source[cursor + 1] in SPECIAL_CHARS: - backslashes += 1 - else: - buffer.append(index) - - buffer.append(source[cursor + 1]) - cursor += 1 - else: - buffer.append(index) - - cursor += 1 - - yield from send_buffer() - - -class PathAction(Enum): - KEY = auto() - INDEX = auto() - APPEND = auto() - - # Pseudo action, used by the interpreter - SET = auto() - - def to_string(self) -> str: - return self.name.lower() - - -class Path: - def __init__( - self, - kind: PathAction, - accessor: Optional[Union[str, int]] = None, - tokens: Optional[List[Token]] = None, - is_root: bool = False, - ): - self.kind = kind - self.accessor = accessor - self.tokens = tokens or [] - self.is_root = is_root - - def reconstruct(self) -> str: - if self.kind is PathAction.KEY: - if self.is_root: - return str(self.accessor) - return OPEN_BRACKET + self.accessor + CLOSE_BRACKET - elif self.kind is PathAction.INDEX: - return OPEN_BRACKET + str(self.accessor) + CLOSE_BRACKET - elif self.kind is PathAction.APPEND: - return OPEN_BRACKET + CLOSE_BRACKET - else: - assert_cant_happen() - - -def parse(source: str) -> Iterator[Path]: - """ - start: root_path path* - root_path: (literal | index_path | append_path) - literal: TEXT | NUMBER - - path: - key_path - | index_path - | append_path - key_path: LEFT_BRACKET TEXT RIGHT_BRACKET - index_path: LEFT_BRACKET NUMBER RIGHT_BRACKET - append_path: LEFT_BRACKET RIGHT_BRACKET - """ - - tokens = list(tokenize(source)) - cursor = 0 - - def can_advance(): - return cursor < len(tokens) - - def expect(*kinds): - nonlocal cursor - - assert len(kinds) > 0 - if can_advance(): - token = tokens[cursor] - cursor += 1 - if token.kind in kinds: - return token - elif tokens: - token = tokens[-1]._replace( - start=tokens[-1].end + 0, end=tokens[-1].end + 1 - ) - else: - token = None - - if len(kinds) == 1: - suffix = kinds[0].to_name() - else: - suffix = ', '.join(kind.to_name() for kind in kinds[:-1]) - suffix += ' or ' + kinds[-1].to_name() - - message = f'Expecting {suffix}' - raise HTTPieSyntaxError(source, token, message) - - def parse_root(): - tokens = [] - if not can_advance(): - return Path( - PathAction.KEY, - EMPTY_STRING, - is_root=True - ) - - # (literal | index_path | append_path)? - token = expect(*LITERAL_TOKENS, TokenKind.LEFT_BRACKET) - tokens.append(token) - - if token.kind in LITERAL_TOKENS: - action = PathAction.KEY - value = str(token.value) - elif token.kind is TokenKind.LEFT_BRACKET: - token = expect(TokenKind.NUMBER, TokenKind.RIGHT_BRACKET) - tokens.append(token) - if token.kind is TokenKind.NUMBER: - action = PathAction.INDEX - value = token.value - tokens.append(expect(TokenKind.RIGHT_BRACKET)) - elif token.kind is TokenKind.RIGHT_BRACKET: - action = PathAction.APPEND - value = None - else: - assert_cant_happen() - else: - assert_cant_happen() - - return Path( - action, - value, - tokens=tokens, - is_root=True - ) - - yield parse_root() - - # path* - while can_advance(): - path_tokens = [] - path_tokens.append(expect(TokenKind.LEFT_BRACKET)) - - token = expect( - TokenKind.TEXT, TokenKind.NUMBER, TokenKind.RIGHT_BRACKET - ) - path_tokens.append(token) - if token.kind is TokenKind.RIGHT_BRACKET: - path = Path(PathAction.APPEND, tokens=path_tokens) - elif token.kind is TokenKind.TEXT: - path = Path(PathAction.KEY, token.value, tokens=path_tokens) - path_tokens.append(expect(TokenKind.RIGHT_BRACKET)) - elif token.kind is TokenKind.NUMBER: - path = Path(PathAction.INDEX, token.value, tokens=path_tokens) - path_tokens.append(expect(TokenKind.RIGHT_BRACKET)) - else: - assert_cant_happen() - yield path - - -JSON_TYPE_MAPPING = { - dict: 'object', - list: 'array', - int: 'number', - float: 'number', - str: 'string', -} - - -def interpret(context: Any, key: str, value: Any) -> Any: - cursor = context - - paths = list(parse(key)) - paths.append(Path(PathAction.SET, value)) - - def type_check(index: int, path: Path, expected_type: Type[Any]) -> None: - if not isinstance(cursor, expected_type): - if path.tokens: - pseudo_token = Token( - None, None, path.tokens[0].start, path.tokens[-1].end - ) - else: - pseudo_token = None - - cursor_type = JSON_TYPE_MAPPING.get( - type(cursor), type(cursor).__name__ - ) - required_type = JSON_TYPE_MAPPING[expected_type] - - message = f"Can't perform {path.kind.to_string()!r} based access on " - message += repr( - ''.join(path.reconstruct() for path in paths[:index]) - ) - message += ( - f' which has a type of {cursor_type!r} but this operation' - ) - message += f' requires a type of {required_type!r}.' - raise HTTPieSyntaxError( - key, pseudo_token, message, message_kind='Type' - ) - - def object_for(kind: str) -> Any: - if kind is PathAction.KEY: - return {} - elif kind in {PathAction.INDEX, PathAction.APPEND}: - return [] - else: - assert_cant_happen() - - for index, (path, next_path) in enumerate(zip(paths, paths[1:])): - # If there is no context yet, set it. - if cursor is None: - context = cursor = object_for(path.kind) - - if path.kind is PathAction.KEY: - type_check(index, path, dict) - if next_path.kind is PathAction.SET: - cursor[path.accessor] = next_path.accessor - break - - cursor = cursor.setdefault( - path.accessor, object_for(next_path.kind) - ) - elif path.kind is PathAction.INDEX: - type_check(index, path, list) - if path.accessor < 0: - raise HTTPieSyntaxError( - key, - path.tokens[1], - 'Negative indexes are not supported.', - message_kind='Value', - ) - cursor.extend([None] * (path.accessor - len(cursor) + 1)) - if next_path.kind is PathAction.SET: - cursor[path.accessor] = next_path.accessor - break - - if cursor[path.accessor] is None: - cursor[path.accessor] = object_for(next_path.kind) - - cursor = cursor[path.accessor] - elif path.kind is PathAction.APPEND: - type_check(index, path, list) - if next_path.kind is PathAction.SET: - cursor.append(next_path.accessor) - break - - cursor.append(object_for(next_path.kind)) - cursor = cursor[-1] - else: - assert_cant_happen() - - return context - - -def wrap_with_dict(context): - if context is None: - return {} - elif isinstance(context, list): - return {EMPTY_STRING: NestedJSONArray(context)} - else: - assert isinstance(context, dict) - return context - - -def interpret_nested_json(pairs): - context = None - for key, value in pairs: - context = interpret(context, key, value) - - return wrap_with_dict(context) diff --git a/httpie/cli/nested_json/__init__.py b/httpie/cli/nested_json/__init__.py new file mode 100644 index 0000000000..17b129abf3 --- /dev/null +++ b/httpie/cli/nested_json/__init__.py @@ -0,0 +1,20 @@ +""" +A library for parsing the HTTPie nested JSON key syntax and constructing the resulting objects. + + + +It has no dependencies. + +""" +from .interpret import interpret_nested_json, unwrap_top_level_list_if_needed +from .errors import NestedJSONSyntaxError +from .tokens import EMPTY_STRING, NestedJSONArray + + +__all__ = [ + 'interpret_nested_json', + 'unwrap_top_level_list_if_needed', + 'EMPTY_STRING', + 'NestedJSONArray', + 'NestedJSONSyntaxError' +] diff --git a/httpie/cli/nested_json/errors.py b/httpie/cli/nested_json/errors.py new file mode 100644 index 0000000000..f53f871566 --- /dev/null +++ b/httpie/cli/nested_json/errors.py @@ -0,0 +1,27 @@ +from typing import Optional + +from .tokens import Token, HIGHLIGHTER + + +class NestedJSONSyntaxError(ValueError): + def __init__( + self, + source: str, + token: Optional[Token], + message: str, + message_kind: str = 'Syntax', + ) -> None: + self.source = source + self.token = token + self.message = message + self.message_kind = message_kind + + def __str__(self): + lines = [f'HTTPie {self.message_kind} Error: {self.message}'] + if self.token is not None: + lines.append(self.source) + lines.append( + ' ' * self.token.start + + HIGHLIGHTER * (self.token.end - self.token.start) + ) + return '\n'.join(lines) diff --git a/httpie/cli/nested_json/interpret.py b/httpie/cli/nested_json/interpret.py new file mode 100644 index 0000000000..71fad98acd --- /dev/null +++ b/httpie/cli/nested_json/interpret.py @@ -0,0 +1,129 @@ +from typing import Type, Union, Any, Iterable, Tuple + +from .parse import parse, assert_cant_happen +from .errors import NestedJSONSyntaxError +from .tokens import EMPTY_STRING, TokenKind, Token, PathAction, Path, NestedJSONArray + + +__all__ = [ + 'interpret_nested_json', + 'unwrap_top_level_list_if_needed', +] + +JSONType = Type[Union[dict, list, int, float, str]] +JSON_TYPE_MAPPING = { + dict: 'object', + list: 'array', + int: 'number', + float: 'number', + str: 'string', +} + + +def interpret_nested_json(pairs: Iterable[Tuple[str, str]]) -> dict: + context = None + for key, value in pairs: + context = interpret(context, key, value) + return wrap_with_dict(context) + + +def interpret(context: Any, key: str, value: Any) -> Any: + cursor = context + paths = list(parse(key)) + paths.append(Path(PathAction.SET, value)) + + # noinspection PyShadowingNames + def type_check(index: int, path: Path, expected_type: JSONType): + if not isinstance(cursor, expected_type): + if path.tokens: + pseudo_token = Token( + kind=TokenKind.PSEUDO, + value='', + start=path.tokens[0].start, + end=path.tokens[-1].end, + ) + else: + pseudo_token = None + cursor_type = JSON_TYPE_MAPPING.get(type(cursor), type(cursor).__name__) + required_type = JSON_TYPE_MAPPING[expected_type] + message = f'Cannot perform {path.kind.to_string()!r} based access on ' + message += repr(''.join(path.reconstruct() for path in paths[:index])) + message += f' which has a type of {cursor_type!r} but this operation' + message += f' requires a type of {required_type!r}.' + raise NestedJSONSyntaxError( + source=key, + token=pseudo_token, + message=message, + message_kind='Type', + ) + + def object_for(kind: PathAction) -> Any: + if kind is PathAction.KEY: + return {} + elif kind in {PathAction.INDEX, PathAction.APPEND}: + return [] + else: + assert_cant_happen() + + for index, (path, next_path) in enumerate(zip(paths, paths[1:])): + # If there is no context yet, set it. + if cursor is None: + context = cursor = object_for(path.kind) + if path.kind is PathAction.KEY: + type_check(index, path, dict) + if next_path.kind is PathAction.SET: + cursor[path.accessor] = next_path.accessor + break + cursor = cursor.setdefault(path.accessor, object_for(next_path.kind)) + elif path.kind is PathAction.INDEX: + type_check(index, path, list) + if path.accessor < 0: + raise NestedJSONSyntaxError( + source=key, + token=path.tokens[1], + message='Negative indexes are not supported.', + message_kind='Value', + ) + cursor.extend([None] * (path.accessor - len(cursor) + 1)) + if next_path.kind is PathAction.SET: + cursor[path.accessor] = next_path.accessor + break + if cursor[path.accessor] is None: + cursor[path.accessor] = object_for(next_path.kind) + cursor = cursor[path.accessor] + elif path.kind is PathAction.APPEND: + type_check(index, path, list) + if next_path.kind is PathAction.SET: + cursor.append(next_path.accessor) + break + cursor.append(object_for(next_path.kind)) + cursor = cursor[-1] + else: + assert_cant_happen() + + return context + + +def wrap_with_dict(context): + if context is None: + return {} + elif isinstance(context, list): + return { + EMPTY_STRING: NestedJSONArray(context), + } + else: + assert isinstance(context, dict) + return context + + +def unwrap_top_level_list_if_needed(data: dict): + """ + Propagate the top-level list, if that’s what we got. + + """ + if len(data) == 1: + key, value = list(data.items())[0] + if isinstance(value, NestedJSONArray): + assert key == EMPTY_STRING + return value + return data diff --git a/httpie/cli/nested_json/parse.py b/httpie/cli/nested_json/parse.py new file mode 100644 index 0000000000..323a22eef1 --- /dev/null +++ b/httpie/cli/nested_json/parse.py @@ -0,0 +1,193 @@ +from typing import Iterator + +from .errors import NestedJSONSyntaxError +from .tokens import ( + EMPTY_STRING, + BACKSLASH, + TokenKind, + OPERATORS, + SPECIAL_CHARS, + LITERAL_TOKENS, + Token, + PathAction, + Path, +) + + +__all__ = [ + 'parse', + 'assert_cant_happen', +] + + +def parse(source: str) -> Iterator[Path]: + """ + start: root_path path* + root_path: (literal | index_path | append_path) + literal: TEXT | NUMBER + + path: + key_path + | index_path + | append_path + key_path: LEFT_BRACKET TEXT RIGHT_BRACKET + index_path: LEFT_BRACKET NUMBER RIGHT_BRACKET + append_path: LEFT_BRACKET RIGHT_BRACKET + + """ + + tokens = list(tokenize(source)) + cursor = 0 + + def can_advance(): + return cursor < len(tokens) + + # noinspection PyShadowingNames + def expect(*kinds): + nonlocal cursor + assert kinds + if can_advance(): + token = tokens[cursor] + cursor += 1 + if token.kind in kinds: + return token + elif tokens: + token = tokens[-1]._replace( + start=tokens[-1].end + 0, + end=tokens[-1].end + 1, + ) + else: + token = None + if len(kinds) == 1: + suffix = kinds[0].to_name() + else: + suffix = ', '.join(kind.to_name() for kind in kinds[:-1]) + suffix += ' or ' + kinds[-1].to_name() + message = f'Expecting {suffix}' + raise NestedJSONSyntaxError(source, token, message) + + # noinspection PyShadowingNames + def parse_root(): + tokens = [] + if not can_advance(): + return Path( + kind=PathAction.KEY, + accessor=EMPTY_STRING, + is_root=True + ) + # (literal | index_path | append_path)? + token = expect(*LITERAL_TOKENS, TokenKind.LEFT_BRACKET) + tokens.append(token) + if token.kind in LITERAL_TOKENS: + action = PathAction.KEY + value = str(token.value) + elif token.kind is TokenKind.LEFT_BRACKET: + token = expect(TokenKind.NUMBER, TokenKind.RIGHT_BRACKET) + tokens.append(token) + if token.kind is TokenKind.NUMBER: + action = PathAction.INDEX + value = token.value + tokens.append(expect(TokenKind.RIGHT_BRACKET)) + elif token.kind is TokenKind.RIGHT_BRACKET: + action = PathAction.APPEND + value = None + else: + assert_cant_happen() + else: + assert_cant_happen() + # noinspection PyUnboundLocalVariable + return Path( + kind=action, + accessor=value, + tokens=tokens, + is_root=True + ) + + yield parse_root() + + # path* + while can_advance(): + path_tokens = [expect(TokenKind.LEFT_BRACKET)] + token = expect(TokenKind.TEXT, TokenKind.NUMBER, TokenKind.RIGHT_BRACKET) + path_tokens.append(token) + if token.kind is TokenKind.RIGHT_BRACKET: + path = Path(PathAction.APPEND, tokens=path_tokens) + elif token.kind is TokenKind.TEXT: + path = Path(PathAction.KEY, token.value, tokens=path_tokens) + path_tokens.append(expect(TokenKind.RIGHT_BRACKET)) + elif token.kind is TokenKind.NUMBER: + path = Path(PathAction.INDEX, token.value, tokens=path_tokens) + path_tokens.append(expect(TokenKind.RIGHT_BRACKET)) + else: + assert_cant_happen() + # noinspection PyUnboundLocalVariable + yield path + + +def tokenize(source: str) -> Iterator[Token]: + cursor = 0 + backslashes = 0 + buffer = [] + + def send_buffer() -> Iterator[Token]: + nonlocal backslashes + if not buffer: + return None + + value = ''.join(buffer) + kind = TokenKind.TEXT + if not backslashes: + for variation, kind in [ + (int, TokenKind.NUMBER), + (check_escaped_int, TokenKind.TEXT), + ]: + try: + value = variation(value) + except ValueError: + continue + else: + break + yield Token( + kind=kind, + value=value, + start=cursor - (len(buffer) + backslashes), + end=cursor, + ) + buffer.clear() + backslashes = 0 + + def can_advance() -> bool: + return cursor < len(source) + + while can_advance(): + index = source[cursor] + if index in OPERATORS: + yield from send_buffer() + yield Token(OPERATORS[index], index, cursor, cursor + 1) + elif index == BACKSLASH and can_advance(): + if source[cursor + 1] in SPECIAL_CHARS: + backslashes += 1 + else: + buffer.append(index) + buffer.append(source[cursor + 1]) + cursor += 1 + else: + buffer.append(index) + cursor += 1 + + yield from send_buffer() + + +def check_escaped_int(value: str) -> str: + if not value.startswith(BACKSLASH): + raise ValueError('Not an escaped int') + try: + int(value[1:]) + except ValueError as exc: + raise ValueError('Not an escaped int') from exc + else: + return value[1:] + + +def assert_cant_happen(): + raise ValueError('Unexpected value') diff --git a/httpie/cli/nested_json/tokens.py b/httpie/cli/nested_json/tokens.py new file mode 100644 index 0000000000..e8f3f4c12f --- /dev/null +++ b/httpie/cli/nested_json/tokens.py @@ -0,0 +1,80 @@ +from enum import Enum, auto +from typing import NamedTuple, Union, Optional, List + +EMPTY_STRING = '' +HIGHLIGHTER = '^' +OPEN_BRACKET = '[' +CLOSE_BRACKET = ']' +BACKSLASH = '\\' + + +class TokenKind(Enum): + TEXT = auto() + NUMBER = auto() + LEFT_BRACKET = auto() + RIGHT_BRACKET = auto() + PSEUDO = auto() # Not a real token, use when representing location only. + + def to_name(self) -> str: + for key, value in OPERATORS.items(): + if value is self: + return repr(key) + else: + return 'a ' + self.name.lower() + + +OPERATORS = { + OPEN_BRACKET: TokenKind.LEFT_BRACKET, + CLOSE_BRACKET: TokenKind.RIGHT_BRACKET, +} +SPECIAL_CHARS = OPERATORS.keys() | {BACKSLASH} +LITERAL_TOKENS = [ + TokenKind.TEXT, + TokenKind.NUMBER, +] + + +class Token(NamedTuple): + kind: TokenKind + value: Union[str, int] + start: int + end: int + + +class PathAction(Enum): + KEY = auto() + INDEX = auto() + APPEND = auto() + # Pseudo action, used by the interpreter + SET = auto() + + def to_string(self) -> str: + return self.name.lower() + + +class Path: + def __init__( + self, + kind: PathAction, + accessor: Optional[Union[str, int]] = None, + tokens: Optional[List[Token]] = None, + is_root: bool = False, + ): + self.kind = kind + self.accessor = accessor + self.tokens = tokens or [] + self.is_root = is_root + + def reconstruct(self) -> str: + if self.kind is PathAction.KEY: + if self.is_root: + return str(self.accessor) + return OPEN_BRACKET + self.accessor + CLOSE_BRACKET + elif self.kind is PathAction.INDEX: + return OPEN_BRACKET + str(self.accessor) + CLOSE_BRACKET + elif self.kind is PathAction.APPEND: + return OPEN_BRACKET + CLOSE_BRACKET + + +class NestedJSONArray(list): + """Denotes a top-level JSON array.""" diff --git a/httpie/cli/requestitems.py b/httpie/cli/requestitems.py index 96731b59a2..8931b88ac7 100644 --- a/httpie/cli/requestitems.py +++ b/httpie/cli/requestitems.py @@ -18,7 +18,7 @@ ) from .exceptions import ParseError from .nested_json import interpret_nested_json -from ..utils import get_content_type, load_json_preserve_order_and_dupe_keys, split +from ..utils import get_content_type, load_json_preserve_order_and_dupe_keys, split_iterable class RequestItems: @@ -78,25 +78,28 @@ def from_args( instance.data, ), SEPARATOR_DATA_RAW_JSON: ( - json_only(instance, process_data_raw_json_embed_arg), + convert_json_value_to_form_if_needed( + in_json_mode=instance.is_json, + processor=process_data_raw_json_embed_arg + ), instance.data, ), SEPARATOR_DATA_EMBED_RAW_JSON_FILE: ( - json_only(instance, process_data_embed_raw_json_file_arg), + convert_json_value_to_form_if_needed( + in_json_mode=instance.is_json, + processor=process_data_embed_raw_json_file_arg, + ), instance.data, ), } if instance.is_json: - json_item_args, request_item_args = split( - request_item_args, - lambda arg: arg.sep in SEPARATOR_GROUP_NESTED_JSON_ITEMS + json_item_args, request_item_args = split_iterable( + iterable=request_item_args, + key=lambda arg: arg.sep in SEPARATOR_GROUP_NESTED_JSON_ITEMS ) if json_item_args: - pairs = [ - (arg.key, rules[arg.sep][0](arg)) - for arg in json_item_args - ] + pairs = [(arg.key, rules[arg.sep][0](arg)) for arg in json_item_args] processor_func, target_dict = rules[SEPARATOR_GROUP_NESTED_JSON_ITEMS] value = processor_func(pairs) target_dict.update(value) @@ -159,37 +162,38 @@ def process_file_upload_arg(arg: KeyValueArg) -> Tuple[str, IO, str]: ) -def process_data_item_arg(arg: KeyValueArg) -> str: - return arg.value - - -def process_data_embed_file_contents_arg(arg: KeyValueArg) -> str: - return load_text_file(arg) +def convert_json_value_to_form_if_needed(in_json_mode: bool, processor: Callable[[KeyValueArg], JSONType]) -> Callable[[], str]: + """ + We allow primitive values to be passed to forms via JSON key/value syntax. + But complex values lead to an error because there’s no clear way to serialize them. -def json_only(items: RequestItems, func: Callable[[KeyValueArg], JSONType]) -> str: - if items.is_json: - return func + """ + if in_json_mode: + return processor - @functools.wraps(func) + @functools.wraps(processor) def wrapper(*args, **kwargs) -> str: try: - ret = func(*args, **kwargs) + output = processor(*args, **kwargs) except ParseError: - ret = None - - # If it is a basic type, then allow it - if isinstance(ret, (str, int, float)): - return str(ret) + output = None + if isinstance(output, (str, int, float)): + return str(output) else: - raise ParseError( - 'Can\'t use complex JSON value types with ' - '--form/--multipart.' - ) + raise ParseError('Cannot use complex JSON value types with --form/--multipart.') return wrapper +def process_data_item_arg(arg: KeyValueArg) -> str: + return arg.value + + +def process_data_embed_file_contents_arg(arg: KeyValueArg) -> str: + return load_text_file(arg) + + def process_data_embed_raw_json_file_arg(arg: KeyValueArg) -> JSONType: contents = load_text_file(arg) value = load_json(arg, contents) diff --git a/httpie/client.py b/httpie/client.py index 97608e782f..815ec559b2 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -10,12 +10,13 @@ import requests # noinspection PyPackageRequirements import urllib3 + from . import __version__ from .adapters import HTTPieHTTPAdapter -from .context import Environment from .cli.constants import HTTP_OPTIONS -from .cli.nested_json import EMPTY_STRING -from .cli.dicts import HTTPHeadersDict, NestedJSONArray +from .cli.dicts import HTTPHeadersDict +from .cli.nested_json import unwrap_top_level_list_if_needed +from .context import Environment from .encoding import UTF8 from .models import RequestsMessage from .plugins.registry import plugin_manager @@ -306,21 +307,13 @@ def make_send_kwargs_mergeable_from_env(args: argparse.Namespace) -> dict: def json_dict_to_request_body(data: Dict[str, Any]) -> str: - # Propagate the top-level list if there is only one - # item in the object, with an en empty key. - if len(data) == 1: - [(key, value)] = data.items() - if isinstance(value, NestedJSONArray): - assert key == EMPTY_STRING - data = value - + data = unwrap_top_level_list_if_needed(data) if data: data = json.dumps(data) else: # We need to set data to an empty string to prevent requests # from assigning an empty list to `response.request.data`. data = '' - return data diff --git a/httpie/core.py b/httpie/core.py index c90452a0b7..d0c26dcbcc 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -11,7 +11,7 @@ from . import __version__ as httpie_version from .cli.constants import OUT_REQ_BODY -from .cli.nested_json import HTTPieSyntaxError +from .cli.nested_json import NestedJSONSyntaxError from .client import collect_messages from .context import Environment, LogLevel from .downloads import Downloader @@ -78,7 +78,7 @@ def handle_generic_error(e, annotation=None): args=args, env=env, ) - except HTTPieSyntaxError as exc: + except NestedJSONSyntaxError as exc: env.stderr.write(str(exc) + "\n") if include_traceback: raise diff --git a/httpie/utils.py b/httpie/utils.py index 0c4e0048e7..4735b2be5d 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -245,7 +245,7 @@ def get_site_paths(path: Path) -> Iterable[Path]: yield as_site(path) -def split(iterable: Iterable[T], key: Callable[[T], bool]) -> Tuple[List[T], List[T]]: +def split_iterable(iterable: Iterable[T], key: Callable[[T], bool]) -> Tuple[List[T], List[T]]: left, right = [], [] for item in iterable: if key(item): diff --git a/tests/test_json.py b/tests/test_json.py index 2ba603a680..e758ebe7f4 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -5,7 +5,7 @@ from httpie.cli.constants import PRETTY_MAP from httpie.cli.exceptions import ParseError -from httpie.cli.nested_json import HTTPieSyntaxError +from httpie.cli.nested_json import NestedJSONSyntaxError from httpie.output.formatters.colors import ColorFormatter from httpie.utils import JsonDictPreservingDuplicateKeys @@ -157,7 +157,7 @@ def test_complex_json_arguments_with_non_json(httpbin, request_type, value): f'option:={json.dumps(value)}', ) - cm.match("Can't use complex JSON value types") + cm.match('Cannot use complex JSON value types') @pytest.mark.parametrize( @@ -508,23 +508,23 @@ def test_nested_json_syntax(input_json, expected_json, httpbin): ), ( ['foo=1', 'foo[key]:=2'], - "HTTPie Type Error: Can't perform 'key' based access on 'foo' which has a type of 'string' but this operation requires a type of 'object'.\nfoo[key]\n ^^^^^", + "HTTPie Type Error: Cannot perform 'key' based access on 'foo' which has a type of 'string' but this operation requires a type of 'object'.\nfoo[key]\n ^^^^^", ), ( ['foo=1', 'foo[0]:=2'], - "HTTPie Type Error: Can't perform 'index' based access on 'foo' which has a type of 'string' but this operation requires a type of 'array'.\nfoo[0]\n ^^^", + "HTTPie Type Error: Cannot perform 'index' based access on 'foo' which has a type of 'string' but this operation requires a type of 'array'.\nfoo[0]\n ^^^", ), ( ['foo=1', 'foo[]:=2'], - "HTTPie Type Error: Can't perform 'append' based access on 'foo' which has a type of 'string' but this operation requires a type of 'array'.\nfoo[]\n ^^", + "HTTPie Type Error: Cannot perform 'append' based access on 'foo' which has a type of 'string' but this operation requires a type of 'array'.\nfoo[]\n ^^", ), ( ['data[key]=value', 'data[key 2]=value 2', 'data[0]=value'], - "HTTPie Type Error: Can't perform 'index' based access on 'data' which has a type of 'object' but this operation requires a type of 'array'.\ndata[0]\n ^^^", + "HTTPie Type Error: Cannot perform 'index' based access on 'data' which has a type of 'object' but this operation requires a type of 'array'.\ndata[0]\n ^^^", ), ( ['data[key]=value', 'data[key 2]=value 2', 'data[]=value'], - "HTTPie Type Error: Can't perform 'append' based access on 'data' which has a type of 'object' but this operation requires a type of 'array'.\ndata[]\n ^^", + "HTTPie Type Error: Cannot perform 'append' based access on 'data' which has a type of 'object' but this operation requires a type of 'array'.\ndata[]\n ^^", ), ( [ @@ -532,7 +532,7 @@ def test_nested_json_syntax(input_json, expected_json, httpbin): 'foo[bar][baz][5][]:=4', 'foo[bar][baz][key][]:=5', ], - "HTTPie Type Error: Can't perform 'key' based access on 'foo[bar][baz]' which has a type of 'array' but this operation requires a type of 'object'.\nfoo[bar][baz][key][]\n ^^^^^", + "HTTPie Type Error: Cannot perform 'key' based access on 'foo[bar][baz]' which has a type of 'array' but this operation requires a type of 'object'.\nfoo[bar][baz][key][]\n ^^^^^", ), ( ['foo[-10]:=[1,2]'], @@ -540,32 +540,32 @@ def test_nested_json_syntax(input_json, expected_json, httpbin): ), ( ['foo[0]:=1', 'foo[]:=2', 'foo[\\2]:=3'], - "HTTPie Type Error: Can't perform 'key' based access on 'foo' which has a type of 'array' but this operation requires a type of 'object'.\nfoo[\\2]\n ^^^^", + "HTTPie Type Error: Cannot perform 'key' based access on 'foo' which has a type of 'array' but this operation requires a type of 'object'.\nfoo[\\2]\n ^^^^", ), ( ['foo[\\1]:=2', 'foo[5]:=3'], - "HTTPie Type Error: Can't perform 'index' based access on 'foo' which has a type of 'object' but this operation requires a type of 'array'.\nfoo[5]\n ^^^", + "HTTPie Type Error: Cannot perform 'index' based access on 'foo' which has a type of 'object' but this operation requires a type of 'array'.\nfoo[5]\n ^^^", ), ( ['x=y', '[]:=2'], - "HTTPie Type Error: Can't perform 'append' based access on '' which has a type of 'object' but this operation requires a type of 'array'.", + "HTTPie Type Error: Cannot perform 'append' based access on '' which has a type of 'object' but this operation requires a type of 'array'.", ), ( ['[]:=2', 'x=y'], - "HTTPie Type Error: Can't perform 'key' based access on '' which has a type of 'array' but this operation requires a type of 'object'.", + "HTTPie Type Error: Cannot perform 'key' based access on '' which has a type of 'array' but this operation requires a type of 'object'.", ), ( [':=[1,2,3]', '[]:=4'], - "HTTPie Type Error: Can't perform 'append' based access on '' which has a type of 'object' but this operation requires a type of 'array'.", + "HTTPie Type Error: Cannot perform 'append' based access on '' which has a type of 'object' but this operation requires a type of 'array'.", ), ( ['[]:=4', ':=[1,2,3]'], - "HTTPie Type Error: Can't perform 'key' based access on '' which has a type of 'array' but this operation requires a type of 'object'.", + "HTTPie Type Error: Cannot perform 'key' based access on '' which has a type of 'array' but this operation requires a type of 'object'.", ), ], ) def test_nested_json_errors(input_json, expected_error, httpbin): - with pytest.raises(HTTPieSyntaxError) as exc: + with pytest.raises(NestedJSONSyntaxError) as exc: http(httpbin + '/post', *input_json) exc_lines = str(exc.value).splitlines() From 621042a0486ceb3afaf47a013c4f2eee4edc1a1d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 1 Oct 2022 04:00:56 -0700 Subject: [PATCH 1123/1182] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d1a90e329a..d2b5df45d9 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ HTTPie
      - HTTPie: human-friendly CLI HTTP client for the API era + HTTPie for Terminal: human-friendly CLI HTTP client for the API era
      From 3a123c4125509d3a4864b82c0b620e8a2e0e89dd Mon Sep 17 00:00:00 2001 From: TAKAHASHI Shuuji Date: Wed, 4 Jan 2023 20:17:18 +0900 Subject: [PATCH 1124/1182] Fix ci status badge error (#1464) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d2b5df45d9..6a31b02fdc 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ [![Docs](https://img.shields.io/badge/stable%20docs-httpie.io%2Fdocs%2Fcli-brightgreen?style=flat&color=%2373DC8C&label=Docs)](https://httpie.org/docs/cli) [![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/httpie) -[![Build](https://img.shields.io/github/workflow/status/httpie/httpie/Build?color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions) +[![Build](https://img.shields.io/github/actions/workflow/status/httpie/httpie/tests.yml?branch=master&color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions) [![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/httpie)
      From 4894b4c0fcc019f8d9e964d1df8b217248595822 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Jan 2023 03:17:54 -0800 Subject: [PATCH 1125/1182] Bump actions/stale from 6 to 7 (#1459) Bumps [actions/stale](https://github.com/actions/stale) from 6 to 7. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 3e4d8998b7..f33f21b563 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/stale@v6 + - uses: actions/stale@v7 with: close-pr-message: 'Thanks for the pull request, but since it was stale for more than a 30 days we are closing it. If you want to work back on it, feel free to re-open it or create a new one.' stale-pr-label: 'stale' From f0563deb7f0db313c1d5cdd8d667972ced0a1e52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Jan 2023 03:18:15 -0800 Subject: [PATCH 1126/1182] Bump mislav/bump-homebrew-formula-action from 1 to 2 (#1453) Bumps [mislav/bump-homebrew-formula-action](https://github.com/mislav/bump-homebrew-formula-action) from 1 to 2. - [Release notes](https://github.com/mislav/bump-homebrew-formula-action/releases) - [Commits](https://github.com/mislav/bump-homebrew-formula-action/compare/v1...v2) --- updated-dependencies: - dependency-name: mislav/bump-homebrew-formula-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release-brew.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-brew.yml b/.github/workflows/release-brew.yml index 44de0b6fd9..d58e6b6e3d 100644 --- a/.github/workflows/release-brew.yml +++ b/.github/workflows/release-brew.yml @@ -18,7 +18,7 @@ jobs: with: ref: ${{ github.event.inputs.branch }} - - uses: mislav/bump-homebrew-formula-action@v1 + - uses: mislav/bump-homebrew-formula-action@v2 with: formula-name: httpie tag-name: ${{ github.events.inputs.branch }} From e73c3e6c249b89496b4f81fa20bb449911da79f1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 15 Jan 2023 17:43:17 +0100 Subject: [PATCH 1127/1182] =?UTF-8?q?Fix=20failing=20tests=20with=20respon?= =?UTF-8?q?ses=20=E2=89=A5=200.22.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Close #1461 Close #1467 Thanks, @alexshpilkin! --- httpie/models.py | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/httpie/models.py b/httpie/models.py index d97b55e3c6..6fe02d5fcf 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -16,7 +16,6 @@ from .compat import cached_property from .utils import split_cookies, parse_content_type_header - ELAPSED_TIME_LABEL = 'Elapsed time' @@ -67,27 +66,10 @@ def iter_body(self, chunk_size=1): def iter_lines(self, chunk_size): return ((line, b'\n') for line in self._orig.iter_lines(chunk_size)) - # noinspection PyProtectedMember @property def headers(self): - try: - raw = self._orig.raw - if getattr(raw, '_original_response', None): - raw_version = raw._original_response.version - else: - raw_version = raw.version - except AttributeError: - # Assume HTTP/1.1 - raw_version = 11 - version = { - 9: '0.9', - 10: '1.0', - 11: '1.1', - 20: '2.0', - }[raw_version] - original = self._orig - status_line = f'HTTP/{version} {original.status_code} {original.reason}' + status_line = f'HTTP/{self.version} {original.status_code} {original.reason}' headers = [status_line] headers.extend( ': '.join(header) @@ -117,6 +99,32 @@ def metadata(self) -> str: for key, value in data.items() ) + @property + def version(self) -> str: + """ + Return the HTTP version used by the server, e.g. '1.1'. + + Assume HTTP/1.1 if version is not available. + + """ + mapping = { + 9: '0.9', + 10: '1.0', + 11: '1.1', + 20: '2.0', + } + fallback = 11 + version = None + try: + raw = self._orig.raw + if getattr(raw, '_original_response', None): + version = raw._original_response.version + else: + version = raw.version + except AttributeError: + pass + return mapping[version or fallback] + class HTTPRequest(HTTPMessage): """A :class:`requests.models.Request` wrapper.""" From b16392fbb9aee707c0449f10dab6bfd9ad4b8799 Mon Sep 17 00:00:00 2001 From: Nishant Sikarwar Date: Mon, 16 Jan 2023 01:05:36 +0530 Subject: [PATCH 1128/1182] Remove redundant imports (#1466) --- httpie/manager/__main__.py | 1 - httpie/manager/compat.py | 1 - 2 files changed, 2 deletions(-) diff --git a/httpie/manager/__main__.py b/httpie/manager/__main__.py index 922e3d2a55..ba345662fc 100644 --- a/httpie/manager/__main__.py +++ b/httpie/manager/__main__.py @@ -52,7 +52,6 @@ def program(): try: exit_status = main() except KeyboardInterrupt: - from httpie.status import ExitStatus exit_status = ExitStatus.ERROR_CTRL_C return exit_status diff --git a/httpie/manager/compat.py b/httpie/manager/compat.py index 0f787eb818..18e18163a3 100644 --- a/httpie/manager/compat.py +++ b/httpie/manager/compat.py @@ -43,7 +43,6 @@ def _check_pip_version(pip_location: Optional[str]) -> bool: def _run_pip_subprocess(pip_executable: List[str], args: List[str]) -> bytes: - import subprocess cmd = [*pip_executable, *args] try: From 265841f86683e8881194c471cb658fe3bd31f8cc Mon Sep 17 00:00:00 2001 From: Sid <122173059+hugo-sid@users.noreply.github.com> Date: Thu, 23 Mar 2023 01:33:18 +0530 Subject: [PATCH 1129/1182] docs: improve clarity of sentences (#1489) * docs: improve clarity of sentences Improved clarity by rephrasing sentences in the best practices section. * docs: improve best practices section * use appropriate formatting for stdin * include EOF in abbreviated form * docs: clarify sentence * change 'know that' -> 'note that' * use neither nor for better clarity --- docs/README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/README.md b/docs/README.md index 7dbdaf11b8..b63752a9d6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2395,12 +2395,9 @@ fi The default behavior of automatically reading `stdin` is typically not desirable during non-interactive invocations. You most likely want to use the `--ignore-stdin` option to disable it. -It is a common *gotcha* that without this option HTTPie seemingly hangs. -What happens is that when HTTPie is invoked, for example, from a cron job, `stdin` is not connected to a terminal. -Therefore, the rules for [redirected input](#redirected-input) apply, i.e. HTTPie starts to read it expecting that the request body will be passed through. -And since there’s neither data nor `EOF`, it will get stuck. So unless you’re piping some data to HTTPie, the `--ignore-stdin` flag should be used in scripts. +It's important to note that without the `--ignore-stdin` option, HTTPie may appear to have stopped working (hang). This happens because, in situations where HTTPie is invoked outside of an interactive session, such as from a cron job, `stdin` is not connected to a terminal. This means that the rules for [redirected input](#redirected-input) will be followed. When `stdin` is redirected, HTTPie assumes that the input will contain the request body, and it waits for the input to be provided. But, since there is neither any input data nor an end-of-file (`EOF`) signal, HTTPie gets stuck. To avoid this problem, the `--ignore-stdin` flag should be used in scripts, unless data is being piped to HTTPie. -Also, it might be good to set a connection `--timeout` limit to prevent your program from hanging if the server never responds. +To prevent your program from becoming unresponsive when the server fails to respond, it's a good idea to use the `--timeout` option to set a connection timeout limit. ## Plugin manager From 47e9b99ba19b2a9d3e0098726fff4469b9dd6bb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Mar 2023 18:30:30 -0700 Subject: [PATCH 1130/1182] Bump actions/stale from 7 to 8 (#1492) Bumps [actions/stale](https://github.com/actions/stale) from 7 to 8. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f33f21b563..7aa2e24555 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/stale@v7 + - uses: actions/stale@v8 with: close-pr-message: 'Thanks for the pull request, but since it was stale for more than a 30 days we are closing it. If you want to work back on it, feel free to re-open it or create a new one.' stale-pr-label: 'stale' From 1ae4152e1e3385d89fee6035ff7b29a555e8d518 Mon Sep 17 00:00:00 2001 From: Sid <122173059+hugo-sid@users.noreply.github.com> Date: Tue, 9 May 2023 14:53:29 +0530 Subject: [PATCH 1131/1182] docs: improve documentation for installation of unstable version (#1490) * docs: improve documentation for installation of unstable version I am trying to rephrase the instructions to make it clear, concise and beginner friendly. Summary of changes: * rephrased the instructions to install unstable version of HTTPie * rephrased the instructions to verify the installation * fix(docs): remove trailing spaces * docs: fix 'pip' formatting Enclosed 'pip' with backticks to display it as inline code * docs: better description for pip installation (unstable version) * Update docs/README.md --------- Co-authored-by: Jakub Roztocil --- docs/README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index b63752a9d6..f9013b7e75 100644 --- a/docs/README.md +++ b/docs/README.md @@ -250,36 +250,39 @@ $ pkg upgrade www/py-httpie ### 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. +If you want to try out the latest version of HTTPie that hasn't been officially released yet, you can install the development or unstable version directly from the master branch on GitHub. However, keep in mind that the development version is a work in progress and may not be as reliable as the stable version. -You can install it on Linux, macOS, Windows, or FreeBSD with `pip`: +You can use the following command to install the development version of HTTPie on Linux, macOS, Windows, or FreeBSD operating systems. With this command, the code present in the `master` branch is downloaded and installed using `pip`. ```bash $ python -m pip install --upgrade https://github.com/httpie/httpie/archive/master.tar.gz ``` -Or on macOS, and Linux, with Homebrew: +There are other ways to install the development version of HTTPie on macOS and Linux. + +You can install it using Homebrew by running the following commands: ```bash $ brew uninstall --force httpie $ brew install --HEAD httpie ``` -And even on macOS, and Linux, with Snapcraft: +You can install it using Snapcraft by running the following commands: ```bash $ snap remove httpie $ snap install httpie --edge ``` -Verify that now you have the [current development version identifier](https://github.com/httpie/httpie/blob/master/httpie/__init__.py#L6) with the `.dev0` suffix, for example: +To verify the installation, you can compare the [version identifier on GitHub](https://github.com/httpie/httpie/blob/master/httpie/__init__.py#L6) with the one available on your machine. You can check the version of HTTPie on your machine by using the command `http --version`. ```bash $ http --version # 3.X.X.dev0 ``` +Note that on your machine, the version name will have the `.dev0` suffix. + ## Usage Hello World: From 4e29a6d56132ea59a4fc844102b07e7c473463e5 Mon Sep 17 00:00:00 2001 From: C-A de Salaberry Date: Fri, 19 May 2023 21:18:55 +0200 Subject: [PATCH 1132/1182] fix(urllib3): :bug: could not find urllib3 DEFAULT_CIPHERS (#1505) --- httpie/ssl_.py | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/httpie/ssl_.py b/httpie/ssl_.py index b9438543eb..ac02ddb272 100644 --- a/httpie/ssl_.py +++ b/httpie/ssl_.py @@ -4,12 +4,50 @@ from httpie.adapters import HTTPAdapter # noinspection PyPackageRequirements from urllib3.util.ssl_ import ( - DEFAULT_CIPHERS, create_urllib3_context, + create_urllib3_context, resolve_ssl_version, ) -DEFAULT_SSL_CIPHERS = DEFAULT_CIPHERS +# Default ciphers imported from urllib3 as a work around for https://github.com/httpie/httpie/issues/1499 +# Removed from urllib3 in this commit: https://github.com/urllib3/urllib3/commit/e5eac0c +#################### +# A secure default. +# Sources for more information on TLS ciphers: +# +# - https://wiki.mozilla.org/Security/Server_Side_TLS +# - https://www.ssllabs.com/projects/best-practices/index.html +# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ +# +# The general intent is: +# - prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE), +# - prefer ECDHE over DHE for better performance, +# - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and +# security, +# - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common, +# - disable NULL authentication, MD5 MACs, DSS, and other +# insecure ciphers for security reasons. +# - NOTE: TLS 1.3 cipher suites are managed through a different interface +# not exposed by CPython (yet!) and are enabled by default if they're available. +DEFAULT_SSL_CIPHERS = ":".join( + [ + "ECDHE+AESGCM", + "ECDHE+CHACHA20", + "DHE+AESGCM", + "DHE+CHACHA20", + "ECDH+AESGCM", + "DH+AESGCM", + "ECDH+AES", + "DH+AES", + "RSA+AESGCM", + "RSA+AES", + "!aNULL", + "!eNULL", + "!MD5", + "!DSS", + "!AESCCM", + ] +) SSL_VERSION_ARG_MAPPING = { 'ssl2.3': 'PROTOCOL_SSLv23', 'ssl3': 'PROTOCOL_SSLv3', From d021b94b5d6ee0bbf37c61a62f921b4bc228c90d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 19 May 2023 21:50:58 +0200 Subject: [PATCH 1133/1182] Clean up `DEFAULT_SSL_CIPHERS` comments --- httpie/ssl_.py | 80 +++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/httpie/ssl_.py b/httpie/ssl_.py index ac02ddb272..f82d28260b 100644 --- a/httpie/ssl_.py +++ b/httpie/ssl_.py @@ -8,46 +8,46 @@ resolve_ssl_version, ) - -# Default ciphers imported from urllib3 as a work around for https://github.com/httpie/httpie/issues/1499 -# Removed from urllib3 in this commit: https://github.com/urllib3/urllib3/commit/e5eac0c -#################### -# A secure default. -# Sources for more information on TLS ciphers: -# -# - https://wiki.mozilla.org/Security/Server_Side_TLS -# - https://www.ssllabs.com/projects/best-practices/index.html -# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ -# -# The general intent is: -# - prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE), -# - prefer ECDHE over DHE for better performance, -# - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and -# security, -# - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common, -# - disable NULL authentication, MD5 MACs, DSS, and other -# insecure ciphers for security reasons. -# - NOTE: TLS 1.3 cipher suites are managed through a different interface -# not exposed by CPython (yet!) and are enabled by default if they're available. -DEFAULT_SSL_CIPHERS = ":".join( - [ - "ECDHE+AESGCM", - "ECDHE+CHACHA20", - "DHE+AESGCM", - "DHE+CHACHA20", - "ECDH+AESGCM", - "DH+AESGCM", - "ECDH+AES", - "DH+AES", - "RSA+AESGCM", - "RSA+AES", - "!aNULL", - "!eNULL", - "!MD5", - "!DSS", - "!AESCCM", - ] -) +# We used to import default SSL ciphers via `SSL_CIPHERS` from `urllib3` but it’s been removed, +# so we’ve copied the original list here. +# Our issue: +# Removal commit: +DEFAULT_SSL_CIPHERS = ":".join([ + # + # A secure default. + # Sources for more information on TLS ciphers: + # + # - https://wiki.mozilla.org/Security/Server_Side_TLS + # - https://www.ssllabs.com/projects/best-practices/index.html + # - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ + # + # The general intent is: + # - prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE), + # - prefer ECDHE over DHE for better performance, + # - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and + # security, + # - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common, + # - disable NULL authentication, MD5 MACs, DSS, and other + # insecure ciphers for security reasons. + # - NOTE: TLS 1.3 cipher suites are managed through a different interface + # not exposed by CPython (yet!) and are enabled by default if they're available. + "ECDHE+AESGCM", + "ECDHE+CHACHA20", + "DHE+AESGCM", + "DHE+CHACHA20", + "ECDH+AESGCM", + "DH+AESGCM", + "ECDH+AES", + "DH+AES", + "RSA+AESGCM", + "RSA+AES", + "!aNULL", + "!eNULL", + "!MD5", + "!DSS", + "!AESCCM", + # +]) SSL_VERSION_ARG_MAPPING = { 'ssl2.3': 'PROTOCOL_SSLv23', 'ssl3': 'PROTOCOL_SSLv3', From 44d3cff03f2e43a3e8304e30d96b1ddc2a1bb9e0 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 19 May 2023 21:51:32 +0200 Subject: [PATCH 1134/1182] Fix log level display on newer Python --- httpie/context.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httpie/context.py b/httpie/context.py index 086cfa4f26..2a54f46916 100644 --- a/httpie/context.py +++ b/httpie/context.py @@ -145,7 +145,7 @@ def config(self) -> Config: try: config.load() except ConfigFileError as e: - self.log_error(e, level='warning') + self.log_error(e, level=LogLevel.WARNING) return config @property @@ -174,7 +174,7 @@ def log_error(self, msg: str, level: LogLevel = LogLevel.ERROR) -> None: stderr = self._orig_stderr rich_console = self._make_rich_console(file=stderr, force_terminal=stderr.isatty()) rich_console.print( - f'\n{self.program_name}: {level}: {msg}\n\n', + f'\n{self.program_name}: {level.value}: {msg}\n\n', style=LOG_LEVEL_COLORS[level], markup=False, highlight=False, From 8e56e9fc6449a1cdfd90596e3ccbb1a5b71950d1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 19 May 2023 21:51:52 +0200 Subject: [PATCH 1135/1182] Fix a failing test --- tests/test_sessions.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 0083ea52c0..b0f3c65681 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -446,7 +446,7 @@ def test_get_expired_cookies_manages_multiple_cookie_headers(self, cookies, now, class TestCookieStorage(CookieTestBase): @pytest.mark.parametrize( - 'new_cookies, new_cookies_dict, expected', + ['specified_cookie_header', 'new_cookies_dict', 'expected_effective_cookie_header'], [( 'new=bar', {'new': 'bar'}, @@ -463,9 +463,9 @@ class TestCookieStorage(CookieTestBase): 'chocolate=milk; cookie1=foo; cookie2=foo; new=bar' ), ( - 'new=bar;; chocolate=milk;;;', + 'new=bar; chocolate=milk', {'new': 'bar', 'chocolate': 'milk'}, - 'cookie1=foo; cookie2=foo; new=bar' + 'cookie1=foo; cookie2=foo; new=bar; chocolate=milk' ), ( 'new=bar; chocolate=milk;;;', @@ -474,20 +474,35 @@ class TestCookieStorage(CookieTestBase): ) ] ) - def test_existing_and_new_cookies_sent_in_request(self, new_cookies, new_cookies_dict, expected, httpbin): + def test_existing_and_new_cookies_sent_in_request( + self, + specified_cookie_header, + new_cookies_dict, + expected_effective_cookie_header, + httpbin, + ): r = http( '--session', str(self.session_path), '--print=H', httpbin.url, - 'Cookie:' + new_cookies, + 'Cookie:' + specified_cookie_header, ) - # Note: cookies in response are in alphabetical order - assert f'Cookie: {expected}' in r + parsed_request_headers = { + name: value for name, value in [ + line.split(': ', 1) + for line in r.splitlines() + if line and ':' in line + ] + } + # Note: cookies in the request are in an undefined order. + expected_request_cookie_set = set(expected_effective_cookie_header.split('; ')) + actual_request_cookie_set = set(parsed_request_headers['Cookie'].split('; ')) + assert actual_request_cookie_set == expected_request_cookie_set updated_session = json.loads(self.session_path.read_text(encoding=UTF8)) + assert 'Cookie' not in updated_session['headers'] for name, value in new_cookies_dict.items(): - assert name, value in updated_session['cookies'] - assert 'Cookie' not in updated_session['headers'] + assert updated_session['cookies'][name]['value'] == value @pytest.mark.parametrize( 'cli_cookie, set_cookie, expected', From fcd3f7ece64fb9654c569e98997af873a6346094 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 19 May 2023 22:26:33 +0200 Subject: [PATCH 1136/1182] Generate default ciphers using approach from #1501 --- httpie/cli/definition.py | 6 ++--- httpie/ssl_.py | 51 +++++++++------------------------------- tests/test_ssl.py | 4 ++-- 3 files changed, 16 insertions(+), 45 deletions(-) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 0e5f91edf7..78e968f6c4 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -20,7 +20,7 @@ get_available_styles) from httpie.plugins.builtin import BuiltinAuthPlugin from httpie.plugins.registry import plugin_manager -from httpie.ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS +from httpie.ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS_STRING options = ParserSpec( 'http', @@ -832,9 +832,9 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False): help=f""" A string in the OpenSSL cipher list format. By default, the following - is used: + ciphers are used on your system: - {DEFAULT_SSL_CIPHERS} + {DEFAULT_SSL_CIPHERS_STRING} """, ) diff --git a/httpie/ssl_.py b/httpie/ssl_.py index f82d28260b..af71dfb956 100644 --- a/httpie/ssl_.py +++ b/httpie/ssl_.py @@ -8,46 +8,7 @@ resolve_ssl_version, ) -# We used to import default SSL ciphers via `SSL_CIPHERS` from `urllib3` but it’s been removed, -# so we’ve copied the original list here. -# Our issue: -# Removal commit: -DEFAULT_SSL_CIPHERS = ":".join([ - # - # A secure default. - # Sources for more information on TLS ciphers: - # - # - https://wiki.mozilla.org/Security/Server_Side_TLS - # - https://www.ssllabs.com/projects/best-practices/index.html - # - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ - # - # The general intent is: - # - prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE), - # - prefer ECDHE over DHE for better performance, - # - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and - # security, - # - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common, - # - disable NULL authentication, MD5 MACs, DSS, and other - # insecure ciphers for security reasons. - # - NOTE: TLS 1.3 cipher suites are managed through a different interface - # not exposed by CPython (yet!) and are enabled by default if they're available. - "ECDHE+AESGCM", - "ECDHE+CHACHA20", - "DHE+AESGCM", - "DHE+CHACHA20", - "ECDH+AESGCM", - "DH+AESGCM", - "ECDH+AES", - "DH+AES", - "RSA+AESGCM", - "RSA+AES", - "!aNULL", - "!eNULL", - "!MD5", - "!DSS", - "!AESCCM", - # -]) + SSL_VERSION_ARG_MAPPING = { 'ssl2.3': 'PROTOCOL_SSLv23', 'ssl3': 'PROTOCOL_SSLv3', @@ -119,6 +80,10 @@ def _create_ssl_context( cert_reqs=ssl.CERT_REQUIRED if verify else ssl.CERT_NONE ) + @classmethod + def get_default_ciphers_names(cls): + return [cipher['name'] for cipher in cls._create_ssl_context(verify=False).get_ciphers()] + def _is_key_file_encrypted(key_file): """Detects if a key file is encrypted or not. @@ -132,3 +97,9 @@ def _is_key_file_encrypted(key_file): return True return False + + +# We used to import the default set of TLS ciphers from urllib3, but they removed it. +# Instead, now urllib3 uses the list of ciphers configured by the system. +# +DEFAULT_SSL_CIPHERS_STRING = ':'.join(HTTPieHTTPSAdapter.get_default_ciphers_names()) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index ef72e2be40..bf20a96da5 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -7,7 +7,7 @@ from unittest import mock -from httpie.ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS +from httpie.ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS_STRING from httpie.status import ExitStatus from .utils import HTTP_OK, TESTS_ROOT, IS_PYOPENSSL, http @@ -146,7 +146,7 @@ def test_ciphers(httpbin_secure): r = http( httpbin_secure.url + '/get', '--ciphers', - DEFAULT_SSL_CIPHERS, + DEFAULT_SSL_CIPHERS_STRING, ) assert HTTP_OK in r From 18bb49b268eb73b379bd3d01b1e70b9c54b21119 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 19 May 2023 23:29:09 +0200 Subject: [PATCH 1137/1182] Skip a test failing in CI --- tests/test_plugins_cli.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_plugins_cli.py b/tests/test_plugins_cli.py index 2805792364..2aea0deaa0 100644 --- a/tests/test_plugins_cli.py +++ b/tests/test_plugins_cli.py @@ -117,6 +117,8 @@ def test_plugins_double_uninstall(httpie_plugins, httpie_plugins_success, dummy_ ) +# TODO: Make this work on CI (stopped working at some point) +@pytest.mark.skip(reason='Doesn’t work in CI') @pytest.mark.requires_installation def test_plugins_upgrade(httpie_plugins, httpie_plugins_success, dummy_plugin): httpie_plugins_success("install", dummy_plugin.path) From 879fedc10a89f69469ea3f2934aa702f8ffbf181 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 19 May 2023 23:41:16 +0200 Subject: [PATCH 1138/1182] Flake8 --- tests/test_sessions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index b0f3c65681..82a310e08d 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -487,7 +487,7 @@ def test_existing_and_new_cookies_sent_in_request( httpbin.url, 'Cookie:' + specified_cookie_header, ) - parsed_request_headers = { + parsed_request_headers = { # noqa name: value for name, value in [ line.split(': ', 1) for line in r.splitlines() From 29de4ce1151936856cda417767f8c507fc2c201c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 19 May 2023 23:41:26 +0200 Subject: [PATCH 1139/1182] v3.2.2 --- CHANGELOG.md | 4 ++++ httpie/__init__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6aaaafb8e..b03ffc9a5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). +## [3.2.2](https://github.com/httpie/httpie/compare/3.2.1...3.2.2) (2022-05-19) + +- Fixed compatibility with urllib3 2.0.0. ([#1499](https://github.com/httpie/httpie/issue/1499)) + ## [3.2.1](https://github.com/httpie/httpie/compare/3.1.0...3.2.1) (2022-05-06) - Improved support for determining auto-streaming when the `Content-Type` header includes encoding information. ([#1383](https://github.com/httpie/httpie/pull/1383)) diff --git a/httpie/__init__.py b/httpie/__init__.py index 1142fc1b9a..ffe0d35419 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ -__version__ = '3.2.1' +__version__ = '3.2.2' __date__ = '2022-05-06' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 36646447229d39c2b8755b31bbee96b6d7d1612c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 19 May 2023 23:44:52 +0200 Subject: [PATCH 1140/1182] Fix issue link --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b03ffc9a5e..2f2a5139b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [3.2.2](https://github.com/httpie/httpie/compare/3.2.1...3.2.2) (2022-05-19) -- Fixed compatibility with urllib3 2.0.0. ([#1499](https://github.com/httpie/httpie/issue/1499)) +- Fixed compatibility with urllib3 2.0.0. ([#1499](https://github.com/httpie/httpie/issues/1499)) ## [3.2.1](https://github.com/httpie/httpie/compare/3.1.0...3.2.1) (2022-05-06) From cbe53ed79a62a02cad6d30d83c0ac97b3492b205 Mon Sep 17 00:00:00 2001 From: Abdelhakim Qbaich Date: Fri, 19 May 2023 17:53:26 -0400 Subject: [PATCH 1141/1182] Avoid override of headers by urllib3 when unset (#1502) * Pass SKIP_HEADER const when header is unset * Hide SKIP_HEADER constant when displaying headers * Test that omits User-Agent --- httpie/client.py | 5 +++++ httpie/models.py | 2 ++ tests/test_httpie.py | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/httpie/client.py b/httpie/client.py index 815ec559b2..a96b246701 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -10,6 +10,7 @@ import requests # noinspection PyPackageRequirements import urllib3 +from urllib3.util import SKIP_HEADER, SKIPPABLE_HEADERS from . import __version__ from .adapters import HTTPieHTTPAdapter @@ -200,6 +201,10 @@ def finalize_headers(headers: HTTPHeadersDict) -> HTTPHeadersDict: if isinstance(value, str): # See value = value.encode() + elif name.lower() in SKIPPABLE_HEADERS: + # Some headers get overwritten by urllib3 when set to `None` + # and should be replaced with the `SKIP_HEADER` constant. + value = SKIP_HEADER final_headers.add(name, value) return final_headers diff --git a/httpie/models.py b/httpie/models.py index 6fe02d5fcf..a0a68c8ddc 100644 --- a/httpie/models.py +++ b/httpie/models.py @@ -1,6 +1,7 @@ from time import monotonic import requests +from urllib3.util import SKIP_HEADER, SKIPPABLE_HEADERS from enum import Enum, auto from typing import Iterable, Union, NamedTuple @@ -152,6 +153,7 @@ def headers(self): headers = [ f'{name}: {value if isinstance(value, str) else value.decode()}' for name, value in headers.items() + if not (name.lower() in SKIPPABLE_HEADERS and value == SKIP_HEADER) ] headers.insert(0, request_line) diff --git a/tests/test_httpie.py b/tests/test_httpie.py index f07f34b9a5..281dc35600 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -196,6 +196,14 @@ def test_unset_host_header(httpbin_both): assert 'Host' not in r.json['headers'] # default Host unset +def test_unset_useragent_header(httpbin_both): + r = http('GET', httpbin_both + '/headers') + assert 'User-Agent' in r.json['headers'] # default User-Agent present + + r = http('GET', httpbin_both + '/headers', 'User-Agent:') + assert 'User-Agent' not in r.json['headers'] # default User-Agent unset + + def test_headers_empty_value(httpbin_both): r = http('GET', httpbin_both + '/headers') assert r.json['headers']['Accept'] # default Accept has value From cc697db730336410bef882889d4016892ec58c43 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 19 May 2023 23:59:08 +0200 Subject: [PATCH 1142/1182] Add a changelog entry for #1502 --- CHANGELOG.md | 4 ++++ docs/README.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f2a5139b8..3c14d60aa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). +## [3.3.0-dev](https://github.com/httpie/httpie/compare/3.2.2...master) (unreleased) + +- Make it possible to [unset](https://httpie.io/docs/cli/default-request-headers) the `User-Agent`, `Accept-Encoding`, and `Host` request headers. ([#1502](https://github.com/httpie/httpie/issues/1502)) + ## [3.2.2](https://github.com/httpie/httpie/compare/3.2.1...3.2.2) (2022-05-19) - Fixed compatibility with urllib3 2.0.0. ([#1499](https://github.com/httpie/httpie/issues/1499)) diff --git a/docs/README.md b/docs/README.md index f9013b7e75..ab2691e0e5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1174,7 +1174,7 @@ User-Agent: HTTPie/ Host: ``` -Any of these can be overwritten and some of them unset (see below). +All of these can be overwritten or unset (see below). ### Reading headers from a file From 7512ca7e47f37b0e109011a806466ea4e3762721 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 20 May 2023 00:01:10 +0200 Subject: [PATCH 1143/1182] Fix docs deploy --- .github/workflows/docs-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index 62df9c0c0d..797bdc56e0 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Install HTTPie - run: sudo snap install --edge httpie + run: sudo pip install httpie - name: Trigger new documentation build run: http --ignore-stdin POST ${{ secrets.DOCS_UPDATE_VERCEL_HOOK }} From 3b58a4a4a213d2d3fb360e2b341a40a0c82f9aab Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sat, 20 May 2023 00:01:37 +0200 Subject: [PATCH 1144/1182] Trigger docs deploy --- docs/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.md b/docs/README.md index ab2691e0e5..8b075e8ab9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2596,3 +2596,4 @@ BSD-3-Clause: [LICENSE](https://github.com/httpie/httpie/blob/master/LICENSE). ### Authors [Jakub Roztocil](https://roztocil.co) ([@jakubroztocil](https://twitter.com/jakubroztocil)) created HTTPie and [these fine people](https://github.com/httpie/httpie/blob/master/AUTHORS.md) have contributed. + From 2a9cd226aaf983495fe37ef00e78ff1500dc2e3e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 22 May 2023 16:21:25 +0200 Subject: [PATCH 1145/1182] Bump version for Chocolatey --- docs/packaging/windows-chocolatey/httpie.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/packaging/windows-chocolatey/httpie.nuspec b/docs/packaging/windows-chocolatey/httpie.nuspec index 02592cd821..c54654c36f 100644 --- a/docs/packaging/windows-chocolatey/httpie.nuspec +++ b/docs/packaging/windows-chocolatey/httpie.nuspec @@ -2,7 +2,7 @@ httpie - 3.2.1 + 3.2.2 Modern, user-friendly command-line HTTP client for the API era HTTPie *aitch-tee-tee-pie* is a user-friendly command-line HTTP client for the API era. From 3e290e5dba9abe80014fbe9cc73d7db4452112d6 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 22 May 2023 17:51:22 +0200 Subject: [PATCH 1146/1182] Fix Snap publish action --- .github/workflows/release-snap.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-snap.yml b/.github/workflows/release-snap.yml index c415edd76e..ad25186e88 100644 --- a/.github/workflows/release-snap.yml +++ b/.github/workflows/release-snap.yml @@ -34,7 +34,8 @@ jobs: id: build - uses: snapcore/action-publish@v1 + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }} with: - store_login: ${{ secrets.SNAP_STORE_LOGIN }} snap: ${{ steps.build.outputs.snap }} release: ${{ matrix.level }} From 442aa673ac732c34dbbb6e947d7455825b2968f5 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 22 May 2023 18:04:06 +0200 Subject: [PATCH 1147/1182] Fix Choco changelog link --- docs/packaging/windows-chocolatey/httpie.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/packaging/windows-chocolatey/httpie.nuspec b/docs/packaging/windows-chocolatey/httpie.nuspec index c54654c36f..858fa5e20a 100644 --- a/docs/packaging/windows-chocolatey/httpie.nuspec +++ b/docs/packaging/windows-chocolatey/httpie.nuspec @@ -33,7 +33,7 @@ Main features: https://raw.githubusercontent.com/httpie/httpie/master/LICENSE https://pie-assets.s3.eu-central-1.amazonaws.com/LogoIcons/GB.png false - See the [changelog](https://github.com/httpie/httpie/releases/tag/3.2.0). + See the [changelog](https://github.com/httpie/httpie/releases/tag/3.2.2). httpie http https rest api client curl python ssl cli foss oss url https://httpie.io https://github.com/httpie/httpie/tree/master/docs/packaging/windows-chocolatey From 5dc30bc4385e03ce031696aa2d4e4d61ee5bab1e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 22 May 2023 18:44:07 +0200 Subject: [PATCH 1148/1182] Ensure `sudo` for `apt` --- docs/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.md b/docs/README.md index 8b075e8ab9..44b0c0a3e7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -162,6 +162,7 @@ Also works for other Debian-derived distributions like MX Linux, Linux Mint, dee ```bash # Install httpie +$ sudo -i $ curl -SsL https://packages.httpie.io/deb/KEY.gpg | apt-key add - $ curl -SsL -o /etc/apt/sources.list.d/httpie.list https://packages.httpie.io/deb/httpie.list $ apt update From 2e3272b5ba4a80e45b0f709581596688d9339954 Mon Sep 17 00:00:00 2001 From: chrysle Date: Mon, 22 May 2023 18:50:25 +0200 Subject: [PATCH 1149/1182] Fixed installation steps for Debian & Ubuntu (#1473) (#1475) * Fixed installation steps for Debian & Ubuntu * Fixed incorrect path --- docs/installation/methods.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/installation/methods.yml b/docs/installation/methods.yml index cabf577aa3..1cc09762b8 100644 --- a/docs/installation/methods.yml +++ b/docs/installation/methods.yml @@ -37,13 +37,13 @@ tools: package: https://packages.debian.org/sid/web/httpie commands: install: - - curl -SsL https://packages.httpie.io/deb/KEY.gpg | apt-key add - - - curl -SsL -o /etc/apt/sources.list.d/httpie.list https://packages.httpie.io/deb/httpie.list - - apt update - - apt install httpie + - curl -SsL https://packages.httpie.io/deb/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/httpie.gpg + # - curl -SsL -o /etc/apt/sources.list.d/httpie.list https://packages.httpie.io/deb/httpie.list + - sudo echo "deb [arch=amd64 signed-by=/usr/share/keyrings/httpie.gpg] https://packages.httpie.io/deb ./" > /etc/apt/sources.list.d/httpie.list + - sudo apt update + - sudo apt install httpie upgrade: - - apt update - - apt upgrade httpie + - sudo apt update && sudo apt upgrade httpie brew-mac: title: Homebrew From 5325a9bc0792d7405f37a216d8b823bfe35f2d8e Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 22 May 2023 19:01:36 +0200 Subject: [PATCH 1150/1182] Remove skipping Always skipped --- .github/workflows/autogenerated-files.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/autogenerated-files.yml b/.github/workflows/autogenerated-files.yml index c322d12aa2..f622245fcd 100644 --- a/.github/workflows/autogenerated-files.yml +++ b/.github/workflows/autogenerated-files.yml @@ -8,7 +8,6 @@ on: jobs: regen-autogenerated-files: runs-on: ubuntu-latest - if: github.event.pull_request.head.repo.full_name == github.repository steps: - uses: actions/checkout@v3 From c2677eeccf5ead9ca39ba331ad6eae714fcc74c7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 11:40:01 -0700 Subject: [PATCH 1151/1182] [automated] Update auto-generated files (#1507) Co-authored-by: jakubroztocil --- docs/README.md | 73 ++++++++++++++++++++++----------------------- extras/man/http.1 | 6 ++-- extras/man/httpie.1 | 2 +- extras/man/https.1 | 6 ++-- 4 files changed, 43 insertions(+), 44 deletions(-) diff --git a/docs/README.md b/docs/README.md index 44b0c0a3e7..173ccd7a1f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -126,109 +126,108 @@ $ choco upgrade httpie ### Linux -#### Snapcraft (Linux) +#### Debian and Ubuntu -To install [Snapcraft](https://snapcraft.io/), see [its installation](https://snapcraft.io/docs/installing-snapd). +Also works for other Debian-derived distributions like MX Linux, Linux Mint, deepin, Pop!_OS, KDE neon, Zorin OS, elementary OS, Kubuntu, Devuan, Linux Lite, Peppermint OS, Lubuntu, antiX, Xubuntu, etc. ```bash # Install httpie -$ snap install httpie +$ curl -SsL https://packages.httpie.io/deb/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/httpie.gpg +$ sudo echo "deb [arch=amd64 signed-by=/usr/share/keyrings/httpie.gpg] https://packages.httpie.io/deb ./" > /etc/apt/sources.list.d/httpie.list +$ sudo apt update +$ sudo apt install httpie ``` ```bash # Upgrade httpie -$ snap refresh httpie +$ sudo apt update && sudo apt upgrade httpie ``` -#### Linuxbrew - -To install [Linuxbrew](https://docs.brew.sh/Homebrew-on-Linux), see [its installation](https://docs.brew.sh/Homebrew-on-Linux#install). +#### Fedora ```bash # Install httpie -$ brew update -$ brew install httpie +$ dnf install httpie ``` ```bash # Upgrade httpie -$ brew update -$ brew upgrade httpie +$ dnf upgrade httpie ``` -#### Debian and Ubuntu +#### CentOS and RHEL -Also works for other Debian-derived distributions like MX Linux, Linux Mint, deepin, Pop!_OS, KDE neon, Zorin OS, elementary OS, Kubuntu, Devuan, Linux Lite, Peppermint OS, Lubuntu, antiX, Xubuntu, etc. +Also works for other RHEL-derived distributions like ClearOS, Oracle Linux, etc. ```bash # Install httpie -$ sudo -i -$ curl -SsL https://packages.httpie.io/deb/KEY.gpg | apt-key add - -$ curl -SsL -o /etc/apt/sources.list.d/httpie.list https://packages.httpie.io/deb/httpie.list -$ apt update -$ apt install httpie +$ yum install epel-release +$ yum install httpie ``` ```bash # Upgrade httpie -$ apt update -$ apt upgrade httpie +$ yum upgrade httpie ``` -#### Fedora +#### Single binary executables + +Get the standalone HTTPie Linux executables when you don't want to go through the full installation process. ```bash # Install httpie -$ dnf install httpie +$ https --download packages.httpie.io/binaries/linux/http-latest -o http +$ ln -ls ./http ./https +$ chmod +x ./http ./https ``` ```bash # Upgrade httpie -$ dnf upgrade httpie +$ https --download packages.httpie.io/binaries/linux/http-latest -o http ``` -#### CentOS and RHEL +#### Snapcraft (Linux) -Also works for other RHEL-derived distributions like ClearOS, Oracle Linux, etc. +To install [Snapcraft](https://snapcraft.io/), see [its installation](https://snapcraft.io/docs/installing-snapd). ```bash # Install httpie -$ yum install epel-release -$ yum install httpie +$ snap install httpie ``` ```bash # Upgrade httpie -$ yum upgrade httpie +$ snap refresh httpie ``` -#### Arch Linux +#### Linuxbrew -Also works for other Arch-derived distributions like ArcoLinux, EndeavourOS, Artix Linux, etc. +To install [Linuxbrew](https://docs.brew.sh/Homebrew-on-Linux), see [its installation](https://docs.brew.sh/Homebrew-on-Linux#install). ```bash # Install httpie -$ pacman -Syu httpie +$ brew update +$ brew install httpie ``` ```bash # Upgrade httpie -$ pacman -Syu +$ brew update +$ brew upgrade httpie ``` -#### Single binary executables +#### Arch Linux -Get the standalone HTTPie Linux executables when you don't want to go through the full installation process +Also works for other Arch-derived distributions like ArcoLinux, EndeavourOS, Artix Linux, etc. ```bash # Install httpie -$ https --download packages.httpie.io/binaries/linux/http-latest -o http -$ chmod +x ./http +$ pacman -Syu httpie ``` ```bash # Upgrade httpie -$ https --download packages.httpie.io/binaries/linux/http-latest -o http +$ pacman -Syu ``` ### FreeBSD diff --git a/extras/man/http.1 b/extras/man/http.1 index 8aded62fcd..eef0e07136 100644 --- a/extras/man/http.1 +++ b/extras/man/http.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/cli/definition.py by extras/scripts/generate_man_pages.py. -.TH http 1 "2022-05-06" "HTTPie 3.2.1" "HTTPie Manual" +.TH http 1 "2022-05-06" "HTTPie 3.2.2" "HTTPie Manual" .SH NAME http .SH SYNOPSIS @@ -511,9 +511,9 @@ are shown here). A string in the OpenSSL cipher list format. By default, the following -is used: +ciphers are used on your system: -ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:ECDH+AESGCM:DH+AESGCM:ECDH+AES:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!eNULL:!MD5:!DSS +TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA diff --git a/extras/man/httpie.1 b/extras/man/httpie.1 index 54b4145961..0536d61bfa 100644 --- a/extras/man/httpie.1 +++ b/extras/man/httpie.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/manager/cli.py by extras/scripts/generate_man_pages.py. -.TH httpie 1 "2022-05-06" "HTTPie 3.2.1" "HTTPie Manual" +.TH httpie 1 "2022-05-06" "HTTPie 3.2.2" "HTTPie Manual" .SH NAME httpie .SH SYNOPSIS diff --git a/extras/man/https.1 b/extras/man/https.1 index 35f9f75734..2395ba414d 100644 --- a/extras/man/https.1 +++ b/extras/man/https.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/cli/definition.py by extras/scripts/generate_man_pages.py. -.TH https 1 "2022-05-06" "HTTPie 3.2.1" "HTTPie Manual" +.TH https 1 "2022-05-06" "HTTPie 3.2.2" "HTTPie Manual" .SH NAME https .SH SYNOPSIS @@ -511,9 +511,9 @@ are shown here). A string in the OpenSSL cipher list format. By default, the following -is used: +ciphers are used on your system: -ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:ECDH+AESGCM:DH+AESGCM:ECDH+AES:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!eNULL:!MD5:!DSS +TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA From 2da955fb0619e18078c56b5bec9dae8c7d99d0e3 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 22 May 2023 11:56:30 -0700 Subject: [PATCH 1152/1182] Man page clean-up (#1508) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure we don’t include dynamic content in the static man pages. --- .../{autogenerated-files.yml => content.yml} | 15 +++----- Makefile | 8 ++-- extras/man/http.1 | 7 ++-- extras/man/https.1 | 8 ++-- extras/scripts/generate_man_pages.py | 21 +++++++---- httpie/cli/definition.py | 37 +++++++++++++++---- httpie/output/ui/man_pages.py | 19 +++++----- 7 files changed, 67 insertions(+), 48 deletions(-) rename .github/workflows/{autogenerated-files.yml => content.yml} (63%) diff --git a/.github/workflows/autogenerated-files.yml b/.github/workflows/content.yml similarity index 63% rename from .github/workflows/autogenerated-files.yml rename to .github/workflows/content.yml index f622245fcd..d5d6dbcfa4 100644 --- a/.github/workflows/autogenerated-files.yml +++ b/.github/workflows/content.yml @@ -1,27 +1,22 @@ -name: Update Autogenerated Files - +name: Update Generated Content on: push: branches: - master - jobs: - regen-autogenerated-files: + update-content: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 with: python-version: 3.9 - - - run: make regen-all - + - run: make content - name: Create Pull Request id: cpr uses: peter-evans/create-pull-request@v4 with: - commit-message: "[automated] Update auto-generated files" - title: "[automated] Update auto-generated files" + commit-message: "[automated] Update generated content" + title: "[automated] Update generated content" delete-branch: true token: ${{ secrets.GITHUB_TOKEN }} diff --git a/Makefile b/Makefile index a447b233a2..3226a0312e 100644 --- a/Makefile +++ b/Makefile @@ -231,15 +231,15 @@ brew-test: brew audit --strict httpie ############################################################################### -# Regeneration +# Generated content ############################################################################### -regen-all: regen-man-pages regen-install-methods +content: man installation-docs -regen-man-pages: install +man: install @echo $(H1)Regenerate man pages$(H1END) $(VENV_PYTHON) extras/scripts/generate_man_pages.py -regen-install-methods: +installation-docs: @echo $(H1)Updating installation instructions in the docs$(H1END) $(VENV_PYTHON) docs/installation/generate.py diff --git a/extras/man/http.1 b/extras/man/http.1 index eef0e07136..52b3155fa0 100644 --- a/extras/man/http.1 +++ b/extras/man/http.1 @@ -399,7 +399,7 @@ The authentication mechanism to be used. Defaults to \[dq]basic\[dq]. \[dq]bearer\[dq]: Bearer HTTP Auth -For finding out all available authentication types in your system, try: +To see all available auth types on your system, including ones installed via plugins, run: $ http \fB\,--auth-type\/\fR @@ -510,11 +510,10 @@ are shown here). -A string in the OpenSSL cipher list format. By default, the following -ciphers are used on your system: +A string in the OpenSSL cipher list format. -TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA +See `http \fB\,--help\/\fR` for the default ciphers list on you system. .IP "\fB\,--cert\/\fR" diff --git a/extras/man/https.1 b/extras/man/https.1 index 2395ba414d..5dd2b7c386 100644 --- a/extras/man/https.1 +++ b/extras/man/https.1 @@ -399,7 +399,7 @@ The authentication mechanism to be used. Defaults to \[dq]basic\[dq]. \[dq]bearer\[dq]: Bearer HTTP Auth -For finding out all available authentication types in your system, try: +To see all available auth types on your system, including ones installed via plugins, run: $ http \fB\,--auth-type\/\fR @@ -509,12 +509,10 @@ are shown here). .IP "\fB\,--ciphers\/\fR" +A string in the OpenSSL cipher list format. -A string in the OpenSSL cipher list format. By default, the following -ciphers are used on your system: - -TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA +See `http \fB\,--help\/\fR` for the default ciphers list on you system. .IP "\fB\,--cert\/\fR" diff --git a/extras/scripts/generate_man_pages.py b/extras/scripts/generate_man_pages.py index 71e0100f39..87939bd5b3 100644 --- a/extras/scripts/generate_man_pages.py +++ b/extras/scripts/generate_man_pages.py @@ -1,20 +1,25 @@ +import os import re from contextlib import contextmanager from pathlib import Path from typing import Optional, Iterator, Iterable + +# So that httpie.cli.definition can provide man-page-specific output. Must be set before importing httpie. +os.environ['HTTPIE_BUILDING_MAN_PAGES'] = '1' + import httpie -from httpie.cli.definition import options as core_options +from httpie.cli.definition import options as core_options, IS_MAN_PAGE from httpie.cli.options import ParserSpec from httpie.manager.cli import options as manager_options from httpie.output.ui.rich_help import OptionsHighlighter, to_usage from httpie.output.ui.rich_utils import render_as_string -from httpie.utils import split_iterable -# Escape certain characters so they are rendered properly on -# all terminals. -# https://man7.org/linux/man-pages/man7/groff_char.7.html +assert IS_MAN_PAGE, 'CLI definition does not understand we’re building man pages' + +# Escape certain characters, so they are rendered properly on all terminals. +# ESCAPE_MAP = { '"': '\[dq]', "'": '\[aq]', @@ -32,6 +37,7 @@ OptionsHighlighter.highlights[0] ) + class ManPageBuilder: def __init__(self): self.source = [] @@ -125,7 +131,7 @@ def to_man_page(program_name: str, spec: ParserSpec, *, is_top_level_cmd: bool = with builder.section('SYNOPSIS'): # `http` and `https` are commands that can be directly used, so they can have - # have a valid usage. But `httpie` is a top-level command with multiple sub commands, + # a valid usage. But `httpie` is a top-level command with multiple sub commands, # so for the synopsis we'll only reference the `httpie` name. if is_top_level_cmd: synopsis = program_name @@ -153,7 +159,7 @@ def to_man_page(program_name: str, spec: ParserSpec, *, is_top_level_cmd: bool = if raw_arg.get('is_positional'): # In case of positional arguments, metavar is always equal # to the list of options (e.g `METHOD`). - metavar = None + metavar = None builder.add_options(raw_arg['options'], metavar=metavar) desc = builder.format_desc(raw_arg.get('description', '')) @@ -178,6 +184,5 @@ def main() -> None: stream.write(to_man_page(program_name, spec, **config)) - if __name__ == '__main__': main() diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 78e968f6c4..2fa410114e 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -1,5 +1,6 @@ from __future__ import annotations +import os import textwrap from argparse import FileType @@ -22,6 +23,12 @@ from httpie.plugins.registry import plugin_manager from httpie.ssl_ import AVAILABLE_SSL_VERSION_ARG_MAPPING, DEFAULT_SSL_CIPHERS_STRING + +# Man pages are static (built when making a release). +# We use this check to not include generated, system-specific information there (e.g., default --ciphers). +IS_MAN_PAGE = bool(os.environ.get('HTTPIE_BUILDING_MAN_PAGES')) + + options = ParserSpec( 'http', description=f'{__doc__.strip()} ', @@ -35,7 +42,6 @@ source_file=__file__ ) - ####################################################################### # Positional arguments. ####################################################################### @@ -234,6 +240,7 @@ """, ) + ####################################################################### # Output processing ####################################################################### @@ -610,6 +617,7 @@ def format_style_help(available_styles, *, isolation_mode: bool = False): """, ) + ####################################################################### # Authentication ####################################################################### @@ -630,7 +638,7 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False): if issubclass(auth_plugin, BuiltinAuthPlugin) ] text += '\n' - text += 'For finding out all available authentication types in your system, try:\n\n' + text += 'To see all available auth types on your system, including ones installed via plugins, run:\n\n' text += ' $ http --auth-type' auth_types = '\n\n '.join( @@ -646,7 +654,7 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False): '' if not plugin.description else '\n ' - + ('\n '.join(textwrap.wrap(plugin.description))) + + ('\n '.join(textwrap.wrap(plugin.description))) ), ) for plugin in auth_plugins @@ -826,23 +834,36 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False): """, ) + +CIPHERS_CURRENT_DEFAULTS = ( + """ + See `http --help` for the default ciphers list on you system. + + """ + if IS_MAN_PAGE else + f""" + By default, the following ciphers are used on your system: + + {DEFAULT_SSL_CIPHERS_STRING} + + """ +) ssl.add_argument( '--ciphers', short_help='A string in the OpenSSL cipher list format.', help=f""" - A string in the OpenSSL cipher list format. By default, the following - ciphers are used on your system: + A string in the OpenSSL cipher list format. - {DEFAULT_SSL_CIPHERS_STRING} + {CIPHERS_CURRENT_DEFAULTS} - """, + """ ) ssl.add_argument( '--cert', default=None, type=readable_file_arg, - short_help='Specifys a local cert to use as client side SSL certificate.', + short_help='Specifies a local cert to use as the client-side SSL certificate.', help=""" You can specify a local cert to use as client side SSL certificate. This file may either contain both private key and certificate or you may diff --git a/httpie/output/ui/man_pages.py b/httpie/output/ui/man_pages.py index f0ea4ad72b..0ba4974578 100644 --- a/httpie/output/ui/man_pages.py +++ b/httpie/output/ui/man_pages.py @@ -4,23 +4,22 @@ import os from httpie.context import Environment + MAN_COMMAND = 'man' NO_MAN_PAGES = os.getenv('HTTPIE_NO_MAN_PAGES', False) -# On some systems, HTTP(n) might exist but we are only -# interested in HTTP(1). -# -# For more information on man page sections: https://unix.stackexchange.com/a/138643 - +# On some systems, HTTP(n) might exist, but we are only interested in HTTP(1). +# For more information on man page sections: MAN_PAGE_SECTION = '1' def is_available(program: str) -> bool: - """Check whether HTTPie's man pages are available in this system.""" + """ + Check whether `program`'s man pages are available on this system. + """ if NO_MAN_PAGES or os.system == 'nt': return False - try: process = subprocess.run( [MAN_COMMAND, MAN_PAGE_SECTION, program], @@ -29,7 +28,7 @@ def is_available(program: str) -> bool: stderr=subprocess.DEVNULL ) except Exception: - # There might be some errors outside of the process, e.g + # There might be some errors outside the process, e.g # a permission error to execute something that is not an # executable. return False @@ -38,8 +37,10 @@ def is_available(program: str) -> bool: def display_for(env: Environment, program: str) -> None: - """Display the man page for the given command (http/https).""" + """ + Open the system man page for the given command (http/https/httpie). + """ subprocess.run( [MAN_COMMAND, MAN_PAGE_SECTION, program], stdout=env.stdout, From c8c135ffff0297f42e90ad7f049395b4c1fc1bad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 11:57:31 -0700 Subject: [PATCH 1153/1182] [automated] Update generated content (#1509) Co-authored-by: jakubroztocil --- extras/man/http.1 | 3 +++ extras/man/https.1 | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/extras/man/http.1 b/extras/man/http.1 index 52b3155fa0..aaaa202e8e 100644 --- a/extras/man/http.1 +++ b/extras/man/http.1 @@ -516,6 +516,9 @@ A string in the OpenSSL cipher list format. See `http \fB\,--help\/\fR` for the default ciphers list on you system. + + + .IP "\fB\,--cert\/\fR" diff --git a/extras/man/https.1 b/extras/man/https.1 index 5dd2b7c386..e4f8299978 100644 --- a/extras/man/https.1 +++ b/extras/man/https.1 @@ -509,12 +509,16 @@ are shown here). .IP "\fB\,--ciphers\/\fR" + A string in the OpenSSL cipher list format. See `http \fB\,--help\/\fR` for the default ciphers list on you system. + + + .IP "\fB\,--cert\/\fR" From ec4fb84254fadc56e95cc9dda9a384f2155812aa Mon Sep 17 00:00:00 2001 From: Boris Verkhovskiy Date: Tue, 23 May 2023 15:11:41 +0300 Subject: [PATCH 1154/1182] Document restriction on top-level JSON types explicitly (#1496) * Document restriction on top-level JSON types explicitly * Update docs/README.md --------- Co-authored-by: Jakub Roztocil --- docs/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/README.md b/docs/README.md index 173ccd7a1f..850ba150ae 100644 --- a/docs/README.md +++ b/docs/README.md @@ -915,6 +915,8 @@ http --offline --print=B pie.dev/post \ ] ``` +Sending scalar JSON types (a single `null`, `true`, `false`, string or number) as the top-level object is impossible using the key/value syntax. But you can still pass it via [`--raw=''`](#raw-request-body). + ##### Escaping behavior Nested JSON syntax uses the same [escaping rules](#escaping-rules) as From 30a6f73ec806393d897247b4c7268832de811ff7 Mon Sep 17 00:00:00 2001 From: Rudolf Olah <89982117+rudolfolah@users.noreply.github.com> Date: Wed, 24 May 2023 11:22:56 -0400 Subject: [PATCH 1155/1182] README.md: fix the file based separators internal link (#1510) The link to "file based separators" in the "Reading headers from a file" section when rendered to HTML does not work. The link is now fixed by providing a URL and link text. --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 850ba150ae..0f553dcb5f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1180,7 +1180,7 @@ All of these can be overwritten or unset (see below). ### Reading headers from a file -You can read headers from a file by using the `:@` operator. This would also effectively strip the newlines from the end. See [#file-based-separators] for more examples. +You can read headers from a file by using the `:@` operator. This would also effectively strip the newlines from the end. See [file based separators](#file-based-separators) for more examples. ```bash $ http pie.dev/headers X-Data:@files/text.txt From 011402152c696dafda045c6d7aed7c50a155d14b Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 6 Aug 2023 14:04:32 +0200 Subject: [PATCH 1156/1182] Rename repo from `httpie/httpie` to `httpie/cli` --- .../workflows/release-linux-standalone.yml | 2 +- AUTHORS.md | 2 +- CHANGELOG.md | 256 +++++++++--------- CONTRIBUTING.md | 14 +- MANIFEST.in | 2 +- README.md | 18 +- docs/README.md | 34 +-- docs/packaging/README.md | 6 +- docs/packaging/brew/README.md | 4 +- docs/packaging/brew/httpie.rb | 2 +- docs/packaging/linux-arch/PKGBUILD | 4 +- docs/packaging/linux-debian/README.md | 2 +- docs/packaging/linux-fedora/README.md | 2 +- docs/packaging/linux-fedora/httpie.spec.txt | 2 +- docs/packaging/mac-ports/README.md | 2 +- docs/packaging/snapcraft/README.md | 4 +- docs/packaging/windows-chocolatey/README.md | 4 +- .../windows-chocolatey/httpie.nuspec | 10 +- extras/man/http.1 | 2 +- extras/man/https.1 | 2 +- extras/packaging/linux/README.md | 6 +- extras/profiling/README.md | 2 +- extras/profiling/run.py | 2 +- httpie/cli/definition.py | 2 +- httpie/client.py | 6 +- httpie/downloads.py | 2 +- httpie/plugins/builtin.py | 2 +- httpie/ssl_.py | 2 +- setup.cfg | 2 +- setup.py | 4 +- snapcraft.yaml | 2 +- tests/README.md | 2 +- tests/test_auth.py | 2 +- tests/test_defaults.py | 6 +- tests/test_httpie.py | 4 +- tests/test_output.py | 2 +- tests/test_redirects.py | 2 +- tests/test_regressions.py | 6 +- tests/test_sessions.py | 10 +- tests/test_ssl.py | 2 +- 40 files changed, 221 insertions(+), 221 deletions(-) diff --git a/.github/workflows/release-linux-standalone.yml b/.github/workflows/release-linux-standalone.yml index 07a8522560..01821c9a91 100644 --- a/.github/workflows/release-linux-standalone.yml +++ b/.github/workflows/release-linux-standalone.yml @@ -52,7 +52,7 @@ jobs: id: release_id run: | pip install httpie - export API_URL="api.github.com/repos/httpie/httpie/releases/tags/${{ github.event.inputs.tag_name }}" + export API_URL="api.github.com/repos/httpie/cli/releases/tags/${{ github.event.inputs.tag_name }}" export UPLOAD_URL=`https --ignore-stdin GET $API_URL | jq -r ".upload_url"` echo "::set-output name=UPLOAD_URL::$UPLOAD_URL" diff --git a/AUTHORS.md b/AUTHORS.md index 72fc384df6..5351307d84 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -4,7 +4,7 @@ ## Patches, features, ideas -[Complete list of contributors on GitHub](https://github.com/httpie/httpie/graphs/contributors) +[Complete list of contributors on GitHub](https://github.com/httpie/cli/graphs/contributors) - [Cláudia T. Delgado](https://github.com/claudiatd) - [Hank Gay](https://github.com/gthank) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c14d60aa7..fd80c096f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,151 +3,151 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). -## [3.3.0-dev](https://github.com/httpie/httpie/compare/3.2.2...master) (unreleased) +## [3.3.0-dev](https://github.com/httpie/cli/compare/3.2.2...master) (unreleased) -- Make it possible to [unset](https://httpie.io/docs/cli/default-request-headers) the `User-Agent`, `Accept-Encoding`, and `Host` request headers. ([#1502](https://github.com/httpie/httpie/issues/1502)) +- Make it possible to [unset](https://httpie.io/docs/cli/default-request-headers) the `User-Agent`, `Accept-Encoding`, and `Host` request headers. ([#1502](https://github.com/httpie/cli/issues/1502)) -## [3.2.2](https://github.com/httpie/httpie/compare/3.2.1...3.2.2) (2022-05-19) +## [3.2.2](https://github.com/httpie/cli/compare/3.2.1...3.2.2) (2022-05-19) -- Fixed compatibility with urllib3 2.0.0. ([#1499](https://github.com/httpie/httpie/issues/1499)) +- Fixed compatibility with urllib3 2.0.0. ([#1499](https://github.com/httpie/cli/issues/1499)) -## [3.2.1](https://github.com/httpie/httpie/compare/3.1.0...3.2.1) (2022-05-06) +## [3.2.1](https://github.com/httpie/cli/compare/3.1.0...3.2.1) (2022-05-06) -- Improved support for determining auto-streaming when the `Content-Type` header includes encoding information. ([#1383](https://github.com/httpie/httpie/pull/1383)) -- Fixed the display of the crash happening in the secondary process for update checks. ([#1388](https://github.com/httpie/httpie/issues/1388)) +- Improved support for determining auto-streaming when the `Content-Type` header includes encoding information. ([#1383](https://github.com/httpie/cli/pull/1383)) +- Fixed the display of the crash happening in the secondary process for update checks. ([#1388](https://github.com/httpie/cli/issues/1388)) -## [3.2.0](https://github.com/httpie/httpie/compare/3.1.0...3.2.0) (2022-05-05) +## [3.2.0](https://github.com/httpie/cli/compare/3.1.0...3.2.0) (2022-05-05) -- Added a warning for notifying the user about the new updates. ([#1336](https://github.com/httpie/httpie/pull/1336)) -- Added support for single binary executables. ([#1330](https://github.com/httpie/httpie/pull/1330)) -- Added support for man pages (and auto generation of them from the parser declaration). ([#1317](https://github.com/httpie/httpie/pull/1317)) -- Added `http --manual` for man pages & regular manual with pager. ([#1343](https://github.com/httpie/httpie/pull/1343)) -- Added support for session persistence of repeated headers with the same name. ([#1335](https://github.com/httpie/httpie/pull/1335)) -- Added support for sending `Secure` cookies to the `localhost` (and `.local` suffixed domains). ([#1308](https://github.com/httpie/httpie/issues/1308)) -- Improved UI for the progress bars. ([#1324](https://github.com/httpie/httpie/pull/1324)) -- Fixed redundant creation of `Content-Length` header on `OPTIONS` requests. ([#1310](https://github.com/httpie/httpie/issues/1310)) -- Fixed blocking of warning thread on some use cases. ([#1349](https://github.com/httpie/httpie/issues/1349)) -- Changed `httpie plugins` to the new `httpie cli` namespace as `httpie cli plugins` (`httpie plugins` continues to work as a hidden alias). ([#1320](https://github.com/httpie/httpie/issues/1320)) -- Soft deprecated the `--history-print`. ([#1380](https://github.com/httpie/httpie/pull/1380)) +- Added a warning for notifying the user about the new updates. ([#1336](https://github.com/httpie/cli/pull/1336)) +- Added support for single binary executables. ([#1330](https://github.com/httpie/cli/pull/1330)) +- Added support for man pages (and auto generation of them from the parser declaration). ([#1317](https://github.com/httpie/cli/pull/1317)) +- Added `http --manual` for man pages & regular manual with pager. ([#1343](https://github.com/httpie/cli/pull/1343)) +- Added support for session persistence of repeated headers with the same name. ([#1335](https://github.com/httpie/cli/pull/1335)) +- Added support for sending `Secure` cookies to the `localhost` (and `.local` suffixed domains). ([#1308](https://github.com/httpie/cli/issues/1308)) +- Improved UI for the progress bars. ([#1324](https://github.com/httpie/cli/pull/1324)) +- Fixed redundant creation of `Content-Length` header on `OPTIONS` requests. ([#1310](https://github.com/httpie/cli/issues/1310)) +- Fixed blocking of warning thread on some use cases. ([#1349](https://github.com/httpie/cli/issues/1349)) +- Changed `httpie plugins` to the new `httpie cli` namespace as `httpie cli plugins` (`httpie plugins` continues to work as a hidden alias). ([#1320](https://github.com/httpie/cli/issues/1320)) +- Soft deprecated the `--history-print`. ([#1380](https://github.com/httpie/cli/pull/1380)) -## [3.1.0](https://github.com/httpie/httpie/compare/3.0.2...3.1.0) (2022-03-08) +## [3.1.0](https://github.com/httpie/cli/compare/3.0.2...3.1.0) (2022-03-08) -- **SECURITY** Fixed the [vulnerability](https://github.com/httpie/httpie/security/advisories/GHSA-9w4w-cpc8-h2fq) that caused exposure of cookies on redirects to third party hosts. ([#1312](https://github.com/httpie/httpie/pull/1312)) -- Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/httpie/issues/1285)) -- Fixed displaying of status code without a status message on non-`auto` themes. ([#1300](https://github.com/httpie/httpie/issues/1300)) -- Fixed redundant issuance of stdin detection warnings on some rare cases due to underlying implementation. ([#1303](https://github.com/httpie/httpie/pull/1303)) -- Fixed double `--quiet` so that it will now suppress all python level warnings. ([#1271](https://github.com/httpie/httpie/issues/1271)) -- Added support for specifying certificate private key passphrases through `--cert-key-pass` and prompts. ([#946](https://github.com/httpie/httpie/issues/946)) -- Added `httpie cli export-args` command for exposing the parser specification for the `http`/`https` commands. ([#1293](https://github.com/httpie/httpie/pull/1293)) -- Improved regulation of top-level arrays. ([#1292](https://github.com/httpie/httpie/commit/225dccb2186f14f871695b6c4e0bfbcdb2e3aa28)) -- Improved UI layout for standalone invocations. ([#1296](https://github.com/httpie/httpie/pull/1296)) +- **SECURITY** Fixed the [vulnerability](https://github.com/httpie/cli/security/advisories/GHSA-9w4w-cpc8-h2fq) that caused exposure of cookies on redirects to third party hosts. ([#1312](https://github.com/httpie/cli/pull/1312)) +- Fixed escaping of integer indexes with multiple backslashes in the nested JSON builder. ([#1285](https://github.com/httpie/cli/issues/1285)) +- Fixed displaying of status code without a status message on non-`auto` themes. ([#1300](https://github.com/httpie/cli/issues/1300)) +- Fixed redundant issuance of stdin detection warnings on some rare cases due to underlying implementation. ([#1303](https://github.com/httpie/cli/pull/1303)) +- Fixed double `--quiet` so that it will now suppress all python level warnings. ([#1271](https://github.com/httpie/cli/issues/1271)) +- Added support for specifying certificate private key passphrases through `--cert-key-pass` and prompts. ([#946](https://github.com/httpie/cli/issues/946)) +- Added `httpie cli export-args` command for exposing the parser specification for the `http`/`https` commands. ([#1293](https://github.com/httpie/cli/pull/1293)) +- Improved regulation of top-level arrays. ([#1292](https://github.com/httpie/cli/commit/225dccb2186f14f871695b6c4e0bfbcdb2e3aa28)) +- Improved UI layout for standalone invocations. ([#1296](https://github.com/httpie/cli/pull/1296)) -## [3.0.2](https://github.com/httpie/httpie/compare/3.0.1...3.0.2) (2022-01-24) +## [3.0.2](https://github.com/httpie/cli/compare/3.0.1...3.0.2) (2022-01-24) [What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) -- Fixed usage of `httpie` when there is a presence of a config with `default_options`. ([#1280](https://github.com/httpie/httpie/pull/1280)) +- Fixed usage of `httpie` when there is a presence of a config with `default_options`. ([#1280](https://github.com/httpie/cli/pull/1280)) -## [3.0.1](https://github.com/httpie/httpie/compare/3.0.0...3.0.1) (2022-01-23) +## [3.0.1](https://github.com/httpie/cli/compare/3.0.0...3.0.1) (2022-01-23) [What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) -- Changed the value shown as time elapsed from time-to-read-headers to total exchange time. ([#1277](https://github.com/httpie/httpie/issues/1277)) +- Changed the value shown as time elapsed from time-to-read-headers to total exchange time. ([#1277](https://github.com/httpie/cli/issues/1277)) -## [3.0.0](https://github.com/httpie/httpie/compare/2.6.0...3.0.0) (2022-01-21) +## [3.0.0](https://github.com/httpie/cli/compare/2.6.0...3.0.0) (2022-01-21) [What’s new in HTTPie for Terminal 3.0 →](https://httpie.io/blog/httpie-3.0.0) -- Dropped support for Python 3.6. ([#1177](https://github.com/httpie/httpie/issues/1177)) -- Improved startup time by 40%. ([#1211](https://github.com/httpie/httpie/pull/1211)) -- Added support for nested JSON syntax. ([#1169](https://github.com/httpie/httpie/issues/1169)) -- Added `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/httpie/issues/566)) -- Added support for Bearer authentication via `--auth-type=bearer` ([#1215](https://github.com/httpie/httpie/issues/1215)). -- Added support for quick conversions of pasted URLs into HTTPie calls by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/httpie/issues/1195)) -- Added support for _sending_ multiple HTTP header lines with the same name. ([#130](https://github.com/httpie/httpie/issues/130)) -- Added support for _receiving_ multiple HTTP headers lines with the same name. ([#1207](https://github.com/httpie/httpie/issues/1207)) -- Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) -- Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376)) -- Added support for displaying the total elapsed time through `--meta`/`-vv` or `--print=m`. ([#243](https://github.com/httpie/httpie/issues/243)) -- Added new `pie-dark`/`pie-light` (and `pie`) styles that match with [HTTPie for Web and Desktop](https://httpie.io/product). ([#1237](https://github.com/httpie/httpie/issues/1237)) -- Added support for better error handling on DNS failures. ([#1248](https://github.com/httpie/httpie/issues/1248)) -- Added support for storing prompted passwords in the local sessions. ([#1098](https://github.com/httpie/httpie/issues/1098)) -- Added warnings about the `--ignore-stdin`, when there is no incoming data from stdin. ([#1255](https://github.com/httpie/httpie/issues/1255)) -- Fixed crashing due to broken plugins. ([#1204](https://github.com/httpie/httpie/issues/1204)) -- Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156)) -- Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/httpie/issues/1242)) -- Fixed an unexpected crash when `--raw` is used with `--chunked`. ([#1253](https://github.com/httpie/httpie/issues/1253)) -- Changed the default Windows theme from `fruity` to `auto`. ([#1266](https://github.com/httpie/httpie/issues/1266)) - -## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) +- Dropped support for Python 3.6. ([#1177](https://github.com/httpie/cli/issues/1177)) +- Improved startup time by 40%. ([#1211](https://github.com/httpie/cli/pull/1211)) +- Added support for nested JSON syntax. ([#1169](https://github.com/httpie/cli/issues/1169)) +- Added `httpie plugins` interface for plugin management. ([#566](https://github.com/httpie/cli/issues/566)) +- Added support for Bearer authentication via `--auth-type=bearer` ([#1215](https://github.com/httpie/cli/issues/1215)). +- Added support for quick conversions of pasted URLs into HTTPie calls by adding a space after the protocol name (`$ https ://pie.dev` → `https://pie.dev`). ([#1195](https://github.com/httpie/cli/issues/1195)) +- Added support for _sending_ multiple HTTP header lines with the same name. ([#130](https://github.com/httpie/cli/issues/130)) +- Added support for _receiving_ multiple HTTP headers lines with the same name. ([#1207](https://github.com/httpie/cli/issues/1207)) +- Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/cli/issues/1212)) +- Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/cli/issues/376)) +- Added support for displaying the total elapsed time through `--meta`/`-vv` or `--print=m`. ([#243](https://github.com/httpie/cli/issues/243)) +- Added new `pie-dark`/`pie-light` (and `pie`) styles that match with [HTTPie for Web and Desktop](https://httpie.io/product). ([#1237](https://github.com/httpie/cli/issues/1237)) +- Added support for better error handling on DNS failures. ([#1248](https://github.com/httpie/cli/issues/1248)) +- Added support for storing prompted passwords in the local sessions. ([#1098](https://github.com/httpie/cli/issues/1098)) +- Added warnings about the `--ignore-stdin`, when there is no incoming data from stdin. ([#1255](https://github.com/httpie/cli/issues/1255)) +- Fixed crashing due to broken plugins. ([#1204](https://github.com/httpie/cli/issues/1204)) +- Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/cli/issues/1156)) +- Fixed highlighting when `Content-Type` specifies `charset`. ([#1242](https://github.com/httpie/cli/issues/1242)) +- Fixed an unexpected crash when `--raw` is used with `--chunked`. ([#1253](https://github.com/httpie/cli/issues/1253)) +- Changed the default Windows theme from `fruity` to `auto`. ([#1266](https://github.com/httpie/cli/issues/1266)) + +## [2.6.0](https://github.com/httpie/cli/compare/2.5.0...2.6.0) (2021-10-14) [What’s new in HTTPie for Terminal 2.6.0 →](https://httpie.io/blog/httpie-2.6.0) -- Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/httpie/issues/1130)) -- Added charset auto-detection when `Content-Type` doesn’t include it. ([#1110](https://github.com/httpie/httpie/issues/1110), [#1168](https://github.com/httpie/httpie/issues/1168)) -- Added `--response-charset` to allow overriding the response encoding for terminal display purposes. ([#1168](https://github.com/httpie/httpie/issues/1168)) -- Added `--response-mime` to allow overriding the response mime type for coloring and formatting for the terminal. ([#1168](https://github.com/httpie/httpie/issues/1168)) -- Added the ability to silence warnings through using `-q` or `--quiet` twice (e.g. `-qq`) ([#1175](https://github.com/httpie/httpie/issues/1175)) -- Added installed plugin list to `--debug` output. ([#1165](https://github.com/httpie/httpie/issues/1165)) -- Fixed duplicate keys preservation in JSON data. ([#1163](https://github.com/httpie/httpie/issues/1163)) +- Added support for formatting & coloring of JSON bodies preceded by non-JSON data (e.g., an XXSI prefix). ([#1130](https://github.com/httpie/cli/issues/1130)) +- Added charset auto-detection when `Content-Type` doesn’t include it. ([#1110](https://github.com/httpie/cli/issues/1110), [#1168](https://github.com/httpie/cli/issues/1168)) +- Added `--response-charset` to allow overriding the response encoding for terminal display purposes. ([#1168](https://github.com/httpie/cli/issues/1168)) +- Added `--response-mime` to allow overriding the response mime type for coloring and formatting for the terminal. ([#1168](https://github.com/httpie/cli/issues/1168)) +- Added the ability to silence warnings through using `-q` or `--quiet` twice (e.g. `-qq`) ([#1175](https://github.com/httpie/cli/issues/1175)) +- Added installed plugin list to `--debug` output. ([#1165](https://github.com/httpie/cli/issues/1165)) +- Fixed duplicate keys preservation in JSON data. ([#1163](https://github.com/httpie/cli/issues/1163)) -## [2.5.0](https://github.com/httpie/httpie/compare/2.4.0...2.5.0) (2021-09-06) +## [2.5.0](https://github.com/httpie/cli/compare/2.4.0...2.5.0) (2021-09-06) [What’s new in HTTPie for Terminal 2.5.0 →](https://httpie.io/blog/httpie-2.5.0) - Added `--raw` to allow specifying the raw request body without extra processing as - an alternative to `stdin`. ([#534](https://github.com/httpie/httpie/issues/534)) -- Added support for XML formatting. ([#1129](https://github.com/httpie/httpie/issues/1129)) -- Added internal support for file-like object responses to improve adapter plugin support. ([#1094](https://github.com/httpie/httpie/issues/1094)) -- Fixed `--continue --download` with a single byte to be downloaded left. ([#1032](https://github.com/httpie/httpie/issues/1032)) -- Fixed `--verbose` HTTP 307 redirects with streamed request body. ([#1088](https://github.com/httpie/httpie/issues/1088)) -- Fixed handling of session files with `Cookie:` followed by other headers. ([#1126](https://github.com/httpie/httpie/issues/1126)) + an alternative to `stdin`. ([#534](https://github.com/httpie/cli/issues/534)) +- Added support for XML formatting. ([#1129](https://github.com/httpie/cli/issues/1129)) +- Added internal support for file-like object responses to improve adapter plugin support. ([#1094](https://github.com/httpie/cli/issues/1094)) +- Fixed `--continue --download` with a single byte to be downloaded left. ([#1032](https://github.com/httpie/cli/issues/1032)) +- Fixed `--verbose` HTTP 307 redirects with streamed request body. ([#1088](https://github.com/httpie/cli/issues/1088)) +- Fixed handling of session files with `Cookie:` followed by other headers. ([#1126](https://github.com/httpie/cli/issues/1126)) -## [2.4.0](https://github.com/httpie/httpie/compare/2.3.0...2.4.0) (2021-02-06) +## [2.4.0](https://github.com/httpie/cli/compare/2.3.0...2.4.0) (2021-02-06) -- Added support for `--session` cookie expiration based on `Set-Cookie: max-age=`. ([#1029](https://github.com/httpie/httpie/issues/1029)) -- Show a `--check-status` warning with `--quiet` as well, not only when the output is redirected. ([#1026](https://github.com/httpie/httpie/issues/1026)) -- Fixed upload with `--session` ([#1020](https://github.com/httpie/httpie/issues/1020)). -- Fixed a missing blank line between request and response ([#1006](https://github.com/httpie/httpie/issues/1006)). +- Added support for `--session` cookie expiration based on `Set-Cookie: max-age=`. ([#1029](https://github.com/httpie/cli/issues/1029)) +- Show a `--check-status` warning with `--quiet` as well, not only when the output is redirected. ([#1026](https://github.com/httpie/cli/issues/1026)) +- Fixed upload with `--session` ([#1020](https://github.com/httpie/cli/issues/1020)). +- Fixed a missing blank line between request and response ([#1006](https://github.com/httpie/cli/issues/1006)). -## [2.3.0](https://github.com/httpie/httpie/compare/2.2.0...2.3.0) (2020-10-25) +## [2.3.0](https://github.com/httpie/cli/compare/2.2.0...2.3.0) (2020-10-25) -- Added support for streamed uploads ([#201](https://github.com/httpie/httpie/issues/201)). -- Added support for multipart upload streaming ([#684](https://github.com/httpie/httpie/issues/684)). +- Added support for streamed uploads ([#201](https://github.com/httpie/cli/issues/201)). +- Added support for multipart upload streaming ([#684](https://github.com/httpie/cli/issues/684)). - Added support for body-from-file upload streaming (`http pie.dev/post @file`). -- Added `--chunked` to enable chunked transfer encoding ([#753](https://github.com/httpie/httpie/issues/753)). +- Added `--chunked` to enable chunked transfer encoding ([#753](https://github.com/httpie/cli/issues/753)). - Added `--multipart` to allow `multipart/form-data` encoding for non-file `--form` requests as well. -- Added support for preserving field order in multipart requests ([#903](https://github.com/httpie/httpie/issues/903)). +- Added support for preserving field order in multipart requests ([#903](https://github.com/httpie/cli/issues/903)). - Added `--boundary` to allow a custom boundary string for `multipart/form-data` requests. -- Added support for combining cookies specified on the CLI and in a session file ([#932](https://github.com/httpie/httpie/issues/932)). -- Added out of the box SOCKS support with no extra installation ([#904](https://github.com/httpie/httpie/issues/904)). +- Added support for combining cookies specified on the CLI and in a session file ([#932](https://github.com/httpie/cli/issues/932)). +- Added out of the box SOCKS support with no extra installation ([#904](https://github.com/httpie/cli/issues/904)). - Added `--quiet, -q` flag to enforce silent behaviour. -- Fixed the handling of invalid `expires` dates in `Set-Cookie` headers ([#963](https://github.com/httpie/httpie/issues/963)). -- Removed Tox testing entirely ([#943](https://github.com/httpie/httpie/issues/943)). +- Fixed the handling of invalid `expires` dates in `Set-Cookie` headers ([#963](https://github.com/httpie/cli/issues/963)). +- Removed Tox testing entirely ([#943](https://github.com/httpie/cli/issues/943)). -## [2.2.0](https://github.com/httpie/httpie/compare/2.1.0...2.2.0) (2020-06-18) +## [2.2.0](https://github.com/httpie/cli/compare/2.1.0...2.2.0) (2020-06-18) -- Added support for custom content types for uploaded files ([#668](https://github.com/httpie/httpie/issues/668)). -- Added support for `$XDG_CONFIG_HOME` ([#920](https://github.com/httpie/httpie/issues/920)). -- Added support for `Set-Cookie`-triggered cookie expiration ([#853](https://github.com/httpie/httpie/issues/853)). -- Added `--format-options` to allow disabling sorting, etc. ([#128](https://github.com/httpie/httpie/issues/128)) -- Added `--sorted` and `--unsorted` shortcuts for (un)setting all sorting-related `--format-options`. ([#128](https://github.com/httpie/httpie/issues/128)) -- Added `--ciphers` to allow configuring OpenSSL ciphers ([#870](https://github.com/httpie/httpie/issues/870)). +- Added support for custom content types for uploaded files ([#668](https://github.com/httpie/cli/issues/668)). +- Added support for `$XDG_CONFIG_HOME` ([#920](https://github.com/httpie/cli/issues/920)). +- Added support for `Set-Cookie`-triggered cookie expiration ([#853](https://github.com/httpie/cli/issues/853)). +- Added `--format-options` to allow disabling sorting, etc. ([#128](https://github.com/httpie/cli/issues/128)) +- Added `--sorted` and `--unsorted` shortcuts for (un)setting all sorting-related `--format-options`. ([#128](https://github.com/httpie/cli/issues/128)) +- Added `--ciphers` to allow configuring OpenSSL ciphers ([#870](https://github.com/httpie/cli/issues/870)). - Added `netrc` support for auth plugins. Enabled for `--auth-type=basic` - and `digest`, 3rd parties may opt in ([#718](https://github.com/httpie/httpie/issues/718), [#719](https://github.com/httpie/httpie/issues/719), [#852](https://github.com/httpie/httpie/issues/852), [#934](https://github.com/httpie/httpie/issues/934)). -- Fixed built-in plugins-related circular imports ([#925](https://github.com/httpie/httpie/issues/925)). + and `digest`, 3rd parties may opt in ([#718](https://github.com/httpie/cli/issues/718), [#719](https://github.com/httpie/cli/issues/719), [#852](https://github.com/httpie/cli/issues/852), [#934](https://github.com/httpie/cli/issues/934)). +- Fixed built-in plugins-related circular imports ([#925](https://github.com/httpie/cli/issues/925)). -## [2.1.0](https://github.com/httpie/httpie/compare/2.0.0...2.1.0) (2020-04-18) +## [2.1.0](https://github.com/httpie/cli/compare/2.0.0...2.1.0) (2020-04-18) - Added `--path-as-is` to bypass dot segment (`/../` or `/./`) - URL squashing ([#895](https://github.com/httpie/httpie/issues/895)). + URL squashing ([#895](https://github.com/httpie/cli/issues/895)). - Changed the default `Accept` header value for JSON requests from `application/json, */*` to `application/json, */*;q=0.5` - to clearly indicate preference ([#488](https://github.com/httpie/httpie/issues/488)). + to clearly indicate preference ([#488](https://github.com/httpie/cli/issues/488)). - Fixed `--form` file upload mixed with redirected `stdin` error handling - ([#840](https://github.com/httpie/httpie/issues/840)). + ([#840](https://github.com/httpie/cli/issues/840)). -## [2.0.0](https://github.com/httpie/httpie/compare/1.0.3...2.0.0) (2020-01-12) +## [2.0.0](https://github.com/httpie/cli/compare/1.0.3...2.0.0) (2020-01-12) - Removed Python 2.7 support ([EOL Jan 2020](https://www.python.org/doc/sunset-python-2/). - Added `--offline` to allow building an HTTP request and printing it but not @@ -170,7 +170,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed an error when `stdin` was a closed fd. - Improved `--debug` output formatting. -## [1.0.3](https://github.com/httpie/httpie/compare/1.0.2...1.0.3) (2019-08-26) +## [1.0.3](https://github.com/httpie/cli/compare/1.0.2...1.0.3) (2019-08-26) - Fixed CVE-2019-10751 — the way the output filename is generated for `--download` requests without `--output` resulting in a redirect has @@ -196,15 +196,15 @@ This project adheres to [Semantic Versioning](https://semver.org/). Reported by Raul Onitza and Giulio Comi. -## [1.0.2](https://github.com/httpie/httpie/compare/1.0.1...1.0.2) (2018-11-14) +## [1.0.2](https://github.com/httpie/cli/compare/1.0.1...1.0.2) (2018-11-14) - Fixed tests for installation with pyOpenSSL. -## [1.0.1](https://github.com/httpie/httpie/compare/1.0.0...1.0.1) (2018-11-14) +## [1.0.1](https://github.com/httpie/cli/compare/1.0.0...1.0.1) (2018-11-14) - Removed external URL calls from tests. -## [1.0.0](https://github.com/httpie/httpie/compare/0.9.9...1.0.0) (2018-11-02) +## [1.0.0](https://github.com/httpie/cli/compare/0.9.9...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` @@ -215,11 +215,11 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed default headers being incorrectly case-sensitive. - Removed Python 2.6 support. -## [0.9.9](https://github.com/httpie/httpie/compare/0.9.8...0.9.9) (2016-12-08) +## [0.9.9](https://github.com/httpie/cli/compare/0.9.8...0.9.9) (2016-12-08) - Fixed README. -## [0.9.8](https://github.com/httpie/httpie/compare/0.9.6...0.9.8) (2016-12-08) +## [0.9.8](https://github.com/httpie/cli/compare/0.9.6...0.9.8) (2016-12-08) - Extended auth plugin API. - Added exit status code `7` for plugin errors. @@ -228,7 +228,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Improved `CTRL-C` interrupt handling. - Added the standard exit status code `130` for keyboard interrupts. -## [0.9.6](https://github.com/httpie/httpie/compare/0.9.4...0.9.6) (2016-08-13) +## [0.9.6](https://github.com/httpie/cli/compare/0.9.4...0.9.6) (2016-08-13) - Added Python 3 as a dependency for Homebrew installations to ensure some of the newer HTTP features work out of the box @@ -247,7 +247,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Changed the pre-processing of request HTTP headers so that any leading and trailing whitespace is removed. -## [0.9.4](https://github.com/httpie/httpie/compare/0.9.3...0.9.4) (2016-07-01) +## [0.9.4](https://github.com/httpie/cli/compare/0.9.3...0.9.4) (2016-07-01) - Added `Content-Type` of files uploaded in `multipart/form-data` requests - Added `--ssl=` to specify the desired SSL/TLS protocol version @@ -271,7 +271,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed the handling of `Content-Type` with multiple `+subtype` parts - Removed the XML formatter as the implementation suffered from multiple issues -## [0.9.3](https://github.com/httpie/httpie/compare/0.9.2...0.9.3) (2016-01-01) +## [0.9.3](https://github.com/httpie/cli/compare/0.9.2...0.9.3) (2016-01-01) - Changed the default color `--style` from `solarized` to `monokai` - Added basic Bash autocomplete support (need to be installed manually) @@ -281,19 +281,19 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed colors and formatting on Windows - Fixed `--auth` prompt on Windows -## [0.9.2](https://github.com/httpie/httpie/compare/0.9.1...0.9.2) (2015-02-24) +## [0.9.2](https://github.com/httpie/cli/compare/0.9.1...0.9.2) (2015-02-24) - Fixed compatibility with Requests 2.5.1 - Changed the default JSON `Content-Type` to `application/json` as UTF-8 is the default JSON encoding -## [0.9.1](https://github.com/httpie/httpie/compare/0.9.0...0.9.1) (2015-02-07) +## [0.9.1](https://github.com/httpie/cli/compare/0.9.0...0.9.1) (2015-02-07) - Added support for Requests transport adapter plugins (see [httpie-unixsocket](https://github.com/httpie/httpie-unixsocket) and [httpie-http2](https://github.com/httpie/httpie-http2)) -## [0.9.0](https://github.com/httpie/httpie/compare/0.8.0...0.9.0) (2015-01-31) +## [0.9.0](https://github.com/httpie/cli/compare/0.8.0...0.9.0) (2015-01-31) - Added `--cert` and `--cert-key` parameters to specify a client side certificate and private key for SSL @@ -312,7 +312,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed `--output=/dev/null` on Linux - Miscellaneous bugfixes -## [0.8.0](https://github.com/httpie/httpie/compare/0.7.1...0.8.0) (2014-01-25) +## [0.8.0](https://github.com/httpie/cli/compare/0.7.1...0.8.0) (2014-01-25) - Added `field=@file.txt` and `field:=@file.json` for embedding the contents of text and JSON files into request data @@ -320,7 +320,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed request `Host` header value output so that it doesn't contain credentials, if included in the URL -## [0.7.1](https://github.com/httpie/httpie/compare/0.6.0...0.7.1) (2013-09-24) +## [0.7.1](https://github.com/httpie/cli/compare/0.6.0...0.7.1) (2013-09-24) - Added `--ignore-stdin` - Added support for auth plugins @@ -328,27 +328,27 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Improved `Content-Disposition` parsing for `--download` mode - Update to Requests 2.0.0 -## [0.6.0](https://github.com/httpie/httpie/compare/0.5.1...0.6.0) (2013-06-03) +## [0.6.0](https://github.com/httpie/cli/compare/0.5.1...0.6.0) (2013-06-03) - XML data is now formatted - `--session` and `--session-read-only` now also accept paths to session files (eg. `http --session=/tmp/session.json example.org`) -## [0.5.1](https://github.com/httpie/httpie/compare/0.5.0...0.5.1) (2013-05-13) +## [0.5.1](https://github.com/httpie/cli/compare/0.5.0...0.5.1) (2013-05-13) - `Content-*` and `If-*` request headers are not stored in sessions anymore as they are request-specific -## [0.5.0](https://github.com/httpie/httpie/compare/0.4.1...0.5.0) (2013-04-27) +## [0.5.0](https://github.com/httpie/cli/compare/0.4.1...0.5.0) (2013-04-27) - Added a download mode via `--download` - Fixes miscellaneous bugs -## [0.4.1](https://github.com/httpie/httpie/compare/0.4.0...0.4.1) (2013-02-26) +## [0.4.1](https://github.com/httpie/cli/compare/0.4.0...0.4.1) (2013-02-26) - Fixed `setup.py` -## [0.4.0](https://github.com/httpie/httpie/compare/0.3.0...0.4.0) (2013-02-22) +## [0.4.0](https://github.com/httpie/cli/compare/0.3.0...0.4.0) (2013-02-22) - Added Python 3.3 compatibility - Added Requests >= v1.0.4 compatibility @@ -357,7 +357,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Mutually exclusive arguments can be specified multiple times. The last value is used -## [0.3.0](https://github.com/httpie/httpie/compare/0.2.7...0.3.0) (2012-09-21) +## [0.3.0](https://github.com/httpie/cli/compare/0.2.7...0.3.0) (2012-09-21) - Allow output redirection on Windows - Added configuration file @@ -372,7 +372,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). (`--pretty=all`, `--pretty=colors` and `--pretty=format`) `--ugly` has bee removed in favor of `--pretty=none` -## [0.2.7](https://github.com/httpie/httpie/compare/0.2.5...0.2.7) (2012-08-07) +## [0.2.7](https://github.com/httpie/cli/compare/0.2.5...0.2.7) (2012-08-07) - Added compatibility with Requests 0.13.6 - Added streamed terminal output. `--stream, -S` can be used to enable @@ -389,7 +389,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed printing of `multipart/form-data` requests - Renamed `--traceback` to `--debug` -## [0.2.6](https://github.com/httpie/httpie/compare/0.2.5...0.2.6) (2012-07-26) +## [0.2.6](https://github.com/httpie/cli/compare/0.2.5...0.2.6) (2012-07-26) - The short option for `--headers` is now `-h` (`-t` has been removed, for usage use `--help`) @@ -404,7 +404,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added query string parameters (`param==value`) - Added support for terminal colors under Windows -## [0.2.5](https://github.com/httpie/httpie/compare/0.2.2...0.2.5) (2012-07-17) +## [0.2.5](https://github.com/httpie/cli/compare/0.2.2...0.2.5) (2012-07-17) - Unicode characters in prettified JSON now don't get escaped for improved readability @@ -415,20 +415,20 @@ This project adheres to [Semantic Versioning](https://semver.org/). `--verbose` - Fixed Content-Type for requests with no data -## [0.2.2](https://github.com/httpie/httpie/compare/0.2.1...0.2.2) (2012-06-24) +## [0.2.2](https://github.com/httpie/cli/compare/0.2.1...0.2.2) (2012-06-24) - The `METHOD` positional argument can now be omitted (defaults to `GET`, or to `POST` with data) - Fixed --verbose --form - Added support for Tox -## [0.2.1](https://github.com/httpie/httpie/compare/0.2.0...0.2.1) (2012-06-13) +## [0.2.1](https://github.com/httpie/cli/compare/0.2.0...0.2.1) (2012-06-13) - Added compatibility with `requests-0.12.1` - Dropped custom JSON and HTTP lexers in favor of the ones newly included in `pygments-1.5` -## [0.2.0](https://github.com/httpie/httpie/compare/0.1.6...0.2.0) (2012-04-25) +## [0.2.0](https://github.com/httpie/cli/compare/0.1.6...0.2.0) (2012-04-25) - Added Python 3 support - Added the ability to print the HTTP request as well as the response @@ -440,18 +440,18 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added support for field name escaping - Many bug fixes -## [0.1.6](https://github.com/httpie/httpie/compare/0.1.5...0.1.6) (2012-03-04) +## [0.1.6](https://github.com/httpie/cli/compare/0.1.5...0.1.6) (2012-03-04) - Fixed `setup.py` -## [0.1.5](https://github.com/httpie/httpie/compare/0.1.4...0.1.5) (2012-03-04) +## [0.1.5](https://github.com/httpie/cli/compare/0.1.4...0.1.5) (2012-03-04) - Many improvements and bug fixes -## [0.1.4](https://github.com/httpie/httpie/compare/b966efa...0.1.4) (2012-02-28) +## [0.1.4](https://github.com/httpie/cli/compare/b966efa...0.1.4) (2012-02-28) - Many improvements and bug fixes -## [0.1.0](https://github.com/httpie/httpie/commit/b966efa) (2012-02-25) +## [0.1.0](https://github.com/httpie/cli/commit/b966efa) (2012-02-25) - Initial public release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c0a0e91c1..1360184a8b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,7 @@ $ http --debug ## 2. Contributing Code and Docs -Before working on a new feature or a bug, please browse [existing issues](https://github.com/httpie/httpie/issues) +Before working on a new feature or a bug, please browse [existing issues](https://github.com/httpie/cli/issues) to see whether it has previously been discussed. If your change alters HTTPie’s behaviour or interface, it's a good idea to @@ -38,13 +38,13 @@ for existing-yet-previously-untested behavior will very likely be merged. Therefore, docs and tests improvements are a great candidate for your first contribution. -Consider also adding a [CHANGELOG](https://github.com/httpie/httpie/blob/master/CHANGELOG.md) entry for your changes. +Consider also adding a [CHANGELOG](https://github.com/httpie/cli/blob/master/CHANGELOG.md) entry for your changes. ### Development Environment #### Getting the code -Go to and fork the project repository. +Go to and fork the project repository. ```bash # Clone your fork @@ -59,7 +59,7 @@ $ git checkout -b my_topical_branch #### Setup -The [Makefile](https://github.com/httpie/httpie/blob/master/Makefile) contains a bunch of tasks to get you started. +The [Makefile](https://github.com/httpie/cli/blob/master/Makefile) contains a bunch of tasks to get you started. You can run `$ make` to see all the available tasks. To get started, run the command below, which: @@ -112,7 +112,7 @@ and that `make pycodestyle` passes. Please add tests for any new features and bug fixes. -When you open a Pull Request, [GitHub Actions](https://github.com/httpie/httpie/actions) will automatically run HTTPie’s [test suite](https://github.com/httpie/httpie/tree/master/tests) against your code, so please make sure all checks pass. +When you open a Pull Request, [GitHub Actions](https://github.com/httpie/cli/actions) will automatically run HTTPie’s [test suite](https://github.com/httpie/cli/tree/master/tests) against your code, so please make sure all checks pass. #### Running tests locally @@ -144,7 +144,7 @@ $ python -m pytest tests/test_uploads.py::TestMultipartFormDataFileUpload $ python -m pytest tests/test_uploads.py::TestMultipartFormDataFileUpload::test_upload_ok ``` -See [Makefile](https://github.com/httpie/httpie/blob/master/Makefile) for additional development utilities. +See [Makefile](https://github.com/httpie/cli/blob/master/Makefile) for additional development utilities. #### Running benchmarks @@ -209,4 +209,4 @@ $ python -m pytest ______________________________________________________________________ -Finally, feel free to add yourself to [AUTHORS](https://github.com/httpie/httpie/blob/master/AUTHORS.md)! +Finally, feel free to add yourself to [AUTHORS](https://github.com/httpie/cli/blob/master/AUTHORS.md)! diff --git a/MANIFEST.in b/MANIFEST.in index e166aa09fb..a09a3037eb 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,5 +4,5 @@ include CHANGELOG.md include AUTHORS.md include docs/README.md -# +# recursive-include tests/ * diff --git a/README.md b/README.md index 6a31b02fdc..e8d1c33db1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

      - HTTPie + HTTPie
      HTTPie for Terminal: human-friendly CLI HTTP client for the API era @@ -21,8 +21,8 @@ [![Docs](https://img.shields.io/badge/stable%20docs-httpie.io%2Fdocs%2Fcli-brightgreen?style=flat&color=%2373DC8C&label=Docs)](https://httpie.org/docs/cli) [![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/httpie) -[![Build](https://img.shields.io/github/actions/workflow/status/httpie/httpie/tests.yml?branch=master&color=%23FA9BFA&label=Build)](https://github.com/httpie/httpie/actions) -[![Coverage](https://img.shields.io/codecov/c/github/httpie/httpie?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/httpie) +[![Build](https://img.shields.io/github/actions/workflow/status/httpie/cli/tests.yml?branch=master&color=%23FA9BFA&label=Build)](https://github.com/httpie/cli/actions) +[![Coverage](https://img.shields.io/codecov/c/github/httpie/cli?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/cli)

      @@ -34,7 +34,7 @@ They use simple and natural syntax and provide formatted and colorized output.
      -HTTPie in action +HTTPie in action
      @@ -88,10 +88,10 @@ Build and print a request without sending it using [offline mode](https://httpie http --offline pie.dev/post hello=offline ``` -Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comment) to post a comment on an [Issue](https://github.com/httpie/httpie/issues/83) with [authentication](https://httpie.io/docs#authentication): +Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comment) to post a comment on an [Issue](https://github.com/httpie/cli/issues/83) with [authentication](https://httpie.io/docs#authentication): ```bash -http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comments body='HTTPie is awesome! :heart:' +http -a USERNAME POST https://api.github.com/repos/httpie/cli/issues/83/comments body='HTTPie is awesome! :heart:' ``` [See more examples →](https://httpie.io/docs#examples) @@ -102,11 +102,11 @@ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comme - Join our [Discord server](https://httpie.io/discord) is to ask questions, discuss features, and for general API chat. - Tweet at [@httpie](https://twitter.com/httpie) on Twitter. - Use [StackOverflow](https://stackoverflow.com/questions/tagged/httpie) to ask questions and include a `httpie` tag. -- Create [GitHub Issues](https://github.com/httpie/httpie/issues) for bug reports and feature requests. +- Create [GitHub Issues](https://github.com/httpie/cli/issues) for bug reports and feature requests. - Subscribe to the [HTTPie newsletter](https://httpie.io) for occasional updates. ## Contributing -Have a look through existing [Issues](https://github.com/httpie/httpie/issues) and [Pull Requests](https://github.com/httpie/httpie/pulls) that you could help with. If you'd like to request a feature or report a bug, please [create a GitHub Issue](https://github.com/httpie/httpie/issues) using one of the templates provided. +Have a look through existing [Issues](https://github.com/httpie/cli/issues) and [Pull Requests](https://github.com/httpie/cli/pulls) that you could help with. If you'd like to request a feature or report a bug, please [create a GitHub Issue](https://github.com/httpie/cli/issues) using one of the templates provided. -[See contribution guide →](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md) +[See contribution guide →](https://github.com/httpie/cli/blob/master/CONTRIBUTING.md) diff --git a/docs/README.md b/docs/README.md index 0f553dcb5f..3b12e98f4c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -19,7 +19,7 @@ This documentation is best viewed at [httpie.io/docs](https://httpie.org/docs). You can select your corresponding HTTPie version as well as run examples directly from the browser using a [termible.io](https://termible.io?utm_source=httpie-readme) embedded terminal. If you are reading this on GitHub, then this text covers the current *development* version. -You are invited to submit fixes and improvements to the docs by editing [this file](https://github.com/httpie/httpie/blob/master/docs/README.md). +You are invited to submit fixes and improvements to the docs by editing [this file](https://github.com/httpie/cli/blob/master/docs/README.md). @@ -255,7 +255,7 @@ If you want to try out the latest version of HTTPie that hasn't been officially You can use the following command to install the development version of HTTPie on Linux, macOS, Windows, or FreeBSD operating systems. With this command, the code present in the `master` branch is downloaded and installed using `pip`. ```bash -$ python -m pip install --upgrade https://github.com/httpie/httpie/archive/master.tar.gz +$ python -m pip install --upgrade https://github.com/httpie/cli/archive/master.tar.gz ``` There are other ways to install the development version of HTTPie on macOS and Linux. @@ -274,7 +274,7 @@ $ snap remove httpie $ snap install httpie --edge ``` -To verify the installation, you can compare the [version identifier on GitHub](https://github.com/httpie/httpie/blob/master/httpie/__init__.py#L6) with the one available on your machine. You can check the version of HTTPie on your machine by using the command `http --version`. +To verify the installation, you can compare the [version identifier on GitHub](https://github.com/httpie/cli/blob/master/httpie/__init__.py#L6) with the one available on your machine. You can check the version of HTTPie on your machine by using the command `http --version`. ```bash $ http --version @@ -325,10 +325,10 @@ Build and print a request without sending it using [offline mode](#offline-mode) $ http --offline pie.dev/post hello=offline ``` -Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comment) to post a comment on an [issue](https://github.com/httpie/httpie/issues/83) with [authentication](#authentication): +Use [GitHub API](https://developer.github.com/v3/issues/comments/#create-a-comment) to post a comment on an [issue](https://github.com/httpie/cli/issues/83) with [authentication](#authentication): ```bash -$ http -a USERNAME POST https://api.github.com/repos/httpie/httpie/issues/83/comments body='HTTPie is awesome! :heart:' +$ http -a USERNAME POST https://api.github.com/repos/httpie/cli/issues/83/comments body='HTTPie is awesome! :heart:' ``` Upload a file using [redirected input](#redirected-input): @@ -1754,7 +1754,7 @@ $ http pie.dev/post <<<'{"name": "John"}' You can even pipe web services together using HTTPie: ```bash -$ http GET https://api.github.com/repos/httpie/httpie | http POST pie.dev/post +$ http GET https://api.github.com/repos/httpie/cli | http POST pie.dev/post ``` You can use `cat` to enter multiline data on the terminal: @@ -2002,7 +2002,7 @@ HTTPie features a download mode in which it acts similarly to `wget`. When enabled using the `--download, -d` flag, response headers are printed to the terminal (`stderr`), and a progress bar is shown while the response body is being saved to a file. ```bash -$ http --download https://github.com/httpie/httpie/archive/master.tar.gz +$ http --download https://github.com/httpie/cli/archive/master.tar.gz ``` ```http @@ -2031,7 +2031,7 @@ To prevent data loss by overwriting, HTTPie adds a unique numerical suffix to th You can also redirect the response body to another program while the response headers and progress are still shown in the terminal: ```bash -$ http -d https://github.com/httpie/httpie/archive/master.tar.gz | tar zxf - +$ http -d https://github.com/httpie/cli/archive/master.tar.gz | tar zxf - ``` ### Resuming downloads @@ -2313,7 +2313,7 @@ These flags are available for both `sessions upgrade` and `sessions upgrade-all` | Option | Description | |------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `--bind-cookies` | Bind all previously [unbound cookies](#host-based-cookie-policy) to the session’s host ([context](https://github.com/httpie/httpie/security/advisories/GHSA-9w4w-cpc8-h2fq)). | +| `--bind-cookies` | Bind all previously [unbound cookies](#host-based-cookie-policy) to the session’s host ([context](https://github.com/httpie/cli/security/advisories/GHSA-9w4w-cpc8-h2fq)). | ## Config @@ -2406,7 +2406,7 @@ To prevent your program from becoming unresponsive when the server fails to resp ## Plugin manager -HTTPie offers extensibility through a [plugin API](https://github.com/httpie/httpie/blob/master/httpie/plugins/base.py), +HTTPie offers extensibility through a [plugin API](https://github.com/httpie/cli/blob/master/httpie/plugins/base.py), and there are dozens of plugins available to try! They add things like new authentication methods ([akamai/httpie-edgegrid](https://github.com/akamai/httpie-edgegrid)), transport mechanisms ([httpie/httpie-unixsocket](https://github.com/httpie/httpie-unixsocket)), @@ -2546,7 +2546,7 @@ All changes are recorded in the [change log](#change-log). HTTPie has the following community channels: -- [GitHub Issues](https://github.com/httpie/httpie/issues) for bug reports and feature requests +- [GitHub Issues](https://github.com/httpie/cli/issues) for bug reports and feature requests - [Discord server](https://httpie.io/discord) to ask questions, discuss features, and for general API development discussion - [StackOverflow](https://stackoverflow.com) to ask questions (make sure to use the [httpie](https://stackoverflow.com/questions/tagged/httpie) tag) @@ -2577,25 +2577,25 @@ Helpers to convert from other client tools: ### Contributing -See [CONTRIBUTING](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md). +See [CONTRIBUTING](https://github.com/httpie/cli/blob/master/CONTRIBUTING.md). ### Security policy -See [github.com/httpie/httpie/security/policy](https://github.com/httpie/httpie/security/policy). +See [github.com/httpie/cli/security/policy](https://github.com/httpie/cli/security/policy). ### Change log -See [CHANGELOG](https://github.com/httpie/httpie/blob/master/CHANGELOG.md). +See [CHANGELOG](https://github.com/httpie/cli/blob/master/CHANGELOG.md). ### Artwork -- [README Animation](https://github.com/httpie/httpie/blob/master/docs/httpie-animation.gif) by [Allen Smith](https://github.com/loranallensmith). +- [README Animation](https://github.com/httpie/cli/blob/master/docs/httpie-animation.gif) by [Allen Smith](https://github.com/loranallensmith). ### Licence -BSD-3-Clause: [LICENSE](https://github.com/httpie/httpie/blob/master/LICENSE). +BSD-3-Clause: [LICENSE](https://github.com/httpie/cli/blob/master/LICENSE). ### Authors -[Jakub Roztocil](https://roztocil.co) ([@jakubroztocil](https://twitter.com/jakubroztocil)) created HTTPie and [these fine people](https://github.com/httpie/httpie/blob/master/AUTHORS.md) have contributed. +[Jakub Roztocil](https://roztocil.co) ([@jakubroztocil](https://twitter.com/jakubroztocil)) created HTTPie and [these fine people](https://github.com/httpie/cli/blob/master/AUTHORS.md) have contributed. diff --git a/docs/packaging/README.md b/docs/packaging/README.md index 5354b5e5b7..e455742cc5 100644 --- a/docs/packaging/README.md +++ b/docs/packaging/README.md @@ -3,7 +3,7 @@ Welcome on the documentation part of the **HTTPie release process**. - If you do not know HTTPie, have a look [here](https://httpie.io/cli). -- If you are looking for HTTPie installation or upgrade instructions, then you can find all you need for your OS on [that page](https://httpie.io/docs#installation). In the case you do not find your OS, [let us know](https://github.com/httpie/httpie/issues/). +- If you are looking for HTTPie installation or upgrade instructions, then you can find all you need for your OS on [that page](https://httpie.io/docs#installation). In the case you do not find your OS, [let us know](https://github.com/httpie/cli/issues/). - If you are looking for technical information about the HTTPie packaging, then you are at the good place. ## About @@ -25,7 +25,7 @@ The overall release process starts simple: ## Company-specific tasks -- Blank the `master_and_released_docs_differ_after` value in [config.json](https://github.com/httpie/httpie/blob/master/docs/config.json). +- Blank the `master_and_released_docs_differ_after` value in [config.json](https://github.com/httpie/cli/blob/master/docs/config.json). - Update the [contributors list](../contributors). - Update the HTTPie version bundled into [Termible](https://termible.io/) ([example](https://github.com/httpie/termible/pull/1)). @@ -44,4 +44,4 @@ A more complete state of deployment can be found on [repology](https://repology. | [Snapcraft](snapcraft/) | **HTTPie** | | [Windows — Chocolatey](windows-chocolatey/) | **HTTPie** | -:new: You do not find your system or you would like to see HTTPie supported on another OS? Then [let us know](https://github.com/httpie/httpie/issues/). +:new: You do not find your system or you would like to see HTTPie supported on another OS? Then [let us know](https://github.com/httpie/cli/issues/). diff --git a/docs/packaging/brew/README.md b/docs/packaging/brew/README.md index 933e7cb2f3..a06324ecd3 100644 --- a/docs/packaging/brew/README.md +++ b/docs/packaging/brew/README.md @@ -13,7 +13,7 @@ We will discuss setting up the environment, installing development tools, instal ## Overall process -The brew deployment is completely automated, and only requires a trigger to [`Release on Homebrew`](https://github.com/httpie/httpie/actions/workflows/release-brew.yml) action +The brew deployment is completely automated, and only requires a trigger to [`Release on Homebrew`](https://github.com/httpie/cli/actions/workflows/release-brew.yml) action from the release manager. If it is needed to be done manually, the following command can be used: @@ -26,6 +26,6 @@ which will bump the formula, and create a PR against the package index. ## Hacking -Make your changes, test the formula through the [`Test Brew Package`](https://github.com/httpie/httpie/actions/workflows/test-package-mac-brew.yml) action +Make your changes, test the formula through the [`Test Brew Package`](https://github.com/httpie/cli/actions/workflows/test-package-mac-brew.yml) action and then finally submit your patch to [`homebrew-core`](https://github.com/Homebrew/homebrew-core`) diff --git a/docs/packaging/brew/httpie.rb b/docs/packaging/brew/httpie.rb index 6a6257ed74..e249a5aa10 100644 --- a/docs/packaging/brew/httpie.rb +++ b/docs/packaging/brew/httpie.rb @@ -6,7 +6,7 @@ class Httpie < Formula url "https://files.pythonhosted.org/packages/32/85/bb095699be20cc98731261cb80884e9458178f8fef2a38273530ce77c0a5/httpie-3.1.0.tar.gz" sha256 "2e4a2040b84a912e65c01fb34f7aafe88cad2a3af2da8c685ca65080f376feda" license "BSD-3-Clause" - head "https://github.com/httpie/httpie.git", branch: "master" + head "https://github.com/httpie/cli.git", branch: "master" bottle do sha256 cellar: :any_skip_relocation, arm64_monterey: "9bb6e8c1ef5ba8b019ddedd7e908dd2174da695351aa9a238dfb28b0f57ef005" diff --git a/docs/packaging/linux-arch/PKGBUILD b/docs/packaging/linux-arch/PKGBUILD index d483fd67b2..5ecec154e8 100644 --- a/docs/packaging/linux-arch/PKGBUILD +++ b/docs/packaging/linux-arch/PKGBUILD @@ -7,7 +7,7 @@ pkgname=httpie pkgver=2.6.0 pkgrel=1 pkgdesc="human-friendly CLI HTTP client for the API era" -url="https://github.com/httpie/httpie" +url="https://github.com/httpie/cli" depends=('python-defusedxml' 'python-pygments' 'python-pysocks' @@ -22,7 +22,7 @@ conflicts=(python-httpie) replaces=(python-httpie python2-httpie) license=('BSD') arch=('any') -source=($pkgname-$pkgver.tar.gz::"https://github.com/httpie/httpie/archive/$pkgver.tar.gz") +source=($pkgname-$pkgver.tar.gz::"https://github.com/httpie/cli/archive/$pkgver.tar.gz") sha256sums=('3bcd9a8cb2b11299da12d3af36c095c6d4b665e41c395898a07f1ae4d99fc14a') build() { diff --git a/docs/packaging/linux-debian/README.md b/docs/packaging/linux-debian/README.md index 10c409f757..4ec0c0e24e 100644 --- a/docs/packaging/linux-debian/README.md +++ b/docs/packaging/linux-debian/README.md @@ -17,7 +17,7 @@ command (due to the underlying `httpie cli plugins` interface) explicitly depend ## Overall process -The [`Release as Standalone Linux Binary`](https://github.com/httpie/httpie/actions/workflows/release-linux-standalone.yml) will be automatically +The [`Release as Standalone Linux Binary`](https://github.com/httpie/cli/actions/workflows/release-linux-standalone.yml) will be automatically triggered when a new release is created, and it will submit the `.deb` package as a release asset. For making that asset available for all debian users, the release manager needs to go to the [`httpie/debian.httpie.io`](https://github.com/httpie/debian.httpie.io) repo diff --git a/docs/packaging/linux-fedora/README.md b/docs/packaging/linux-fedora/README.md index b21e003d25..e8bcf99039 100644 --- a/docs/packaging/linux-fedora/README.md +++ b/docs/packaging/linux-fedora/README.md @@ -15,7 +15,7 @@ The current maintainer is [Miro Hrončok](https://github.com/hroncok). ## Overall process -We added the [.packit.yaml](https://github.com/httpie/httpie/blob/master/.packit.yaml) local file. +We added the [.packit.yaml](https://github.com/httpie/cli/blob/master/.packit.yaml) local file. It unlocks real-time Fedora checks on pull requests and new releases. So there is nothing to do on our side: `Packit` will see the new release and open a pull request [there](https://src.fedoraproject.org/rpms/httpie). Then, the Fedora maintainer will review and merge. diff --git a/docs/packaging/linux-fedora/httpie.spec.txt b/docs/packaging/linux-fedora/httpie.spec.txt index 5ac2097edd..3414b188c1 100644 --- a/docs/packaging/linux-fedora/httpie.spec.txt +++ b/docs/packaging/linux-fedora/httpie.spec.txt @@ -5,7 +5,7 @@ Summary: A Curl-like tool for humans License: BSD URL: https://httpie.org/ -Source0: https://github.com/httpie/httpie/archive/%{version}/%{name}-%{version}.tar.gz +Source0: https://github.com/httpie/cli/archive/%{version}/%{name}-%{version}.tar.gz BuildArch: noarch diff --git a/docs/packaging/mac-ports/README.md b/docs/packaging/mac-ports/README.md index 2d8170afa4..792638789f 100644 --- a/docs/packaging/mac-ports/README.md +++ b/docs/packaging/mac-ports/README.md @@ -19,7 +19,7 @@ Open a pull request to update the [downstream file](https://github.com/macports/ ```bash # Download the archive - $ wget https://api.github.com/repos/httpie/httpie/tarball/2.5.0 + $ wget https://api.github.com/repos/httpie/cli/tarball/2.5.0 # Size $ stat --printf="%s\n" 2.5.0 diff --git a/docs/packaging/snapcraft/README.md b/docs/packaging/snapcraft/README.md index fda653417a..e7c37c4782 100644 --- a/docs/packaging/snapcraft/README.md +++ b/docs/packaging/snapcraft/README.md @@ -13,7 +13,7 @@ We will discuss setting up the environment, installing development tools, instal ## Overall process -Trigger the [`Release on Snap`](https://github.com/httpie/httpie/actions/workflows/release-snap.yml) action, which will +Trigger the [`Release on Snap`](https://github.com/httpie/cli/actions/workflows/release-snap.yml) action, which will create a snap package for HTTPie and then push it to Snap Store in the following channels: - Edge @@ -37,7 +37,7 @@ From inside the container: ```bash # Clone -git clone --depth=1 https://github.com/httpie/httpie.git +git clone --depth=1 https://github.com/httpie/cli.git cd httpie # Build diff --git a/docs/packaging/windows-chocolatey/README.md b/docs/packaging/windows-chocolatey/README.md index 50ee9d7006..33c5d35f11 100644 --- a/docs/packaging/windows-chocolatey/README.md +++ b/docs/packaging/windows-chocolatey/README.md @@ -14,7 +14,7 @@ We will discuss setting up the environment, installing development tools, instal ## Overall process After having successfully [built and tested](#hacking) the package, either trigger the -[`Release on Chocolatey`](https://github.com/httpie/httpie/actions/workflows/release-choco.yml) action +[`Release on Chocolatey`](https://github.com/httpie/cli/actions/workflows/release-choco.yml) action to push it to the `Chocolatey` store or use the CLI: ```bash @@ -29,7 +29,7 @@ sets of reviews (some of them are done manually). ```bash # Clone -git clone --depth=1 https://github.com/httpie/httpie.git +git clone --depth=1 https://github.com/httpie/cli.git cd httpie/docs/packaging/windows-chocolatey # Build diff --git a/docs/packaging/windows-chocolatey/httpie.nuspec b/docs/packaging/windows-chocolatey/httpie.nuspec index 858fa5e20a..1d8c69790a 100644 --- a/docs/packaging/windows-chocolatey/httpie.nuspec +++ b/docs/packaging/windows-chocolatey/httpie.nuspec @@ -30,16 +30,16 @@ Main features: HTTPie jakubroztocil 2012-2022 Jakub Roztocil - https://raw.githubusercontent.com/httpie/httpie/master/LICENSE + https://raw.githubusercontent.com/httpie/cli/master/LICENSE https://pie-assets.s3.eu-central-1.amazonaws.com/LogoIcons/GB.png false - See the [changelog](https://github.com/httpie/httpie/releases/tag/3.2.2). + See the [changelog](https://github.com/httpie/cli/releases/tag/3.2.2). httpie http https rest api client curl python ssl cli foss oss url https://httpie.io - https://github.com/httpie/httpie/tree/master/docs/packaging/windows-chocolatey - https://github.com/httpie/httpie + https://github.com/httpie/cli/tree/master/docs/packaging/windows-chocolatey + https://github.com/httpie/cli https://httpie.io/docs - https://github.com/httpie/httpie/issues + https://github.com/httpie/cli/issues diff --git a/extras/man/http.1 b/extras/man/http.1 index aaaa202e8e..95e74740ad 100644 --- a/extras/man/http.1 +++ b/extras/man/http.1 @@ -597,4 +597,4 @@ For every \fB\,--OPTION\/\fR there is also a \fB\,--no-OPTION\/\fR that reverts to its default value. Suggestions and bug reports are greatly appreciated: -https://github.com/httpie/httpie/issues \ No newline at end of file +https://github.com/httpie/cli/issues diff --git a/extras/man/https.1 b/extras/man/https.1 index e4f8299978..6db6828db6 100644 --- a/extras/man/https.1 +++ b/extras/man/https.1 @@ -597,4 +597,4 @@ For every \fB\,--OPTION\/\fR there is also a \fB\,--no-OPTION\/\fR that reverts to its default value. Suggestions and bug reports are greatly appreciated: -https://github.com/httpie/httpie/issues \ No newline at end of file +https://github.com/httpie/cli/issues diff --git a/extras/packaging/linux/README.md b/extras/packaging/linux/README.md index 2958dfaef4..ab18bfd02f 100644 --- a/extras/packaging/linux/README.md +++ b/extras/packaging/linux/README.md @@ -7,13 +7,13 @@ This directory contains the build scripts for creating: - A self-contained binary executable for the HTTPie itself - `httpie.deb` and `httpie.rpm` packages for Debian and Fedora. -The process of constructing them are fully automated, and can be easily done through the [`Release as Standalone Linux Package`](https://github.com/httpie/httpie/actions/workflows/release-linux-standalone.yml) +The process of constructing them are fully automated, and can be easily done through the [`Release as Standalone Linux Package`](https://github.com/httpie/cli/actions/workflows/release-linux-standalone.yml) action. Once it finishes, the release artifacts will be attached in the summary page of the triggered run. ## Hacking -The main entry point for the package builder is the [`build.py`](https://github.com/httpie/httpie/blob/master/extras/packaging/linux/build.py). It +The main entry point for the package builder is the [`build.py`](https://github.com/httpie/cli/blob/master/extras/packaging/linux/build.py). It contains 2 major methods: - `build_binaries`, for the self-contained executables @@ -39,7 +39,7 @@ Since the `httpie` depends on having a pip executable, we explicitly depend on t ### Docker Image -This directory also contains a [docker image](https://github.com/httpie/httpie/blob/master/extras/packaging/linux/Dockerfile) which helps +This directory also contains a [docker image](https://github.com/httpie/cli/blob/master/extras/packaging/linux/Dockerfile) which helps building our standalone binaries in an isolated environment with the lowest possible library versions. This is important, since even though the executables are standalone they still depend on some main system C libraries (like `glibc`) so we need to create our executables inside an environment with a very old (but not deprecated) glibc version. It makes us soundproof for all active Ubuntu/Debian versions. diff --git a/extras/profiling/README.md b/extras/profiling/README.md index ba496605a1..aff4c68614 100644 --- a/extras/profiling/README.md +++ b/extras/profiling/README.md @@ -28,7 +28,7 @@ on both of them. It will compare the results and print it as a markdown table: | Geometric mean | (ref) | 1.10x faster | If your `master` branch is not up-to-date, you can get a fresh clone by passing -`--fresh` option. This way, the benchmark runner will clone the `httpie/httpie` +`--fresh` option. This way, the benchmark runner will clone the `httpie/cli` repo from `GitHub` and use it as the baseline. You can customize these branches by passing `--local-repo`/`--target-branch`, diff --git a/extras/profiling/run.py b/extras/profiling/run.py index d03827b0b0..040e4389e7 100644 --- a/extras/profiling/run.py +++ b/extras/profiling/run.py @@ -50,7 +50,7 @@ BENCHMARK_SCRIPT = Path(__file__).parent / 'benchmarks.py' CURRENT_REPO = Path(__file__).parent.parent.parent -GITHUB_URL = 'https://github.com/httpie/httpie.git' +GITHUB_URL = 'https://github.com/httpie/cli.git' TARGET_BRANCH = 'master' # Additional dependencies for --complex diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 2fa410114e..843b29c9cf 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -37,7 +37,7 @@ to its default value. Suggestions and bug reports are greatly appreciated: - https://github.com/httpie/httpie/issues + https://github.com/httpie/cli/issues """, source_file=__file__ ) diff --git a/httpie/client.py b/httpie/client.py index a96b246701..a1da284a7c 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -143,7 +143,7 @@ def collect_messages( # noinspection PyProtectedMember @contextmanager def max_headers(limit): - # + # # noinspection PyUnresolvedReferences orig = http.client._MAXHEADERS http.client._MAXHEADERS = limit or float('Inf') @@ -199,7 +199,7 @@ def finalize_headers(headers: HTTPHeadersDict) -> HTTPHeadersDict: # Also, requests raises `InvalidHeader` for leading spaces. value = value.strip() if isinstance(value, str): - # See + # See value = value.encode() elif name.lower() in SKIPPABLE_HEADERS: # Some headers get overwritten by urllib3 when set to `None` @@ -381,7 +381,7 @@ def ensure_path_as_is(orig_url: str, prepped_url: str) -> str: untouched because other (welcome) processing on the URL might have taken place. - + diff --git a/httpie/downloads.py b/httpie/downloads.py index 557be87b46..9c4b895e6f 100644 --- a/httpie/downloads.py +++ b/httpie/downloads.py @@ -217,7 +217,7 @@ def start( assert not self.status.time_started # FIXME: some servers still might sent Content-Encoding: gzip - # + # try: total_size = int(final_response.headers['Content-Length']) except (KeyError, ValueError, TypeError): diff --git a/httpie/plugins/builtin.py b/httpie/plugins/builtin.py index 8a2dae615c..860aebf7f9 100644 --- a/httpie/plugins/builtin.py +++ b/httpie/plugins/builtin.py @@ -19,7 +19,7 @@ def __call__( """ Override username/password serialization to allow unicode. - See https://github.com/httpie/httpie/issues/212 + See https://github.com/httpie/cli/issues/212 """ # noinspection PyTypeChecker diff --git a/httpie/ssl_.py b/httpie/ssl_.py index af71dfb956..af5ca548db 100644 --- a/httpie/ssl_.py +++ b/httpie/ssl_.py @@ -101,5 +101,5 @@ def _is_key_file_encrypted(key_file): # We used to import the default set of TLS ciphers from urllib3, but they removed it. # Instead, now urllib3 uses the list of ciphers configured by the system. -# +# DEFAULT_SSL_CIPHERS_STRING = ':'.join(HTTPieHTTPSAdapter.get_default_ciphers_names()) diff --git a/setup.cfg b/setup.cfg index 2deb39a788..86c41ff308 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ # Please keep all characters in this file in ASCII # distutils uses system's locale to interpret it and not everybody -# uses UTF-8. See https://github.com/httpie/httpie/issues/1039 +# uses UTF-8. See https://github.com/httpie/cli/issues/1039 # for an example [wheel] diff --git a/setup.py b/setup.py index f506f2d0cd..93bdb8f957 100644 --- a/setup.py +++ b/setup.py @@ -77,7 +77,7 @@ def long_description(): long_description=long_description(), long_description_content_type='text/markdown', url='https://httpie.io/', - download_url=f'https://github.com/httpie/httpie/archive/{httpie.__version__}.tar.gz', + download_url=f'https://github.com/httpie/cli/archive/{httpie.__version__}.tar.gz', author=httpie.__author__, author_email='jakub@roztocil.co', license=httpie.__licence__, @@ -108,7 +108,7 @@ def long_description(): 'Topic :: Utilities' ], project_urls={ - 'GitHub': 'https://github.com/httpie/httpie', + 'GitHub': 'https://github.com/httpie/cli', 'Twitter': 'https://twitter.com/httpie', 'Discord': 'https://httpie.io/discord', 'Documentation': 'https://httpie.io/docs', diff --git a/snapcraft.yaml b/snapcraft.yaml index eb620c0e16..1d9246a400 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -31,7 +31,7 @@ description: | Links - Documentation: https://httpie.io/docs - Try in browser: https://httpie.io/run - - GitHub: https://github.com/httpie/httpie + - GitHub: https://github.com/httpie/cli - Twitter: https://twitter.com/httpie - Discord: https://httpie.io/chat license: BSD-3-Clause-LBNL diff --git a/tests/README.md b/tests/README.md index d3e460914e..75d2a2a867 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,3 +1,3 @@ # HTTPie Test Suite -Please see [CONTRIBUTING](https://github.com/httpie/httpie/blob/master/CONTRIBUTING.md) for contribution and testing guidelines. +Please see [CONTRIBUTING](https://github.com/httpie/cli/blob/master/CONTRIBUTING.md) for contribution and testing guidelines. diff --git a/tests/test_auth.py b/tests/test_auth.py index 219576a327..696fb22826 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -71,7 +71,7 @@ def test_credentials_in_url_auth_flag_has_priority(httpbin_both): ]) def test_only_username_in_url(url): """ - https://github.com/httpie/httpie/issues/242 + https://github.com/httpie/cli/issues/242 """ args = httpie.cli.definition.parser.parse_args(args=[url], env=MockEnvironment()) diff --git a/tests/test_defaults.py b/tests/test_defaults.py index 22c7aae25d..267be2ae8d 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -11,7 +11,7 @@ def test_default_headers_case_insensitive(httpbin): """ - + """ r = http( '--debug', @@ -68,7 +68,7 @@ class TestAutoContentTypeAndAcceptHeaders: """ def test_GET_no_data_no_auto_headers(self, httpbin): - # https://github.com/httpie/httpie/issues/62 + # https://github.com/httpie/cli/issues/62 r = http('GET', httpbin.url + '/headers') assert HTTP_OK in r assert r.json['headers']['Accept'] == '*/*' @@ -99,7 +99,7 @@ def test_POST_explicit_JSON_JSON_ACCEPT(self, httpbin): 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/httpie/httpie/issues/137 + # https://github.com/httpie/cli/issues/137 assert 'application/json' in r.json['headers']['Content-Type'] def test_GET_explicit_JSON_explicit_headers(self, httpbin): diff --git a/tests/test_httpie.py b/tests/test_httpie.py index 281dc35600..5824340cda 100644 --- a/tests/test_httpie.py +++ b/tests/test_httpie.py @@ -36,7 +36,7 @@ def test_debug(): def test_help(): r = http('--help', tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.SUCCESS - assert 'https://github.com/httpie/httpie/issues' in r + assert 'https://github.com/httpie/cli/issues' in r def test_version(): @@ -124,7 +124,7 @@ def test_POST_file(httpbin_both): def test_form_POST_file_redirected_stdin(httpbin): """ - + """ with open(FILE_PATH, encoding=UTF8): diff --git a/tests/test_output.py b/tests/test_output.py index 4e94797103..f85f38fa72 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -199,7 +199,7 @@ def test_verbose_raw(self, httpbin): assert 'foo bar' in r def test_verbose_form(self, httpbin): - # https://github.com/httpie/httpie/issues/53 + # https://github.com/httpie/cli/issues/53 r = http('--verbose', '--form', 'POST', httpbin.url + '/post', 'A=B', 'C=D') assert HTTP_OK in r diff --git a/tests/test_redirects.py b/tests/test_redirects.py index 81dcb2befd..a761fa2571 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -26,7 +26,7 @@ def test_follow_without_all_redirects_hidden(httpbin, follow_flag): assert HTTP_OK in r -@pytest.mark.xfail(True, reason="https://github.com/httpie/httpie/issues/1082") +@pytest.mark.xfail(True, reason="https://github.com/httpie/cli/issues/1082") def test_follow_output_options_used_for_redirects(httpbin): r = http('--follow', '--print=H', httpbin.url + '/redirect/2') assert r.count('GET /') == 1 diff --git a/tests/test_regressions.py b/tests/test_regressions.py index ddcf4acf06..07d60a583b 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -8,7 +8,7 @@ def test_Host_header_overwrite(httpbin): """ - https://github.com/httpie/httpie/issues/235 + https://github.com/httpie/cli/issues/235 """ host = 'pie.dev' @@ -22,7 +22,7 @@ def test_Host_header_overwrite(httpbin): @pytest.mark.skipif(is_windows, reason='Unix-only') def test_output_devnull(httpbin): """ - https://github.com/httpie/httpie/issues/252 + https://github.com/httpie/cli/issues/252 """ http('--output=/dev/null', httpbin + '/get') @@ -31,7 +31,7 @@ def test_output_devnull(httpbin): def test_verbose_redirected_stdout_separator(httpbin): """ - + """ r = http( '-v', diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 82a310e08d..6bece48932 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -203,7 +203,7 @@ def test_session_by_path(self, httpbin): def test_session_with_cookie_followed_by_another_header(self, httpbin): """ - Make sure headers don’t get mutated — + Make sure headers don’t get mutated — """ self.start_session(httpbin) session_data = { @@ -239,7 +239,7 @@ def test_session_unicode(self, httpbin): def test_session_default_header_value_overwritten(self, httpbin): self.start_session(httpbin) - # https://github.com/httpie/httpie/issues/180 + # https://github.com/httpie/cli/issues/180 r1 = http('--session=test', httpbin.url + '/headers', 'User-Agent:custom', env=self.env()) @@ -251,7 +251,7 @@ def test_session_default_header_value_overwritten(self, httpbin): assert r2.json['headers']['User-Agent'] == 'custom' def test_download_in_session(self, tmp_path, httpbin): - # https://github.com/httpie/httpie/issues/412 + # https://github.com/httpie/cli/issues/412 self.start_session(httpbin) cwd = os.getcwd() os.chdir(tmp_path) @@ -335,7 +335,7 @@ def get_auth(self, username=None, password=None): assert HTTP_OK in r1 assert HTTP_OK in r2 - # additional test for issue: https://github.com/httpie/httpie/issues/1098 + # additional test for issue: https://github.com/httpie/cli/issues/1098 with open(session_path) as session_file: session_file_lines = ''.join(session_file.readlines()) assert "\"type\": \"test-prompted\"" in session_file_lines @@ -427,7 +427,7 @@ def test_get_expired_cookies_using_max_age(self): ), ( # Checks we gracefully ignore expires date in invalid format. - # + # 'pfg=; Expires=Sat, 19-Sep-2020 06:58:14 GMT+0000; Max-Age=0; path=/; domain=.tumblr.com; secure; HttpOnly', None, [] diff --git a/tests/test_ssl.py b/tests/test_ssl.py index bf20a96da5..6fb983785a 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -15,7 +15,7 @@ try: # Handle OpenSSL errors, if installed. - # See + # See # noinspection PyUnresolvedReferences import OpenSSL.SSL ssl_errors = ( From 8aa654d1ef2b20a99918d3a446a8a8768e2722d4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 6 Aug 2023 14:15:10 +0200 Subject: [PATCH 1157/1182] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e8d1c33db1..42a81e3905 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ HTTPie
      - HTTPie for Terminal: human-friendly CLI HTTP client for the API era + HTTPie CLI: human-friendly HTTP client for the API era
      From e52a60e67ca15291c9ab18f395d4d7af3a6204ff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 6 Aug 2023 14:35:57 +0200 Subject: [PATCH 1158/1182] [automated] Update generated content (#1524) Co-authored-by: jakubroztocil --- extras/man/http.1 | 2 +- extras/man/https.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extras/man/http.1 b/extras/man/http.1 index 95e74740ad..65fa133ab0 100644 --- a/extras/man/http.1 +++ b/extras/man/http.1 @@ -597,4 +597,4 @@ For every \fB\,--OPTION\/\fR there is also a \fB\,--no-OPTION\/\fR that reverts to its default value. Suggestions and bug reports are greatly appreciated: -https://github.com/httpie/cli/issues +https://github.com/httpie/cli/issues \ No newline at end of file diff --git a/extras/man/https.1 b/extras/man/https.1 index 6db6828db6..c91290a245 100644 --- a/extras/man/https.1 +++ b/extras/man/https.1 @@ -597,4 +597,4 @@ For every \fB\,--OPTION\/\fR there is also a \fB\,--no-OPTION\/\fR that reverts to its default value. Suggestions and bug reports are greatly appreciated: -https://github.com/httpie/cli/issues +https://github.com/httpie/cli/issues \ No newline at end of file From 9e8e3691c8d40ca8dcdc90fbd9be12016eacdd56 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Tue, 24 Oct 2023 10:23:30 -0700 Subject: [PATCH 1159/1182] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 42a81e3905..5975abb817 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@
      -[![HTTPie for Desktop](https://img.shields.io/static/v1?label=HTTPie&message=for%20Desktop&color=4B78E6)](https://httpie.io/product) -[![](https://img.shields.io/static/v1?label=HTTPie&message=for%20Web%20%26%20Mobile&color=73DC8C)](https://httpie.io/app) -[![](https://img.shields.io/static/v1?label=HTTPie&message=for%20Terminal&color=FA9BFA)](https://httpie.io/cli) +[![HTTPie for Desktop](https://img.shields.io/static/v1?label=HTTPie&message=Desktop&color=4B78E6)](https://httpie.io/product) +[![](https://img.shields.io/static/v1?label=HTTPie&message=Web%20%26%20Mobile&color=73DC8C)](https://httpie.io/app) +[![](https://img.shields.io/static/v1?label=HTTPie&message=CLI&color=FA9BFA)](https://httpie.io/cli) [![Twitter](https://img.shields.io/twitter/follow/httpie?style=flat&color=%234B78E6&logoColor=%234B78E6)](https://twitter.com/httpie) [![Chat](https://img.shields.io/discord/725351238698270761?style=flat&label=Chat%20on%20Discord&color=%23FA9BFA)](https://httpie.io/discord) @@ -23,6 +23,7 @@ [![Latest version](https://img.shields.io/pypi/v/httpie.svg?style=flat&label=Latest&color=%234B78E6&logo=&logoColor=white)](https://pypi.python.org/pypi/httpie) [![Build](https://img.shields.io/github/actions/workflow/status/httpie/cli/tests.yml?branch=master&color=%23FA9BFA&label=Build)](https://github.com/httpie/cli/actions) [![Coverage](https://img.shields.io/codecov/c/github/httpie/cli?style=flat&label=Coverage&color=%2373DC8C)](https://codecov.io/gh/httpie/cli) +[![PyPi downloads](https://img.shields.io/pepy/dt/httpie?style=flat&label=Downloads%20from%20PyPi%20only&color=4B78E6)](https://www.pepy.tech/projects/httpie)
      From b934eec7fc60665ffcf2a147cb52188c3e98814a Mon Sep 17 00:00:00 2001 From: vostok92 <540339+vostok92@users.noreply.github.com> Date: Mon, 4 Mar 2024 23:34:57 +0900 Subject: [PATCH 1160/1182] Replace redirection with tee command with sudo for file creation (#1557) --- docs/installation/methods.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation/methods.yml b/docs/installation/methods.yml index 1cc09762b8..290b0e2436 100644 --- a/docs/installation/methods.yml +++ b/docs/installation/methods.yml @@ -39,7 +39,7 @@ tools: install: - curl -SsL https://packages.httpie.io/deb/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/httpie.gpg # - curl -SsL -o /etc/apt/sources.list.d/httpie.list https://packages.httpie.io/deb/httpie.list - - sudo echo "deb [arch=amd64 signed-by=/usr/share/keyrings/httpie.gpg] https://packages.httpie.io/deb ./" > /etc/apt/sources.list.d/httpie.list + - echo "deb [arch=amd64 signed-by=/usr/share/keyrings/httpie.gpg] https://packages.httpie.io/deb ./" | sudo tee /etc/apt/sources.list.d/httpie.list > /dev/null - sudo apt update - sudo apt install httpie upgrade: From a842a932cc3d838af1a6e6ba046d37f3155d7717 Mon Sep 17 00:00:00 2001 From: Matthieu LAURENT Date: Mon, 4 Mar 2024 15:35:32 +0100 Subject: [PATCH 1161/1182] docs: Update the url for offline mode (#1556) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5975abb817..13a3503b41 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ Custom [HTTP method](https://httpie.io/docs#http-method), [HTTP headers](https:/ http PUT pie.dev/put X-API-Token:123 name=John ``` -Build and print a request without sending it using [offline mode](https://httpie.io/docs#offline-mode): +Build and print a request without sending it using [offline mode](https://httpie.io/docs/cli/offline-mode): ```bash http --offline pie.dev/post hello=offline From 7a234d60dae84fc4b84d47483c205192acd60117 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 15:36:44 +0100 Subject: [PATCH 1162/1182] [automated] Update generated content (#1566) Co-authored-by: jkbrzt --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 3b12e98f4c..dd12490a24 100644 --- a/docs/README.md +++ b/docs/README.md @@ -133,7 +133,7 @@ Also works for other Debian-derived distributions like MX Linux, Linux Mint, dee ```bash # Install httpie $ curl -SsL https://packages.httpie.io/deb/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/httpie.gpg -$ sudo echo "deb [arch=amd64 signed-by=/usr/share/keyrings/httpie.gpg] https://packages.httpie.io/deb ./" > /etc/apt/sources.list.d/httpie.list +$ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/httpie.gpg] https://packages.httpie.io/deb ./" | sudo tee /etc/apt/sources.list.d/httpie.list > /dev/null $ sudo apt update $ sudo apt install httpie ``` From 2db28ef692163a00de4f65c65cbe1be6de8ff095 Mon Sep 17 00:00:00 2001 From: Aolin Date: Mon, 4 Mar 2024 22:37:15 +0800 Subject: [PATCH 1163/1182] docs: fix typo (#1548) --- docs/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/README.md b/docs/README.md index dd12490a24..65c7ebe4ed 100644 --- a/docs/README.md +++ b/docs/README.md @@ -477,7 +477,7 @@ $ http pie.dev/get text==@files/text.txt ### URL shortcuts for `localhost` Additionally, curl-like shorthand for localhost is supported. -This means that, for example, `:3000` would expand to `http://localhost:3000` +This means that, for example, `:3000` would expand to `http://localhost:3000`. If the port is omitted, then port 80 is assumed. ```bash @@ -530,7 +530,7 @@ $ http-unix %2Fvar%2Frun%2Fdocker.sock/info ### `--path-as-is` -The standard behavior of HTTP clients is to normalize the path portion of URLs by squashing dot segments as a typically filesystem would: +The standard behavior of HTTP clients is to normalize the path portion of URLs by squashing dot segments as a typical filesystem would: ```bash $ http -v example.org/./../../etc/password @@ -583,7 +583,7 @@ Note that the structured data fields aren’t the only way to specify request da ### File based separators Using file contents as values for specific fields is a very common use case, which can be achieved through adding the `@` suffix to -the operators above. For example instead of using a static string as the value for some header, you can use `:@` operator +the operators above. For example, instead of using a static string as the value for some header, you can use `:@` operator to pass the desired value from a file. ```bash @@ -749,7 +749,7 @@ $ http --offline --print=B pie.dev/post \ In the example above, the `search[type]` is an instruction for creating an object called `search`, and setting the `type` field of it to the given value (`"id"`). -Also note that, just as the regular syntax, you can use the `:=` operator to directly pass raw JSON values (e.g, numbers in the case above). +Also note that, just as the regular syntax, you can use the `:=` operator to directly pass raw JSON values (e.g., numbers in the case above). ```json { @@ -1235,7 +1235,7 @@ by individual commands when sending a request instead of being joined together. ### Limiting response headers -The `--max-headers=n` options allows you to control the number of headers HTTPie reads before giving up (the default `0`, i.e., there’s no limit). +The `--max-headers=n` option allows you to control the number of headers HTTPie reads before giving up (the default `0`, i.e., there’s no limit). ```bash $ http --max-headers=100 pie.dev/get From 8ac44b57ce0d4e8b8da574eb4391262c9c55b4e6 Mon Sep 17 00:00:00 2001 From: Aliaksei Urbanski Date: Mon, 4 Mar 2024 17:57:45 +0300 Subject: [PATCH 1164/1182] Ensure support for Python 3.11/3.12 (#1540) These changes: * enable testing for Python 3.11/3.12 on CI * update classifiers at setup.py --- .github/workflows/tests.yml | 10 ++++++++-- setup.py | 7 +++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8e35f4eead..0dbfae4edb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -25,11 +25,17 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: [3.7, 3.8, 3.9, "3.10"] + python-version: + - '3.12' + - '3.11' + - '3.10' + - '3.9' + - '3.8' + - '3.7' pyopenssl: [0, 1] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} diff --git a/setup.py b/setup.py index 93bdb8f957..7ebaaf58ca 100644 --- a/setup.py +++ b/setup.py @@ -96,6 +96,13 @@ def long_description(): 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', 'Programming Language :: Python :: 3 :: Only', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: Implementation :: CPython', 'Environment :: Console', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', From 3524ccf0baa9f2b3029368ab07ba5f64e62dcb1f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 4 Mar 2024 16:27:52 +0100 Subject: [PATCH 1165/1182] Drop dependency on the abandoned python-lazy-fixture --- setup.py | 1 - tests/conftest.py | 8 ++- tests/fixtures/pytest_lazy_fixture.py | 99 +++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 tests/fixtures/pytest_lazy_fixture.py diff --git a/setup.py b/setup.py index 7ebaaf58ca..21bdaf1658 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,6 @@ tests_require = [ 'pytest', 'pytest-httpbin>=0.0.6', - 'pytest-lazy-fixture>=0.0.6', 'responses', 'pytest-mock', 'werkzeug<2.1.0' diff --git a/tests/conftest.py b/tests/conftest.py index 7ca172a867..9430a32ed8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,14 +3,14 @@ import pytest from pytest_httpbin import certs -from .utils import ( # noqa +from .utils import ( # noqa HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN, HTTPBIN_WITH_CHUNKED_SUPPORT, REMOTE_HTTPBIN_DOMAIN, IS_PYOPENSSL, mock_env ) -from .utils.plugins_cli import ( # noqa +from .utils.plugins_cli import ( # noqa broken_plugin, dummy_plugin, dummy_plugins, @@ -18,7 +18,9 @@ httpie_plugins_success, interface, ) -from .utils.http_server import http_server, localhost_http_server # noqa +from .utils.http_server import http_server, localhost_http_server # noqa +# noinspection PyUnresolvedReferences +from .fixtures import pytest_lazy_fixture @pytest.fixture(scope='function', autouse=True) diff --git a/tests/fixtures/pytest_lazy_fixture.py b/tests/fixtures/pytest_lazy_fixture.py new file mode 100644 index 0000000000..5b70d8ec1f --- /dev/null +++ b/tests/fixtures/pytest_lazy_fixture.py @@ -0,0 +1,99 @@ +""" +Replacement for the abandoned `pytest.lazy_fixture` + +Based on + +""" +import dataclasses +import typing + +import pytest + + +@dataclasses.dataclass +class LazyFixture: + """Lazy fixture dataclass.""" + + name: str + + +def lazy_fixture(name: str) -> LazyFixture: + """Mark a fixture as lazy.""" + return LazyFixture(name) + + +# NOTE: Mimic the original API +pytest.lazy_fixture = lazy_fixture + + +def is_lazy_fixture(value: object) -> bool: + """Check whether a value is a lazy fixture.""" + return isinstance(value, LazyFixture) + + +def pytest_make_parametrize_id( + config: pytest.Config, + val: object, + argname: str, +) -> str | None: + """Inject lazy fixture parametrized id. + + Reference: + - https://bit.ly/48Off6r + + Args: + config (pytest.Config): pytest configuration. + value (object): fixture value. + argname (str): automatic parameter name. + + Returns: + str: new parameter id. + """ + if is_lazy_fixture(val): + return typing.cast(LazyFixture, val).name + return None + + +@pytest.hookimpl(tryfirst=True) +def pytest_fixture_setup( + fixturedef: pytest.FixtureDef, + request: pytest.FixtureRequest, +) -> object | None: + """Lazy fixture setup hook. + + This hook will never take over a fixture setup but just simply will + try to resolve recursively any lazy fixture found in request.param. + + Reference: + - https://bit.ly/3SyvsXJ + + Args: + fixturedef (pytest.FixtureDef): fixture definition object. + request (pytest.FixtureRequest): fixture request object. + + Returns: + object | None: fixture value or None otherwise. + """ + if hasattr(request, "param") and request.param: + request.param = _resolve_lazy_fixture(request.param, request) + return None + + +def _resolve_lazy_fixture(__val: object, request: pytest.FixtureRequest) -> object: + """Lazy fixture resolver. + + Args: + __val (object): fixture value object. + request (pytest.FixtureRequest): pytest fixture request object. + + Returns: + object: resolved fixture value. + """ + if isinstance(__val, list | tuple): + return tuple(_resolve_lazy_fixture(v, request) for v in __val) + if isinstance(__val, typing.Mapping): + return {k: _resolve_lazy_fixture(v, request) for k, v in __val.items()} + if not is_lazy_fixture(__val): + return __val + lazy_obj = typing.cast(LazyFixture, __val) + return request.getfixturevalue(lazy_obj.name) From db16bbee961ceb93b7831fe1ec44a72d56a33e38 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 4 Mar 2024 18:05:26 +0100 Subject: [PATCH 1166/1182] Drop dependency on the abandoned python-lazy-fixture II. --- tests/conftest.py | 16 +++- tests/fixtures/pytest_lazy_fixture.py | 99 ---------------------- tests/test_cookie_on_redirects.py | 113 ++++++++++++-------------- tests/test_sessions.py | 7 +- tests/test_update_warnings.py | 17 ++-- 5 files changed, 80 insertions(+), 172 deletions(-) delete mode 100644 tests/fixtures/pytest_lazy_fixture.py diff --git a/tests/conftest.py b/tests/conftest.py index 9430a32ed8..a42ccbb5b8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,7 @@ import pytest from pytest_httpbin import certs +from pytest_httpbin.serve import Server as PyTestHttpBinServer from .utils import ( # noqa HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN, @@ -19,8 +20,10 @@ interface, ) from .utils.http_server import http_server, localhost_http_server # noqa -# noinspection PyUnresolvedReferences -from .fixtures import pytest_lazy_fixture + + +# Patch to support `url = str(server)` in addition to `url = server + '/foo'`. +PyTestHttpBinServer.__str__ = lambda self: self.url @pytest.fixture(scope='function', autouse=True) @@ -72,8 +75,15 @@ def _remote_httpbin_available(): @pytest.fixture def remote_httpbin(_remote_httpbin_available): + if _remote_httpbin_available: - return 'http://' + REMOTE_HTTPBIN_DOMAIN + class Server(str): + """Look like `pytest_httpbin.serve.Server` but only provide URL info.""" + @property + def url(self): + return self + + return Server('http://' + REMOTE_HTTPBIN_DOMAIN) pytest.skip(f'{REMOTE_HTTPBIN_DOMAIN} not resolvable') diff --git a/tests/fixtures/pytest_lazy_fixture.py b/tests/fixtures/pytest_lazy_fixture.py deleted file mode 100644 index 5b70d8ec1f..0000000000 --- a/tests/fixtures/pytest_lazy_fixture.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -Replacement for the abandoned `pytest.lazy_fixture` - -Based on - -""" -import dataclasses -import typing - -import pytest - - -@dataclasses.dataclass -class LazyFixture: - """Lazy fixture dataclass.""" - - name: str - - -def lazy_fixture(name: str) -> LazyFixture: - """Mark a fixture as lazy.""" - return LazyFixture(name) - - -# NOTE: Mimic the original API -pytest.lazy_fixture = lazy_fixture - - -def is_lazy_fixture(value: object) -> bool: - """Check whether a value is a lazy fixture.""" - return isinstance(value, LazyFixture) - - -def pytest_make_parametrize_id( - config: pytest.Config, - val: object, - argname: str, -) -> str | None: - """Inject lazy fixture parametrized id. - - Reference: - - https://bit.ly/48Off6r - - Args: - config (pytest.Config): pytest configuration. - value (object): fixture value. - argname (str): automatic parameter name. - - Returns: - str: new parameter id. - """ - if is_lazy_fixture(val): - return typing.cast(LazyFixture, val).name - return None - - -@pytest.hookimpl(tryfirst=True) -def pytest_fixture_setup( - fixturedef: pytest.FixtureDef, - request: pytest.FixtureRequest, -) -> object | None: - """Lazy fixture setup hook. - - This hook will never take over a fixture setup but just simply will - try to resolve recursively any lazy fixture found in request.param. - - Reference: - - https://bit.ly/3SyvsXJ - - Args: - fixturedef (pytest.FixtureDef): fixture definition object. - request (pytest.FixtureRequest): fixture request object. - - Returns: - object | None: fixture value or None otherwise. - """ - if hasattr(request, "param") and request.param: - request.param = _resolve_lazy_fixture(request.param, request) - return None - - -def _resolve_lazy_fixture(__val: object, request: pytest.FixtureRequest) -> object: - """Lazy fixture resolver. - - Args: - __val (object): fixture value object. - request (pytest.FixtureRequest): pytest fixture request object. - - Returns: - object: resolved fixture value. - """ - if isinstance(__val, list | tuple): - return tuple(_resolve_lazy_fixture(v, request) for v in __val) - if isinstance(__val, typing.Mapping): - return {k: _resolve_lazy_fixture(v, request) for k, v in __val.items()} - if not is_lazy_fixture(__val): - return __val - lazy_obj = typing.cast(LazyFixture, __val) - return request.getfixturevalue(lazy_obj.name) diff --git a/tests/test_cookie_on_redirects.py b/tests/test_cookie_on_redirects.py index 23d8324fe1..c5842f5b46 100644 --- a/tests/test_cookie_on_redirects.py +++ b/tests/test_cookie_on_redirects.py @@ -2,54 +2,47 @@ from .utils import http -def _stringify(fixture): - return fixture + '' - - -@pytest.mark.parametrize('instance', [ - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), +@pytest.mark.parametrize('target_httpbin', [ + 'httpbin', + 'remote_httpbin', ]) -def test_explicit_user_set_cookie(httpbin, instance): - # User set cookies ARE NOT persisted within redirects - # when there is no session, even on the same domain. - +def test_explicit_user_set_cookie(httpbin, target_httpbin, request): + """User set cookies ARE NOT persisted within redirects when there is no session, even on the same domain.""" + target_httpbin = request.getfixturevalue(target_httpbin) r = http( '--follow', httpbin + '/redirect-to', - f'url=={_stringify(instance)}/cookies', + f'url=={target_httpbin.url}/cookies', 'Cookie:a=b' ) assert r.json == {'cookies': {}} -@pytest.mark.parametrize('instance', [ - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), +@pytest.mark.parametrize('target_httpbin', [ + 'httpbin', + 'remote_httpbin', ]) -def test_explicit_user_set_cookie_in_session(tmp_path, httpbin, instance): - # User set cookies ARE persisted within redirects - # when there is A session, even on the same domain. - +def test_explicit_user_set_cookie_in_session(tmp_path, httpbin, target_httpbin, request): + """User set cookies ARE persisted within redirects when there is A session, even on the same domain.""" + target_httpbin = request.getfixturevalue(target_httpbin) r = http( '--follow', '--session', str(tmp_path / 'session.json'), httpbin + '/redirect-to', - f'url=={_stringify(instance)}/cookies', + f'url=={target_httpbin}/cookies', 'Cookie:a=b' ) assert r.json == {'cookies': {'a': 'b'}} -@pytest.mark.parametrize('instance', [ - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), +@pytest.mark.parametrize('target_httpbin', [ + 'httpbin', + 'remote_httpbin', ]) -def test_saved_user_set_cookie_in_session(tmp_path, httpbin, instance): - # User set cookies ARE persisted within redirects - # when there is A session, even on the same domain. - +def test_saved_user_set_cookie_in_session(tmp_path, httpbin, target_httpbin, request): + """User set cookies ARE persisted within redirects when there is A session, even on the same domain.""" + target_httpbin = request.getfixturevalue(target_httpbin) http( '--follow', '--session', @@ -62,32 +55,33 @@ def test_saved_user_set_cookie_in_session(tmp_path, httpbin, instance): '--session', str(tmp_path / 'session.json'), httpbin + '/redirect-to', - f'url=={_stringify(instance)}/cookies', + f'url=={target_httpbin}/cookies', ) assert r.json == {'cookies': {'a': 'b'}} -@pytest.mark.parametrize('instance', [ - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), +@pytest.mark.parametrize('target_httpbin', [ + 'httpbin', + 'remote_httpbin', ]) @pytest.mark.parametrize('session', [True, False]) -def test_explicit_user_set_headers(httpbin, tmp_path, instance, session): - # User set headers ARE persisted within redirects - # even on different domains domain with or without - # an active session. +def test_explicit_user_set_headers(httpbin, tmp_path, target_httpbin, session, request): + """ + User set headers ARE persisted within redirects even on different domains domain with or without an active session. + + """ + target_httpbin = request.getfixturevalue(target_httpbin) session_args = [] if session: session_args.extend([ '--session', str(tmp_path / 'session.json') ]) - r = http( '--follow', *session_args, httpbin + '/redirect-to', - f'url=={_stringify(instance)}/get', + f'url=={target_httpbin}/get', 'X-Custom-Header:value' ) assert 'X-Custom-Header' in r.json['headers'] @@ -95,16 +89,13 @@ def test_explicit_user_set_headers(httpbin, tmp_path, instance, session): @pytest.mark.parametrize('session', [True, False]) def test_server_set_cookie_on_redirect_same_domain(tmp_path, httpbin, session): - # Server set cookies ARE persisted on the same domain - # when they are forwarded. - + """Server set cookies ARE persisted on the same domain when they are forwarded.""" session_args = [] if session: session_args.extend([ '--session', str(tmp_path / 'session.json') ]) - r = http( '--follow', *session_args, @@ -136,8 +127,7 @@ def test_server_set_cookie_on_redirect_different_domain(tmp_path, http_server, h def test_saved_session_cookies_on_same_domain(tmp_path, httpbin): - # Saved session cookies ARE persisted when making a new - # request to the same domain. + """Saved session cookies ARE persisted when making a new request to the same domain.""" http( '--session', str(tmp_path / 'session.json'), @@ -152,8 +142,7 @@ def test_saved_session_cookies_on_same_domain(tmp_path, httpbin): def test_saved_session_cookies_on_different_domain(tmp_path, httpbin, remote_httpbin): - # Saved session cookies ARE persisted when making a new - # request to a different domain. + """Saved session cookies ARE persisted when making a new request to a different domain.""" http( '--session', str(tmp_path / 'session.json'), @@ -167,45 +156,49 @@ def test_saved_session_cookies_on_different_domain(tmp_path, httpbin, remote_htt assert r.json == {'cookies': {}} -@pytest.mark.parametrize('initial_domain, first_request_domain, second_request_domain, expect_cookies', [ +@pytest.mark.parametrize(['initial_domain', 'first_request_domain', 'second_request_domain', 'expect_cookies'], [ ( # Cookies are set by Domain A # Initial domain is Domain A # Redirected domain is Domain A - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('httpbin'), + 'httpbin', + 'httpbin', + 'httpbin', True, ), ( # Cookies are set by Domain A # Initial domain is Domain B # Redirected domain is Domain B - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), - pytest.lazy_fixture('remote_httpbin'), + 'httpbin', + 'remote_httpbin', + 'remote_httpbin', False, ), ( # Cookies are set by Domain A # Initial domain is Domain A # Redirected domain is Domain B - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), + 'httpbin', + 'httpbin', + 'remote_httpbin', False, ), ( # Cookies are set by Domain A # Initial domain is Domain B # Redirected domain is Domain A - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), - pytest.lazy_fixture('httpbin'), + 'httpbin', + 'remote_httpbin', + 'httpbin', True, ), ]) -def test_saved_session_cookies_on_redirect(tmp_path, initial_domain, first_request_domain, second_request_domain, expect_cookies): +def test_saved_session_cookies_on_redirect( + tmp_path, initial_domain, first_request_domain, second_request_domain, expect_cookies, request): + initial_domain = request.getfixturevalue(initial_domain) + first_request_domain = request.getfixturevalue(first_request_domain) + second_request_domain = request.getfixturevalue(second_request_domain) http( '--session', str(tmp_path / 'session.json'), @@ -216,7 +209,7 @@ def test_saved_session_cookies_on_redirect(tmp_path, initial_domain, first_reque str(tmp_path / 'session.json'), '--follow', first_request_domain + '/redirect-to', - f'url=={_stringify(second_request_domain)}/cookies' + f'url=={second_request_domain}/cookies' ) if expect_cookies: expected_data = {'cookies': {'a': 'b'}} diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 6bece48932..6c2c6f0ec2 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -821,16 +821,17 @@ def test_session_multiple_headers_with_same_name(basic_session, httpbin): 'server, expected_cookies', [ ( - pytest.lazy_fixture('localhost_http_server'), + 'localhost_http_server', {'secure_cookie': 'foo', 'insecure_cookie': 'bar'} ), ( - pytest.lazy_fixture('remote_httpbin'), + 'remote_httpbin', {'insecure_cookie': 'bar'} ) ] ) -def test_secure_cookies_on_localhost(mock_env, tmp_path, server, expected_cookies): +def test_secure_cookies_on_localhost(mock_env, tmp_path, server, expected_cookies, request): + server = request.getfixturevalue(server) session_path = tmp_path / 'session.json' http( '--session', str(session_path), diff --git a/tests/test_update_warnings.py b/tests/test_update_warnings.py index b2c24c36de..e794162649 100644 --- a/tests/test_update_warnings.py +++ b/tests/test_update_warnings.py @@ -132,10 +132,10 @@ def test_check_updates_first_invocation( @pytest.mark.parametrize( - 'should_issue_warning, build_channel', + ['should_issue_warning', 'build_channel'], [ - (False, pytest.lazy_fixture('lower_build_channel')), - (True, pytest.lazy_fixture('higher_build_channel')), + (False, 'lower_build_channel'), + (True, 'higher_build_channel'), ], ) def test_check_updates_first_time_after_data_fetch( @@ -145,7 +145,9 @@ def test_check_updates_first_time_after_data_fetch( static_fetch_data, should_issue_warning, build_channel, + request, ): + request.getfixturevalue(build_channel) http('fetch_updates', '--daemon', env=with_warnings) r = http(httpbin + '/get', env=with_warnings) @@ -176,14 +178,15 @@ def test_cli_check_updates( @pytest.mark.parametrize( - "build_channel", [ - pytest.lazy_fixture("lower_build_channel"), - pytest.lazy_fixture("unknown_build_channel") + 'build_channel', [ + 'lower_build_channel', + 'unknown_build_channel', ] ) def test_cli_check_updates_not_shown( - static_fetch_data, build_channel + static_fetch_data, build_channel, request ): + request.getfixturevalue(build_channel) r = httpie('cli', 'check-updates') assert r.exit_status == ExitStatus.SUCCESS assert not check_update_warnings(r) From 3de7c82077ab773ca957c851e94c4b375721feb6 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 4 Mar 2024 18:12:18 +0100 Subject: [PATCH 1167/1182] Cleanup --- tests/conftest.py | 9 +----- tests/test_auth.py | 2 +- tests/test_binary.py | 6 ++-- tests/test_cli.py | 20 ++++++------- tests/test_compress.py | 4 +-- tests/test_config.py | 4 +-- tests/test_cookie_on_redirects.py | 2 +- tests/test_defaults.py | 34 ++++++++++----------- tests/test_downloads.py | 2 +- tests/test_encoding.py | 32 ++++++++++---------- tests/test_exit_status.py | 18 +++++------ tests/test_output.py | 38 +++++++++++------------ tests/test_redirects.py | 20 ++++++------- tests/test_regressions.py | 4 +-- tests/test_sessions.py | 50 +++++++++++++++---------------- tests/test_stream.py | 8 ++--- tests/test_uploads.py | 28 ++++++++--------- tests/test_windows.py | 4 +-- tests/utils/__init__.py | 2 +- 19 files changed, 140 insertions(+), 147 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index a42ccbb5b8..551a636789 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -75,15 +75,8 @@ def _remote_httpbin_available(): @pytest.fixture def remote_httpbin(_remote_httpbin_available): - if _remote_httpbin_available: - class Server(str): - """Look like `pytest_httpbin.serve.Server` but only provide URL info.""" - @property - def url(self): - return self - - return Server('http://' + REMOTE_HTTPBIN_DOMAIN) + return 'http://' + REMOTE_HTTPBIN_DOMAIN pytest.skip(f'{REMOTE_HTTPBIN_DOMAIN} not resolvable') diff --git a/tests/test_auth.py b/tests/test_auth.py index 696fb22826..83423efec0 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -42,7 +42,7 @@ def test_bearer_auth(httpbin_both, token): new=lambda self, prompt: 'password') def test_password_prompt(httpbin): r = http('--auth', 'user', - 'GET', httpbin.url + '/basic-auth/user/password') + 'GET', httpbin + '/basic-auth/user/password') assert HTTP_OK in r assert r.json == {'authenticated': True, 'user': 'user'} diff --git a/tests/test_binary.py b/tests/test_binary.py index ca51aa1686..c5e63ec30e 100644 --- a/tests/test_binary.py +++ b/tests/test_binary.py @@ -15,18 +15,18 @@ def test_binary_stdin(self, httpbin): stdin_isatty=False, stdout_isatty=False ) - r = http('--print=B', 'POST', httpbin.url + '/post', env=env) + r = http('--print=B', 'POST', httpbin + '/post', env=env) assert r == BIN_FILE_CONTENT def test_binary_file_path(self, httpbin): env = MockEnvironment(stdin_isatty=True, stdout_isatty=False) - r = http('--print=B', 'POST', httpbin.url + '/post', + r = http('--print=B', 'POST', httpbin + '/post', '@' + BIN_FILE_PATH_ARG, env=env) assert r == BIN_FILE_CONTENT def test_binary_file_form(self, httpbin): env = MockEnvironment(stdin_isatty=True, stdout_isatty=False) - r = http('--print=B', '--form', 'POST', httpbin.url + '/post', + r = http('--print=B', '--form', 'POST', httpbin + '/post', 'test@' + BIN_FILE_PATH_ARG, env=env) assert bytes(BIN_FILE_CONTENT) in bytes(r) diff --git a/tests/test_cli.py b/tests/test_cli.py index 6504c8a980..2cd27574af 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -151,17 +151,17 @@ def test_multiple_text_fields_with_same_field_name(self): class TestQuerystring: def test_query_string_params_in_url(self, httpbin): - r = http('--print=Hhb', 'GET', httpbin.url + '/get?a=1&b=2') + r = http('--print=Hhb', 'GET', httpbin + '/get?a=1&b=2') path = '/get?a=1&b=2' - url = httpbin.url + path + url = httpbin + path assert HTTP_OK in r assert f'GET {path} HTTP/1.1' in r assert f'"url": "{url}"' in r def test_query_string_params_items(self, httpbin): - r = http('--print=Hhb', 'GET', httpbin.url + '/get', 'a==1') + r = http('--print=Hhb', 'GET', httpbin + '/get', 'a==1') path = '/get?a=1' - url = httpbin.url + path + url = httpbin + path assert HTTP_OK in r assert f'GET {path} HTTP/1.1' in r assert f'"url": "{url}"' in r @@ -169,9 +169,9 @@ def test_query_string_params_items(self, httpbin): def test_query_string_params_in_url_and_items_with_duplicates(self, httpbin): r = http('--print=Hhb', 'GET', - httpbin.url + '/get?a=1&a=1', 'a==1', 'a==1') + httpbin + '/get?a=1&a=1', 'a==1', 'a==1') path = '/get?a=1&a=1&a=1&a=1' - url = httpbin.url + path + url = httpbin + path assert HTTP_OK in r assert f'GET {path} HTTP/1.1' in r assert f'"url": "{url}"' in r @@ -320,11 +320,11 @@ def test_guess_when_method_set_but_invalid_and_item_exists(self): class TestNoOptions: def test_valid_no_options(self, httpbin): - r = http('--verbose', '--no-verbose', 'GET', httpbin.url + '/get') + r = http('--verbose', '--no-verbose', 'GET', httpbin + '/get') assert 'GET /get HTTP/1.1' not in r def test_invalid_no_options(self, httpbin): - r = http('--no-war', 'GET', httpbin.url + '/get', + r = http('--no-war', 'GET', httpbin + '/get', tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR assert 'unrecognized arguments: --no-war' in r.stderr @@ -338,13 +338,13 @@ def test_ignore_stdin(self, httpbin): stdin=StdinBytesIO(FILE_PATH.read_bytes()), stdin_isatty=False, ) - r = http('--ignore-stdin', '--verbose', httpbin.url + '/get', env=env) + r = http('--ignore-stdin', '--verbose', httpbin + '/get', env=env) assert HTTP_OK in r assert 'GET /get HTTP' in r, "Don't default to POST." assert FILE_CONTENT not in r, "Don't send stdin data." def test_ignore_stdin_cannot_prompt_password(self, httpbin): - r = http('--ignore-stdin', '--auth=no-password', httpbin.url + '/get', + r = http('--ignore-stdin', '--auth=no-password', httpbin + '/get', tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR assert 'because --ignore-stdin' in r.stderr diff --git a/tests/test_compress.py b/tests/test_compress.py index 854a23e26e..de5d8a7c48 100644 --- a/tests/test_compress.py +++ b/tests/test_compress.py @@ -29,14 +29,14 @@ def assert_decompressed_equal(base64_compressed_data, expected_str): def test_cannot_combine_compress_with_chunked(httpbin): - r = http('--compress', '--chunked', httpbin.url + '/get', + r = http('--compress', '--chunked', httpbin + '/get', tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR assert 'cannot combine --compress and --chunked' in r.stderr def test_cannot_combine_compress_with_multipart(httpbin): - r = http('--compress', '--multipart', httpbin.url + '/get', + r = http('--compress', '--multipart', httpbin + '/get', tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR assert 'cannot combine --compress and --multipart' in r.stderr diff --git a/tests/test_config.py b/tests/test_config.py index be19d572e4..1d2eea0750 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -17,7 +17,7 @@ def test_default_options(httpbin): env = MockEnvironment() env.config['default_options'] = ['--form'] env.config.save() - r = http(httpbin.url + '/post', 'foo=bar', env=env) + r = http(httpbin + '/post', 'foo=bar', env=env) assert r.json['form'] == { "foo": "bar" } @@ -51,7 +51,7 @@ def test_default_options_overwrite(httpbin): env = MockEnvironment() env.config['default_options'] = ['--form'] env.config.save() - r = http('--json', httpbin.url + '/post', 'foo=bar', env=env) + r = http('--json', httpbin + '/post', 'foo=bar', env=env) assert r.json['json'] == { "foo": "bar" } diff --git a/tests/test_cookie_on_redirects.py b/tests/test_cookie_on_redirects.py index c5842f5b46..2b0ab73b4a 100644 --- a/tests/test_cookie_on_redirects.py +++ b/tests/test_cookie_on_redirects.py @@ -12,7 +12,7 @@ def test_explicit_user_set_cookie(httpbin, target_httpbin, request): r = http( '--follow', httpbin + '/redirect-to', - f'url=={target_httpbin.url}/cookies', + f'url=={target_httpbin}/cookies', 'Cookie:a=b' ) assert r.json == {'cookies': {}} diff --git a/tests/test_defaults.py b/tests/test_defaults.py index 267be2ae8d..dc91211649 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -16,7 +16,7 @@ def test_default_headers_case_insensitive(httpbin): r = http( '--debug', '--print=H', - httpbin.url + '/post', + httpbin + '/post', 'CONTENT-TYPE:application/json-patch+json', 'a=b', ) @@ -27,26 +27,26 @@ def test_default_headers_case_insensitive(httpbin): # noinspection PyPep8Naming class TestImplicitHTTPMethod: def test_implicit_GET(self, httpbin): - r = http(httpbin.url + '/get') + r = http(httpbin + '/get') assert HTTP_OK in r def test_implicit_GET_with_headers(self, httpbin): - r = http(httpbin.url + '/headers', 'Foo:bar') + r = http(httpbin + '/headers', 'Foo:bar') assert HTTP_OK in r assert r.json['headers']['Foo'] == 'bar' def test_implicit_POST_json(self, httpbin): - r = http(httpbin.url + '/post', 'hello=world') + r = http(httpbin + '/post', 'hello=world') assert HTTP_OK in r assert r.json['json'] == {'hello': 'world'} def test_implicit_POST_form(self, httpbin): - r = http('--form', httpbin.url + '/post', 'foo=bar') + r = http('--form', httpbin + '/post', 'foo=bar') assert HTTP_OK in r assert r.json['form'] == {'foo': 'bar'} def test_implicit_POST_raw(self, httpbin): - r = http('--raw', 'foo bar', httpbin.url + '/post') + r = http('--raw', 'foo bar', httpbin + '/post') assert HTTP_OK in r assert r.json['data'] == 'foo bar' @@ -55,7 +55,7 @@ def test_implicit_POST_stdin(self, httpbin): stdin_isatty=False, stdin=BytesIO(FILE_PATH.read_bytes()) ) - r = http('--form', httpbin.url + '/post', env=env) + r = http('--form', httpbin + '/post', env=env) assert HTTP_OK in r @@ -69,33 +69,33 @@ class TestAutoContentTypeAndAcceptHeaders: def test_GET_no_data_no_auto_headers(self, httpbin): # https://github.com/httpie/cli/issues/62 - r = http('GET', httpbin.url + '/headers') + r = http('GET', httpbin + '/headers') assert HTTP_OK in r assert r.json['headers']['Accept'] == '*/*' assert 'Content-Type' not in r.json['headers'] def test_POST_no_data_no_auto_headers(self, httpbin): # JSON headers shouldn't be automatically set for POST with no data. - r = http('POST', httpbin.url + '/post') + r = http('POST', httpbin + '/post') assert HTTP_OK in r assert '"Accept": "*/*"' in r assert '"Content-Type": "application/json' not in r def test_POST_with_data_auto_JSON_headers(self, httpbin): - r = http('POST', httpbin.url + '/post', 'a=b') + r = http('POST', httpbin + '/post', 'a=b') assert HTTP_OK in r assert r.json['headers']['Accept'] == JSON_ACCEPT assert r.json['headers']['Content-Type'] == 'application/json' def test_GET_with_data_auto_JSON_headers(self, httpbin): # JSON headers should automatically be set also for GET with data. - r = http('POST', httpbin.url + '/post', 'a=b') + r = http('POST', httpbin + '/post', 'a=b') assert HTTP_OK in r assert r.json['headers']['Accept'] == JSON_ACCEPT assert r.json['headers']['Content-Type'] == 'application/json' def test_POST_explicit_JSON_JSON_ACCEPT(self, httpbin): - r = http('--json', 'POST', httpbin.url + '/post') + r = http('--json', 'POST', httpbin + '/post') assert HTTP_OK in r assert r.json['headers']['Accept'] == JSON_ACCEPT # Make sure Content-Type gets set even with no data. @@ -103,7 +103,7 @@ def test_POST_explicit_JSON_JSON_ACCEPT(self, httpbin): assert 'application/json' in r.json['headers']['Content-Type'] def test_GET_explicit_JSON_explicit_headers(self, httpbin): - r = http('--json', 'GET', httpbin.url + '/headers', + r = http('--json', 'GET', httpbin + '/headers', 'Accept:application/xml', 'Content-Type:application/xml') assert HTTP_OK in r @@ -111,22 +111,22 @@ def test_GET_explicit_JSON_explicit_headers(self, httpbin): assert '"Content-Type": "application/xml"' in r def test_POST_form_auto_Content_Type(self, httpbin): - r = http('--form', 'POST', httpbin.url + '/post') + r = http('--form', 'POST', httpbin + '/post') assert HTTP_OK in r assert '"Content-Type": "application/x-www-form-urlencoded' in r def test_POST_form_Content_Type_override(self, httpbin): - r = http('--form', 'POST', httpbin.url + '/post', + r = http('--form', 'POST', httpbin + '/post', 'Content-Type:application/xml') assert HTTP_OK in r assert '"Content-Type": "application/xml"' in r def test_print_only_body_when_stdout_redirected_by_default(self, httpbin): env = MockEnvironment(stdin_isatty=True, stdout_isatty=False) - r = http('GET', httpbin.url + '/get', env=env) + r = http('GET', httpbin + '/get', env=env) assert 'HTTP/' not in r def test_print_overridable_when_stdout_redirected(self, httpbin): env = MockEnvironment(stdin_isatty=True, stdout_isatty=False) - r = http('--print=h', 'GET', httpbin.url + '/get', env=env) + r = http('--print=h', 'GET', httpbin + '/get', env=env) assert HTTP_OK in r diff --git a/tests/test_downloads.py b/tests/test_downloads.py index d6e98867bc..b646a0e6a5 100644 --- a/tests/test_downloads.py +++ b/tests/test_downloads.py @@ -255,7 +255,7 @@ def test_download_with_redirect_original_url_used_for_filename(self, httpbin): os.chdir(tmp_dirname) try: assert os.listdir('.') == [] - http('--download', httpbin.url + '/redirect/1') + http('--download', httpbin + '/redirect/1') assert os.listdir('.') == [expected_filename] finally: os.chdir(orig_cwd) diff --git a/tests/test_encoding.py b/tests/test_encoding.py index e9f50dc9bb..62814161ed 100644 --- a/tests/test_encoding.py +++ b/tests/test_encoding.py @@ -31,90 +31,90 @@ def test_charset_text_pairs(): def test_unicode_headers(httpbin): # httpbin doesn't interpret UFT-8 headers - r = http(httpbin.url + '/headers', f'Test:{UNICODE}') + r = http(httpbin + '/headers', f'Test:{UNICODE}') assert HTTP_OK in r def test_unicode_headers_verbose(httpbin): # httpbin doesn't interpret UTF-8 headers - r = http('--verbose', httpbin.url + '/headers', f'Test:{UNICODE}') + r = http('--verbose', httpbin + '/headers', f'Test:{UNICODE}') assert HTTP_OK in r assert UNICODE in r def test_unicode_raw(httpbin): - r = http('--raw', f'test {UNICODE}', 'POST', httpbin.url + '/post') + r = http('--raw', f'test {UNICODE}', 'POST', httpbin + '/post') assert HTTP_OK in r assert r.json['data'] == f'test {UNICODE}' def test_unicode_raw_verbose(httpbin): r = http('--verbose', '--raw', f'test {UNICODE}', - 'POST', httpbin.url + '/post') + 'POST', httpbin + '/post') assert HTTP_OK in r assert UNICODE in r def test_unicode_form_item(httpbin): - r = http('--form', 'POST', httpbin.url + '/post', f'test={UNICODE}') + r = http('--form', 'POST', httpbin + '/post', f'test={UNICODE}') assert HTTP_OK in r assert r.json['form'] == {'test': UNICODE} def test_unicode_form_item_verbose(httpbin): r = http('--verbose', '--form', - 'POST', httpbin.url + '/post', f'test={UNICODE}') + 'POST', httpbin + '/post', f'test={UNICODE}') assert HTTP_OK in r assert UNICODE in r def test_unicode_json_item(httpbin): - r = http('--json', 'POST', httpbin.url + '/post', f'test={UNICODE}') + r = http('--json', 'POST', httpbin + '/post', f'test={UNICODE}') assert HTTP_OK in r assert r.json['json'] == {'test': UNICODE} def test_unicode_json_item_verbose(httpbin): r = http('--verbose', '--json', - 'POST', httpbin.url + '/post', f'test={UNICODE}') + 'POST', httpbin + '/post', f'test={UNICODE}') assert HTTP_OK in r assert UNICODE in r def test_unicode_raw_json_item(httpbin): - r = http('--json', 'POST', httpbin.url + '/post', + r = http('--json', 'POST', httpbin + '/post', f'test:={{ "{UNICODE}" : [ "{UNICODE}" ] }}') assert HTTP_OK in r assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} def test_unicode_raw_json_item_verbose(httpbin): - r = http('--json', 'POST', httpbin.url + '/post', + r = http('--json', 'POST', httpbin + '/post', f'test:={{ "{UNICODE}" : [ "{UNICODE}" ] }}') assert HTTP_OK in r assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} def test_unicode_url_query_arg_item(httpbin): - r = http(httpbin.url + '/get', f'test=={UNICODE}') + r = http(httpbin + '/get', f'test=={UNICODE}') assert HTTP_OK in r assert r.json['args'] == {'test': UNICODE}, r def test_unicode_url_query_arg_item_verbose(httpbin): - r = http('--verbose', httpbin.url + '/get', f'test=={UNICODE}') + r = http('--verbose', httpbin + '/get', f'test=={UNICODE}') assert HTTP_OK in r assert UNICODE in r def test_unicode_url(httpbin): - r = http(f'{httpbin.url}/get?test={UNICODE}') + r = http(f'{httpbin}/get?test={UNICODE}') assert HTTP_OK in r assert r.json['args'] == {'test': UNICODE} def test_unicode_url_verbose(httpbin): - r = http('--verbose', f'{httpbin.url}/get?test={UNICODE}') + r = http('--verbose', f'{httpbin}/get?test={UNICODE}') assert HTTP_OK in r assert r.json['args'] == {'test': UNICODE} @@ -123,7 +123,7 @@ def test_unicode_basic_auth(httpbin): # it doesn't really authenticate us because httpbin # doesn't interpret the UTF-8-encoded auth http('--verbose', '--auth', f'test:{UNICODE}', - f'{httpbin.url}/basic-auth/test/{UNICODE}') + f'{httpbin}/basic-auth/test/{UNICODE}') def test_unicode_digest_auth(httpbin): @@ -131,7 +131,7 @@ def test_unicode_digest_auth(httpbin): # doesn't interpret the UTF-8-encoded auth http('--auth-type=digest', '--auth', f'test:{UNICODE}', - f'{httpbin.url}/digest-auth/auth/test/{UNICODE}') + f'{httpbin}/digest-auth/auth/test/{UNICODE}') @pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) diff --git a/tests/test_exit_status.py b/tests/test_exit_status.py index 4438d3485c..02fd2f1fe5 100644 --- a/tests/test_exit_status.py +++ b/tests/test_exit_status.py @@ -7,25 +7,25 @@ def test_keyboard_interrupt_during_arg_parsing_exit_status(httpbin): with mock.patch('httpie.cli.definition.parser.parse_args', side_effect=KeyboardInterrupt()): - r = http('GET', httpbin.url + '/get', tolerate_error_exit_status=True) + r = http('GET', httpbin + '/get', tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR_CTRL_C def test_keyboard_interrupt_in_program_exit_status(httpbin): with mock.patch('httpie.core.program', side_effect=KeyboardInterrupt()): - r = http('GET', httpbin.url + '/get', tolerate_error_exit_status=True) + r = http('GET', httpbin + '/get', tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR_CTRL_C def test_ok_response_exits_0(httpbin): - r = http('GET', httpbin.url + '/get') + r = http('GET', httpbin + '/get') assert HTTP_OK in r assert r.exit_status == ExitStatus.SUCCESS def test_error_response_exits_0_without_check_status(httpbin): - r = http('GET', httpbin.url + '/status/500') + r = http('GET', httpbin + '/status/500') assert '500 INTERNAL SERVER ERROR' in r assert r.exit_status == ExitStatus.SUCCESS assert not r.stderr @@ -33,7 +33,7 @@ def test_error_response_exits_0_without_check_status(httpbin): def test_timeout_exit_status(httpbin): - r = http('--timeout=0.01', 'GET', httpbin.url + '/delay/0.5', + r = http('--timeout=0.01', 'GET', httpbin + '/delay/0.5', tolerate_error_exit_status=True) assert r.exit_status == ExitStatus.ERROR_TIMEOUT @@ -42,7 +42,7 @@ def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected( httpbin): env = MockEnvironment(stdout_isatty=False) r = http('--check-status', '--headers', - 'GET', httpbin.url + '/status/301', + 'GET', httpbin + '/status/301', env=env, tolerate_error_exit_status=True) assert '301 MOVED PERMANENTLY' in r assert r.exit_status == ExitStatus.ERROR_HTTP_3XX @@ -51,7 +51,7 @@ def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected( def test_3xx_check_status_redirects_allowed_exits_0(httpbin): r = http('--check-status', '--follow', - 'GET', httpbin.url + '/status/301', + 'GET', httpbin + '/status/301', tolerate_error_exit_status=True) # The redirect will be followed so 200 is expected. assert HTTP_OK in r @@ -59,7 +59,7 @@ def test_3xx_check_status_redirects_allowed_exits_0(httpbin): def test_4xx_check_status_exits_4(httpbin): - r = http('--check-status', 'GET', httpbin.url + '/status/401', + r = http('--check-status', 'GET', httpbin + '/status/401', tolerate_error_exit_status=True) assert '401 UNAUTHORIZED' in r assert r.exit_status == ExitStatus.ERROR_HTTP_4XX @@ -68,7 +68,7 @@ def test_4xx_check_status_exits_4(httpbin): def test_5xx_check_status_exits_5(httpbin): - r = http('--check-status', 'GET', httpbin.url + '/status/500', + r = http('--check-status', 'GET', httpbin + '/status/500', tolerate_error_exit_status=True) assert '500 INTERNAL SERVER ERROR' in r assert r.exit_status == ExitStatus.ERROR_HTTP_5XX diff --git a/tests/test_output.py b/tests/test_output.py index f85f38fa72..2242177dbc 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -54,7 +54,7 @@ def test_quiet(self, httpbin, quiet_flags): stdout_isatty=True, devnull=io.BytesIO() ) - r = http(*quiet_flags, 'GET', httpbin.url + '/get', env=env) + r = http(*quiet_flags, 'GET', httpbin + '/get', env=env) assert env.stdout is env.devnull assert env.stderr is env.devnull assert HTTP_OK in r.devnull @@ -134,7 +134,7 @@ def test_quiet_with_password_prompt(self, httpbin, quiet_flags): ) r = http( *quiet_flags, '--auth', 'user', 'GET', - httpbin.url + '/basic-auth/user/password', + httpbin + '/basic-auth/user/password', env=env ) assert env.stdout is env.devnull @@ -147,7 +147,7 @@ def test_quiet_with_password_prompt(self, httpbin, quiet_flags): @pytest.mark.parametrize('output_options', ['-h', '-b', '-v', '-p=hH']) def test_quiet_with_explicit_output_options(self, httpbin, quiet_flags, output_options): env = MockEnvironment(stdin_isatty=True, stdout_isatty=True) - r = http(*quiet_flags, output_options, httpbin.url + '/get', env=env) + r = http(*quiet_flags, output_options, httpbin + '/get', env=env) assert env.stdout is env.devnull assert env.stderr is env.devnull assert r == '' @@ -188,26 +188,26 @@ def test_quiet_with_output_redirection(self, tmp_path, httpbin, quiet_flags, wit class TestVerboseFlag: def test_verbose(self, httpbin): r = http('--verbose', - 'GET', httpbin.url + '/get', 'test-header:__test__') + 'GET', httpbin + '/get', 'test-header:__test__') assert HTTP_OK in r assert r.count('__test__') == 2 def test_verbose_raw(self, httpbin): r = http('--verbose', '--raw', 'foo bar', - 'POST', httpbin.url + '/post') + 'POST', httpbin + '/post') assert HTTP_OK in r assert 'foo bar' in r def test_verbose_form(self, httpbin): # https://github.com/httpie/cli/issues/53 - r = http('--verbose', '--form', 'POST', httpbin.url + '/post', + r = http('--verbose', '--form', 'POST', httpbin + '/post', 'A=B', 'C=D') assert HTTP_OK in r assert 'A=B&C=D' in r def test_verbose_json(self, httpbin): r = http('--verbose', - 'POST', httpbin.url + '/post', 'foo=bar', 'baz=bar') + 'POST', httpbin + '/post', 'foo=bar', 'baz=bar') assert HTTP_OK in r assert '"baz": "bar"' in r @@ -290,20 +290,20 @@ class TestPrettyOptions: def test_pretty_enabled_by_default(self, httpbin): env = MockEnvironment(colors=256) - r = http('GET', httpbin.url + '/get', env=env) + r = http('GET', httpbin + '/get', env=env) assert COLOR in r def test_pretty_enabled_by_default_unless_stdout_redirected(self, httpbin): - r = http('GET', httpbin.url + '/get') + r = http('GET', httpbin + '/get') assert COLOR not in r def test_force_pretty(self, httpbin): env = MockEnvironment(stdout_isatty=False, colors=256) - r = http('--pretty=all', 'GET', httpbin.url + '/get', env=env) + r = http('--pretty=all', 'GET', httpbin + '/get', env=env) assert COLOR in r def test_force_ugly(self, httpbin): - r = http('--pretty=none', 'GET', httpbin.url + '/get') + r = http('--pretty=none', 'GET', httpbin + '/get') assert COLOR not in r def test_subtype_based_pygments_lexer_match(self, httpbin): @@ -312,14 +312,14 @@ def test_subtype_based_pygments_lexer_match(self, httpbin): """ env = MockEnvironment(colors=256) - r = http('--print=B', '--pretty=all', httpbin.url + '/post', + r = http('--print=B', '--pretty=all', httpbin + '/post', 'Content-Type:text/foo+json', 'a=b', env=env) assert COLOR in r def test_colors_option(self, httpbin): env = MockEnvironment(colors=256) r = http('--print=B', '--pretty=colors', - 'GET', httpbin.url + '/get', 'a=b', + 'GET', httpbin + '/get', 'a=b', env=env) # Tests that the JSON data isn't formatted. assert not r.strip().count('\n') @@ -328,7 +328,7 @@ def test_colors_option(self, httpbin): def test_format_option(self, httpbin): env = MockEnvironment(colors=256) r = http('--print=B', '--pretty=format', - 'GET', httpbin.url + '/get', 'a=b', + 'GET', httpbin + '/get', 'a=b', env=env) # Tests that the JSON data is formatted. assert r.strip().count('\n') == 2 @@ -355,25 +355,25 @@ def _validate_crlf(self, msg): return body def test_CRLF_headers_only(self, httpbin): - r = http('--headers', 'GET', httpbin.url + '/get') + r = http('--headers', 'GET', httpbin + '/get') body = self._validate_crlf(r) assert not body, f'Garbage after headers: {r!r}' def test_CRLF_ugly_response(self, httpbin): - r = http('--pretty=none', 'GET', httpbin.url + '/get') + r = http('--pretty=none', 'GET', httpbin + '/get') self._validate_crlf(r) def test_CRLF_formatted_response(self, httpbin): - r = http('--pretty=format', 'GET', httpbin.url + '/get') + r = http('--pretty=format', 'GET', httpbin + '/get') assert r.exit_status == ExitStatus.SUCCESS self._validate_crlf(r) def test_CRLF_ugly_request(self, httpbin): - r = http('--pretty=none', '--print=HB', 'GET', httpbin.url + '/get') + r = http('--pretty=none', '--print=HB', 'GET', httpbin + '/get') self._validate_crlf(r) def test_CRLF_formatted_request(self, httpbin): - r = http('--pretty=format', '--print=HB', 'GET', httpbin.url + '/get') + r = http('--pretty=format', '--print=HB', 'GET', httpbin + '/get') self._validate_crlf(r) diff --git a/tests/test_redirects.py b/tests/test_redirects.py index a761fa2571..f993f31171 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -13,7 +13,7 @@ def test_follow_all_redirects_shown(httpbin): - r = http('--follow', '--all', httpbin.url + '/redirect/2') + r = http('--follow', '--all', httpbin + '/redirect/2') assert r.count('HTTP/1.1') == 3 assert r.count('HTTP/1.1 302 FOUND', 2) assert HTTP_OK in r @@ -21,14 +21,14 @@ def test_follow_all_redirects_shown(httpbin): @pytest.mark.parametrize('follow_flag', ['--follow', '-F']) def test_follow_without_all_redirects_hidden(httpbin, follow_flag): - r = http(follow_flag, httpbin.url + '/redirect/2') + r = http(follow_flag, httpbin + '/redirect/2') assert r.count('HTTP/1.1') == 1 assert HTTP_OK in r @pytest.mark.xfail(True, reason="https://github.com/httpie/cli/issues/1082") def test_follow_output_options_used_for_redirects(httpbin): - r = http('--follow', '--print=H', httpbin.url + '/redirect/2') + r = http('--follow', '--print=H', httpbin + '/redirect/2') assert r.count('GET /') == 1 assert HTTP_OK not in r @@ -38,7 +38,7 @@ def test_follow_all_output_options_used_for_redirects(httpbin): '--follow', '--all', '--print=H', - httpbin.url + '/redirect/2') + httpbin + '/redirect/2') assert r.count('GET /') == 3 assert HTTP_OK not in r @@ -50,7 +50,7 @@ def test_follow_all_output_options_used_for_redirects(httpbin): # '--all', # '--print=h', # '--history-print=H', -# httpbin.url + '/redirect/2') +# httpbin + '/redirect/2') # assert r.count('GET /') == 2 # assert 'HTTP/1.1 302 FOUND' not in r # assert HTTP_OK in r @@ -61,7 +61,7 @@ def test_max_redirects(httpbin): r = http( '--max-redirects=1', '--follow', - httpbin.url + '/redirect/3', + httpbin + '/redirect/3', tolerate_error_exit_status=True, ) assert r.exit_status == ExitStatus.ERROR_TOO_MANY_REDIRECTS @@ -72,11 +72,11 @@ def test_max_redirects(httpbin): def test_follow_redirect_with_repost(httpbin, status_code): r = http( '--follow', - httpbin.url + '/redirect-to', + httpbin + '/redirect-to', 'A:A', 'A:B', 'B:B', - f'url=={httpbin.url}/post', + f'url=={httpbin}/post', f'status_code=={status_code}', '@' + FILE_PATH_ARG, ) @@ -92,11 +92,11 @@ def test_verbose_follow_redirect_with_repost(httpbin, status_code): r = http( '--follow', '--verbose', - httpbin.url + '/redirect-to', + httpbin + '/redirect-to', 'A:A', 'A:B', 'B:B', - f'url=={httpbin.url}/post', + f'url=={httpbin}/post', f'status_code=={status_code}', '@' + FILE_PATH_ARG, ) diff --git a/tests/test_regressions.py b/tests/test_regressions.py index 07d60a583b..622d03d7ce 100644 --- a/tests/test_regressions.py +++ b/tests/test_regressions.py @@ -12,7 +12,7 @@ def test_Host_header_overwrite(httpbin): """ host = 'pie.dev' - url = httpbin.url + '/get' + url = httpbin + '/get' r = http('--print=hH', url, f'host:{host}') assert HTTP_OK in r assert r.lower().count('host:') == 1 @@ -35,7 +35,7 @@ def test_verbose_redirected_stdout_separator(httpbin): """ r = http( '-v', - httpbin.url + '/post', + httpbin + '/post', 'a=b', env=MockEnvironment(stdout_isatty=False), ) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 6c2c6f0ec2..aa5243487d 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -82,7 +82,7 @@ def start_session(self, httpbin): '--session=test', '--auth=username:password', 'GET', - httpbin.url + '/cookies/set?hello=world', + httpbin + '/cookies/set?hello=world', 'Hello:World', env=self.env() ) @@ -92,7 +92,7 @@ def test_session_created_and_reused(self, httpbin): self.start_session(httpbin) # Verify that the session created in setup_method() has been used. r2 = http('--session=test', - 'GET', httpbin.url + '/get', env=self.env()) + 'GET', httpbin + '/get', env=self.env()) assert HTTP_OK in r2 assert r2.json['headers']['Hello'] == 'World' assert r2.json['headers']['Cookie'] == 'hello=world' @@ -101,19 +101,19 @@ def test_session_created_and_reused(self, httpbin): def test_session_update(self, httpbin): self.start_session(httpbin) # Get a response to a request from the original session. - r2 = http('--session=test', 'GET', httpbin.url + '/get', + r2 = http('--session=test', 'GET', httpbin + '/get', env=self.env()) assert HTTP_OK in r2 # Make a request modifying the session data. r3 = http('--follow', '--session=test', '--auth=username:password2', - 'GET', httpbin.url + '/cookies/set?hello=world2', + 'GET', httpbin + '/cookies/set?hello=world2', 'Hello:World2', env=self.env()) assert HTTP_OK in r3 # Get a response to a request from the updated session. - r4 = http('--session=test', 'GET', httpbin.url + '/get', + r4 = http('--session=test', 'GET', httpbin + '/get', env=self.env()) assert HTTP_OK in r4 assert r4.json['headers']['Hello'] == 'World2' @@ -124,7 +124,7 @@ def test_session_update(self, httpbin): def test_session_read_only(self, httpbin): self.start_session(httpbin) # Get a response from the original session. - r2 = http('--session=test', 'GET', httpbin.url + '/get', + r2 = http('--session=test', 'GET', httpbin + '/get', env=self.env()) assert HTTP_OK in r2 @@ -132,12 +132,12 @@ def test_session_read_only(self, httpbin): # with --session-read-only. r3 = http('--follow', '--session-read-only=test', '--auth=username:password2', 'GET', - httpbin.url + '/cookies/set?hello=world2', 'Hello:World2', + httpbin + '/cookies/set?hello=world2', 'Hello:World2', env=self.env()) assert HTTP_OK in r3 # Get a response from the updated session. - r4 = http('--session=test', 'GET', httpbin.url + '/get', + r4 = http('--session=test', 'GET', httpbin + '/get', env=self.env()) assert HTTP_OK in r4 @@ -151,17 +151,17 @@ def test_session_read_only(self, httpbin): def test_session_overwrite_header(self, httpbin): self.start_session(httpbin) - r2 = http('--session=test', 'GET', httpbin.url + '/get', + r2 = http('--session=test', 'GET', httpbin + '/get', 'Hello:World2', env=self.env()) assert HTTP_OK in r2 assert r2.json['headers']['Hello'] == 'World2' - r3 = http('--session=test', 'GET', httpbin.url + '/get', + r3 = http('--session=test', 'GET', httpbin + '/get', 'Hello:World2', 'Hello:World3', env=self.env()) assert HTTP_OK in r3 assert r3.json['headers']['Hello'] == 'World2,World3' - r3 = http('--session=test', 'GET', httpbin.url + '/get', + r3 = http('--session=test', 'GET', httpbin + '/get', 'Hello:', 'Hello:World3', env=self.env()) assert HTTP_OK in r3 assert 'Hello' not in r3.json['headers']['Hello'] @@ -172,12 +172,12 @@ class TestSession(SessionTestBase): def test_session_ignored_header_prefixes(self, httpbin): self.start_session(httpbin) - r1 = http('--session=test', 'GET', httpbin.url + '/get', + r1 = http('--session=test', 'GET', httpbin + '/get', 'Content-Type: text/plain', 'If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT', env=self.env()) assert HTTP_OK in r1 - r2 = http('--session=test', 'GET', httpbin.url + '/get', + r2 = http('--session=test', 'GET', httpbin + '/get', env=self.env()) assert HTTP_OK in r2 assert 'Content-Type' not in r2.json['headers'] @@ -185,18 +185,18 @@ def test_session_ignored_header_prefixes(self, httpbin): def test_session_with_upload(self, httpbin): self.start_session(httpbin) - r = http('--session=test', '--form', '--verbose', 'POST', httpbin.url + '/post', + r = http('--session=test', '--form', '--verbose', 'POST', httpbin + '/post', f'test-file@{FILE_PATH_ARG}', 'foo=bar', env=self.env()) assert HTTP_OK in r def test_session_by_path(self, httpbin): self.start_session(httpbin) session_path = self.config_dir / 'session-by-path.json' - r1 = http('--session', str(session_path), 'GET', httpbin.url + '/get', + r1 = http('--session', str(session_path), 'GET', httpbin + '/get', 'Foo:Bar', env=self.env()) assert HTTP_OK in r1 - r2 = http('--session', str(session_path), 'GET', httpbin.url + '/get', + r2 = http('--session', str(session_path), 'GET', httpbin + '/get', env=self.env()) assert HTTP_OK in r2 assert r2.json['headers']['Foo'] == 'Bar' @@ -214,7 +214,7 @@ def test_session_with_cookie_followed_by_another_header(self, httpbin): } session_path = self.config_dir / 'session-data.json' session_path.write_text(json.dumps(session_data)) - r = http('--session', str(session_path), 'GET', httpbin.url + '/get', + r = http('--session', str(session_path), 'GET', httpbin + '/get', env=self.env()) assert HTTP_OK in r assert 'Zzz' in r @@ -223,12 +223,12 @@ def test_session_unicode(self, httpbin): self.start_session(httpbin) r1 = http('--session=test', f'--auth=test:{UNICODE}', - 'GET', httpbin.url + '/get', f'Test:{UNICODE}', + 'GET', httpbin + '/get', f'Test:{UNICODE}', env=self.env()) assert HTTP_OK in r1 r2 = http('--session=test', '--verbose', 'GET', - httpbin.url + '/get', env=self.env()) + httpbin + '/get', env=self.env()) assert HTTP_OK in r2 # FIXME: Authorization *sometimes* is not present @@ -241,12 +241,12 @@ def test_session_default_header_value_overwritten(self, httpbin): self.start_session(httpbin) # https://github.com/httpie/cli/issues/180 r1 = http('--session=test', - httpbin.url + '/headers', 'User-Agent:custom', + httpbin + '/headers', 'User-Agent:custom', env=self.env()) assert HTTP_OK in r1 assert r1.json['headers']['User-Agent'] == 'custom' - r2 = http('--session=test', httpbin.url + '/headers', env=self.env()) + r2 = http('--session=test', httpbin + '/headers', env=self.env()) assert HTTP_OK in r2 assert r2.json['headers']['User-Agent'] == 'custom' @@ -257,7 +257,7 @@ def test_download_in_session(self, tmp_path, httpbin): os.chdir(tmp_path) try: http('--session=test', '--download', - httpbin.url + '/get', env=self.env()) + httpbin + '/get', env=self.env()) finally: os.chdir(cwd) @@ -386,7 +386,7 @@ def test_expired_cookies(self, httpbin): r = http( '--session', str(self.session_path), '--print=H', - httpbin.url + '/cookies/delete?cookie2', + httpbin + '/cookies/delete?cookie2', ) assert 'Cookie: cookie1=foo; cookie2=foo' in r @@ -484,7 +484,7 @@ def test_existing_and_new_cookies_sent_in_request( r = http( '--session', str(self.session_path), '--print=H', - httpbin.url, + httpbin + '/get', 'Cookie:' + specified_cookie_header, ) parsed_request_headers = { # noqa @@ -537,7 +537,7 @@ def test_cookie_storage_priority(self, cli_cookie, set_cookie, expected, httpbin """ http( '--session', str(self.session_path), - httpbin.url + set_cookie, + httpbin + set_cookie, 'Cookie:' + cli_cookie, ) updated_session = json.loads(self.session_path.read_text(encoding=UTF8)) diff --git a/tests/test_stream.py b/tests/test_stream.py index 45b8e4dd32..b0b9b8bde8 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -46,7 +46,7 @@ def test_pretty_redirected_stream(httpbin): stdout_isatty=False, ) r = http('--verbose', '--pretty=all', '--stream', 'GET', - httpbin.url + '/get', env=env) + httpbin + '/get', env=env) assert BINARY_SUPPRESSED_NOTICE.decode() in r @@ -57,7 +57,7 @@ def test_pretty_stream_ensure_full_stream_is_retrieved(httpbin): stdout_isatty=False, ) r = http('--pretty=format', '--stream', 'GET', - httpbin.url + '/stream/3', env=env) + httpbin + '/stream/3', env=env) assert r.count('/stream/3') == 3 @@ -98,7 +98,7 @@ def test_encoded_stream(httpbin): stdin_isatty=False, ) r = http('--pretty=none', '--stream', '--verbose', 'GET', - httpbin.url + '/get', env=env) + httpbin + '/get', env=env) assert BINARY_SUPPRESSED_NOTICE.decode() in r @@ -111,7 +111,7 @@ def test_redirected_stream(httpbin): stdin=StdinBytesIO(BIN_FILE_PATH.read_bytes()), ) r = http('--pretty=none', '--stream', '--verbose', 'GET', - httpbin.url + '/get', env=env) + httpbin + '/get', env=env) assert BIN_FILE_CONTENT in r diff --git a/tests/test_uploads.py b/tests/test_uploads.py index d0156063d4..e6bb80ac70 100644 --- a/tests/test_uploads.py +++ b/tests/test_uploads.py @@ -192,10 +192,10 @@ class TestMultipartFormDataFileUpload: def test_non_existent_file_raises_parse_error(self, httpbin): with pytest.raises(ParseError): http('--form', - 'POST', httpbin.url + '/post', 'foo@/__does_not_exist__') + 'POST', httpbin + '/post', 'foo@/__does_not_exist__') def test_upload_ok(self, httpbin): - r = http('--form', '--verbose', 'POST', httpbin.url + '/post', + r = http('--form', '--verbose', 'POST', httpbin + '/post', f'test-file@{FILE_PATH_ARG}', 'foo=bar') assert HTTP_OK in r assert 'Content-Disposition: form-data; name="foo"' in r @@ -206,7 +206,7 @@ def test_upload_ok(self, httpbin): assert 'Content-Type: text/plain' in r def test_upload_multiple_fields_with_the_same_name(self, httpbin): - r = http('--form', '--verbose', 'POST', httpbin.url + '/post', + r = http('--form', '--verbose', 'POST', httpbin + '/post', f'test-file@{FILE_PATH_ARG}', f'test-file@{FILE_PATH_ARG}') assert HTTP_OK in r @@ -221,7 +221,7 @@ def test_upload_custom_content_type(self, httpbin): r = http( '--form', '--verbose', - httpbin.url + '/post', + httpbin + '/post', f'test-file@{FILE_PATH_ARG};type=image/vnd.microsoft.icon' ) assert HTTP_OK in r @@ -235,7 +235,7 @@ def test_form_no_files_urlencoded(self, httpbin): r = http( '--form', '--verbose', - httpbin.url + '/post', + httpbin + '/post', 'AAAA=AAA', 'BBB=BBB', ) @@ -246,7 +246,7 @@ def test_multipart(self, httpbin): r = http( '--verbose', '--multipart', - httpbin.url + '/post', + httpbin + '/post', 'AAAA=AAA', 'BBB=BBB', ) @@ -261,7 +261,7 @@ def test_form_multipart_custom_boundary(self, httpbin): '--check-status', '--multipart', f'--boundary={boundary}', - httpbin.url + '/post', + httpbin + '/post', 'AAAA=AAA', 'BBB=BBB', ) @@ -275,7 +275,7 @@ def test_multipart_custom_content_type_boundary_added(self, httpbin): '--check-status', '--multipart', f'--boundary={boundary}', - httpbin.url + '/post', + httpbin + '/post', 'Content-Type: multipart/magic', 'AAAA=AAA', 'BBB=BBB', @@ -292,7 +292,7 @@ def test_multipart_custom_content_type_boundary_preserved(self, httpbin): '--check-status', '--multipart', f'--boundary={boundary_in_body}', - httpbin.url + '/post', + httpbin + '/post', f'Content-Type: multipart/magic; boundary={boundary_in_header}', 'AAAA=AAA', 'BBB=BBB', @@ -342,7 +342,7 @@ class TestRequestBodyFromFilePath: def test_request_body_from_file_by_path(self, httpbin): r = http( '--verbose', - 'POST', httpbin.url + '/post', + 'POST', httpbin + '/post', '@' + FILE_PATH_ARG, ) assert HTTP_OK in r @@ -363,7 +363,7 @@ def test_request_body_from_file_by_path_chunked(self, httpbin_with_chunked_suppo def test_request_body_from_file_by_path_with_explicit_content_type( self, httpbin): r = http('--verbose', - 'POST', httpbin.url + '/post', '@' + FILE_PATH_ARG, + 'POST', httpbin + '/post', '@' + FILE_PATH_ARG, 'Content-Type:text/plain; charset=UTF-8') assert HTTP_OK in r assert FILE_CONTENT in r @@ -372,7 +372,7 @@ def test_request_body_from_file_by_path_with_explicit_content_type( def test_request_body_from_file_by_path_no_field_name_allowed( self, httpbin): env = MockEnvironment(stdin_isatty=True) - r = http('POST', httpbin.url + '/post', 'field-name@' + FILE_PATH_ARG, + r = http('POST', httpbin + '/post', 'field-name@' + FILE_PATH_ARG, env=env, tolerate_error_exit_status=True) assert 'perhaps you meant --form?' in r.stderr @@ -381,7 +381,7 @@ def test_request_body_from_file_by_path_no_data_items_allowed( env = MockEnvironment(stdin_isatty=False) r = http( 'POST', - httpbin.url + '/post', + httpbin + '/post', '@' + FILE_PATH_ARG, 'foo=bar', env=env, tolerate_error_exit_status=True, @@ -393,7 +393,7 @@ def test_multiple_request_bodies_from_file_by_path(self, httpbin): env = MockEnvironment(stdin_isatty=True) r = http( '--verbose', - 'POST', httpbin.url + '/post', + 'POST', httpbin + '/post', '@' + FILE_PATH_ARG, '@' + FILE_PATH_ARG, env=env, diff --git a/tests/test_windows.py b/tests/test_windows.py index b30c7a5084..80d392ae8f 100644 --- a/tests/test_windows.py +++ b/tests/test_windows.py @@ -12,7 +12,7 @@ class TestWindowsOnly: reason='this test for some reason kills the process') def test_windows_colorized_output(self, httpbin): # Spits out the colorized output. - http(httpbin.url + '/get', env=Environment()) + http(httpbin + '/get', env=Environment()) class TestFakeWindows: @@ -20,6 +20,6 @@ def test_output_file_pretty_not_allowed_on_windows(self, tmp_path, httpbin): env = MockEnvironment(is_windows=True) output_file = tmp_path / 'test_output_file_pretty_not_allowed_on_windows' r = http('--output', str(output_file), - '--pretty=all', 'GET', httpbin.url + '/get', + '--pretty=all', 'GET', httpbin + '/get', env=env, tolerate_error_exit_status=True) assert 'Only terminal output can be colorized on Windows' in r.stderr diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index ada0905ff2..5081c71ba6 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -360,7 +360,7 @@ def http( $ http --auth=user:password GET pie.dev/basic-auth/user/password >>> httpbin = getfixture('httpbin') - >>> r = http('-a', 'user:pw', httpbin.url + '/basic-auth/user/pw') + >>> r = http('-a', 'user:pw', httpbin + '/basic-auth/user/pw') >>> type(r) == StrCLIResponse True >>> r.exit_status is ExitStatus.SUCCESS From 10b7d317d03c799f138a961c543294cb44ab416c Mon Sep 17 00:00:00 2001 From: Mathieu Dupuy Date: Mon, 18 Mar 2024 16:37:09 +0100 Subject: [PATCH 1168/1182] Migrate setup.py to setup.cfg (#1553) * migrate setup.py to setup.cfg No man pages * fix Makefile build * silence flake8 F811 for BaseCLIResponse.command * also include man pages * restore a stub setup.py * remove pytest-lazy fixtures --- Makefile | 7 ++- setup.cfg | 89 +++++++++++++++++++++++++++ setup.py | 129 +--------------------------------------- tests/utils/__init__.py | 2 +- 4 files changed, 96 insertions(+), 131 deletions(-) diff --git a/Makefile b/Makefile index 3226a0312e..a2a80a1778 100644 --- a/Makefile +++ b/Makefile @@ -124,7 +124,8 @@ test-dist: test-sdist test-bdist-wheel test-sdist: clean venv @echo $(H1)Testing sdist build an installation$(H1END) - $(VENV_PYTHON) setup.py sdist + $(VENV_PIP) install build + $(VENV_PYTHON) -m build --sdist $(VENV_PIP) install --force-reinstall --upgrade dist/*.gz $(VENV_BIN)/http --version @echo @@ -132,8 +133,8 @@ test-sdist: clean venv test-bdist-wheel: clean venv @echo $(H1)Testing wheel build an installation$(H1END) - $(VENV_PIP) install wheel - $(VENV_PYTHON) setup.py bdist_wheel + $(VENV_PIP) install build + $(VENV_PYTHON) -m build --wheel $(VENV_PIP) install --force-reinstall --upgrade dist/*.whl $(VENV_BIN)/http --version @echo diff --git a/setup.cfg b/setup.cfg index 86c41ff308..e4d7ced96a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,9 +12,98 @@ norecursedirs = tests/fixtures addopts = --tb=native --doctest-modules --verbose xfail_strict = True +[metadata] +name = httpie +version = attr: httpie.__version__ +author = Jakub Roztocil +author_email = jakub@roztocil.co +license = BSD +description = HTTPie: modern, user-friendly command-line HTTP client for the API era. +url = https://httpie.io/ +long_description = file: README.md +long_description_content_type = text/markdown +classifiers = + Development Status :: 5 - Production/Stable + Programming Language :: Python + Programming Language :: Python :: 3 :: Only + Environment :: Console + Intended Audience :: Developers + Intended Audience :: System Administrators + License :: OSI Approved :: BSD License + Topic :: Internet :: WWW/HTTP + Topic :: Software Development + Topic :: System :: Networking + Topic :: Terminals + Topic :: Text Processing + Topic :: Utilities +project_urls = + GitHub = https://github.com/httpie/cli + Twitter = https://twitter.com/httpie + Discord = https://httpie.io/discord + Documentation = https://httpie.io/docs + Online Demo = https://httpie.io/run + + +[options] +packages = find: +install_requires = + pip + charset_normalizer>=2.0.0 + defusedxml>=0.6.0 + requests[socks]>=2.22.0 + Pygments>=2.5.2 + requests-toolbelt>=0.9.1 + multidict>=4.7.0 + setuptools + importlib-metadata>=1.4.0; python_version < "3.8" + rich>=9.10.0 +python_requires = >=3.7 + [flake8] # # E501 - line too long # W503 - line break before binary operator ignore = E501,W503 + +[options.packages.find] +include = + httpie + httpie.* + +[options.entry_points] +console_scripts = + http = httpie.__main__:main + https = httpie.__main__:main + httpie = httpie.manager.__main__:main + +[options.extras_require] +dev = + pytest + pytest-httpbin>=0.0.6 + responses + pytest-mock + werkzeug<2.1.0 + flake8 + flake8-comprehensions + flake8-deprecated + flake8-mutable + flake8-tuple + pyopenssl + pytest-cov + pyyaml + twine + wheel + Jinja2 +test = + pytest + pytest-httpbin>=0.0.6 + responses + pytest-mock + werkzeug<2.1.0 + +[options.data_files] +share/man/man1 = + extras/man/http.1 + extras/man/https.1 + extras/man/httpie.1 diff --git a/setup.py b/setup.py index 21bdaf1658..606849326a 100644 --- a/setup.py +++ b/setup.py @@ -1,128 +1,3 @@ -# This is purely the result of trial and error. +from setuptools import setup -import sys - -from setuptools import setup, find_packages - -import httpie - - -# Note: keep requirements here to ease distributions packaging -tests_require = [ - 'pytest', - 'pytest-httpbin>=0.0.6', - 'responses', - 'pytest-mock', - 'werkzeug<2.1.0' -] -dev_require = [ - *tests_require, - 'flake8', - 'flake8-comprehensions', - 'flake8-deprecated', - 'flake8-mutable', - 'flake8-tuple', - 'pyopenssl', - 'pytest-cov', - 'pyyaml', - 'twine', - 'wheel', - 'Jinja2' -] -install_requires = [ - 'pip', - 'charset_normalizer>=2.0.0', - 'defusedxml>=0.6.0', - 'requests[socks]>=2.22.0', - 'Pygments>=2.5.2', - 'requests-toolbelt>=0.9.1', - 'multidict>=4.7.0', - 'setuptools', - 'importlib-metadata>=1.4.0; python_version < "3.8"', - 'rich>=9.10.0' -] -install_requires_win_only = [ - 'colorama>=0.2.4', -] - -# Conditional dependencies: - -# sdist -if 'bdist_wheel' not in sys.argv: - - if 'win32' in str(sys.platform).lower(): - # Terminal colors for Windows - install_requires.extend(install_requires_win_only) - - -# bdist_wheel -extras_require = { - 'dev': dev_require, - 'test': tests_require, - # https://wheel.readthedocs.io/en/latest/#defining-conditional-dependencies - ':sys_platform == "win32"': install_requires_win_only, -} - - -def long_description(): - with open('README.md', encoding='utf-8') as f: - return f.read() - - -setup( - name='httpie', - version=httpie.__version__, - description=httpie.__doc__.strip(), - long_description=long_description(), - long_description_content_type='text/markdown', - url='https://httpie.io/', - download_url=f'https://github.com/httpie/cli/archive/{httpie.__version__}.tar.gz', - author=httpie.__author__, - author_email='jakub@roztocil.co', - license=httpie.__licence__, - packages=find_packages(include=['httpie', 'httpie.*']), - entry_points={ - 'console_scripts': [ - 'http = httpie.__main__:main', - 'https = httpie.__main__:main', - 'httpie = httpie.manager.__main__:main', - ], - }, - python_requires='>=3.7', - extras_require=extras_require, - install_requires=install_requires, - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - 'Programming Language :: Python :: Implementation :: CPython', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'Intended Audience :: System Administrators', - 'License :: OSI Approved :: BSD License', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Software Development', - 'Topic :: System :: Networking', - 'Topic :: Terminals', - 'Topic :: Text Processing', - 'Topic :: Utilities' - ], - project_urls={ - 'GitHub': 'https://github.com/httpie/cli', - 'Twitter': 'https://twitter.com/httpie', - 'Discord': 'https://httpie.io/discord', - 'Documentation': 'https://httpie.io/docs', - 'Online Demo': 'https://httpie.io/run', - }, - data_files=[ - ('share/man/man1', ['extras/man/http.1']), - ('share/man/man1', ['extras/man/https.1']), - ('share/man/man1', ['extras/man/httpie.1']), - ] -) +setup() diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index 5081c71ba6..0a9af608a5 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -210,7 +210,7 @@ class BaseCLIResponse: complete_args: List[str] = [] @property - def command(self): + def command(self): # noqa: F811 cmd = ' '.join(shlex.quote(arg) for arg in ['http', *self.args]) # pytest-httpbin to real httpbin. return re.sub(r'127\.0\.0\.1:\d+', 'httpbin.org', cmd) From 5c068f8102ef91362132606c8923b13fb8c7fd68 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 18 Mar 2024 16:53:23 +0100 Subject: [PATCH 1169/1182] Re-add conditional colorama dependency #1553 --- setup.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index e4d7ced96a..7342296dd0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -55,8 +55,9 @@ install_requires = requests-toolbelt>=0.9.1 multidict>=4.7.0 setuptools - importlib-metadata>=1.4.0; python_version < "3.8" + importlib-metadata>=1.4.0; python_version<"3.8" rich>=9.10.0 + colorama>=0.2.4; sys_platform=="win32" python_requires = >=3.7 From 7f03c52d2237440c5a672296ce6955aae4ed4f09 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 10 Jul 2024 16:15:24 +0200 Subject: [PATCH 1170/1182] Fix SSL connections by pinning the `requests` version to `2.31.0` Close #1583 Close #1581 --- CHANGELOG.md | 7 ++++--- extras/man/http.1 | 2 +- extras/man/httpie.1 | 2 +- extras/man/https.1 | 2 +- httpie/__init__.py | 4 ++-- setup.cfg | 2 +- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd80c096f2..8ef621e474 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,12 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). -## [3.3.0-dev](https://github.com/httpie/cli/compare/3.2.2...master) (unreleased) +## [3.2.3](https://github.com/httpie/cli/compare/3.2.2...3.2.3) (2024-07-10) -- Make it possible to [unset](https://httpie.io/docs/cli/default-request-headers) the `User-Agent`, `Accept-Encoding`, and `Host` request headers. ([#1502](https://github.com/httpie/cli/issues/1502)) +- Fix SSL connections by pinning the `requests` version to `2.31.0`. ([#1583], [#1581]) +- Make it possible to [unset](https://httpie.io/docs/cli/default-request-headers) the `User-Agent` and `Accept-Encoding` request headers. ([#1502](https://github.com/httpie/cli/issues/1502)) -## [3.2.2](https://github.com/httpie/cli/compare/3.2.1...3.2.2) (2022-05-19) +## [3.2.2](https://github.com/httpie/cli/compare/3.2.1...3.2.2) (2023-05-19) - Fixed compatibility with urllib3 2.0.0. ([#1499](https://github.com/httpie/cli/issues/1499)) diff --git a/extras/man/http.1 b/extras/man/http.1 index 65fa133ab0..09e4237006 100644 --- a/extras/man/http.1 +++ b/extras/man/http.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/cli/definition.py by extras/scripts/generate_man_pages.py. -.TH http 1 "2022-05-06" "HTTPie 3.2.2" "HTTPie Manual" +.TH http 1 "2024-07-10" "HTTPie 3.2.3" "HTTPie Manual" .SH NAME http .SH SYNOPSIS diff --git a/extras/man/httpie.1 b/extras/man/httpie.1 index 0536d61bfa..ba269b1acf 100644 --- a/extras/man/httpie.1 +++ b/extras/man/httpie.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/manager/cli.py by extras/scripts/generate_man_pages.py. -.TH httpie 1 "2022-05-06" "HTTPie 3.2.2" "HTTPie Manual" +.TH httpie 1 "2024-07-10" "HTTPie 3.2.3" "HTTPie Manual" .SH NAME httpie .SH SYNOPSIS diff --git a/extras/man/https.1 b/extras/man/https.1 index c91290a245..dfb1b018ad 100644 --- a/extras/man/https.1 +++ b/extras/man/https.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/cli/definition.py by extras/scripts/generate_man_pages.py. -.TH https 1 "2022-05-06" "HTTPie 3.2.2" "HTTPie Manual" +.TH https 1 "2024-07-10" "HTTPie 3.2.3" "HTTPie Manual" .SH NAME https .SH SYNOPSIS diff --git a/httpie/__init__.py b/httpie/__init__.py index ffe0d35419..d67c919042 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ -__version__ = '3.2.2' -__date__ = '2022-05-06' +__version__ = '3.2.3' +__date__ = '2024-07-10' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' diff --git a/setup.cfg b/setup.cfg index 7342296dd0..3766339326 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,7 +50,7 @@ install_requires = pip charset_normalizer>=2.0.0 defusedxml>=0.6.0 - requests[socks]>=2.22.0 + requests[socks] >=2.22.0, <=2.31.0 Pygments>=2.5.2 requests-toolbelt>=0.9.1 multidict>=4.7.0 From f4cf43ecdd6c5c52b5c4ba91086d5c6ccfebcd6d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 10 Jul 2024 16:24:03 +0200 Subject: [PATCH 1171/1182] Cleanup --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ef621e474..310547435e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [3.2.3](https://github.com/httpie/cli/compare/3.2.2...3.2.3) (2024-07-10) -- Fix SSL connections by pinning the `requests` version to `2.31.0`. ([#1583], [#1581]) +- Fix SSL connections by pinning the `requests` version to `2.31.0`. (#1583, #1581) - Make it possible to [unset](https://httpie.io/docs/cli/default-request-headers) the `User-Agent` and `Accept-Encoding` request headers. ([#1502](https://github.com/httpie/cli/issues/1502)) ## [3.2.2](https://github.com/httpie/cli/compare/3.2.1...3.2.2) (2023-05-19) From 50e1564600eaca3ff99ffd7a7f707f564da3af48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Srinivasan?= Date: Mon, 28 Oct 2024 12:28:36 -0700 Subject: [PATCH 1172/1182] Update the Forms section of README.md (#1593) The Forms section of README.md was missing what the data fields are serialized as. --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 65c7ebe4ed..4b866a043b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1044,7 +1044,7 @@ $ http POST pie.dev/post < files/data.json ## Forms Submitting forms is very similar to sending [JSON](#json) requests. -Often the only difference is in adding the `--form, -f` option, which ensures that data fields are serialized as, and `Content-Type` is set to `application/x-www-form-urlencoded; charset=utf-8`. +Often the only difference is in adding the `--form, -f` option, which ensures that data fields are serialized as key-value tuples separated by '&', with a '=' between the key and the value. In addition `Content-Type` is set to `application/x-www-form-urlencoded; charset=utf-8`. It is possible to make form data the implicit content type instead of JSON via the [config](#config) file. ### Regular forms From 30373274104f592975cb1510b286f6c51d8dcf28 Mon Sep 17 00:00:00 2001 From: Arthur <82575487+arthur-mountain@users.noreply.github.com> Date: Fri, 1 Nov 2024 00:02:17 +0800 Subject: [PATCH 1173/1182] Update the raw json fields example (#1606) --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 4b866a043b..5107e73e73 100644 --- a/docs/README.md +++ b/docs/README.md @@ -574,7 +574,7 @@ $ http PUT pie.dev/put \ | HTTP Headers `Name:Value` | Arbitrary HTTP header, e.g. `X-API-Token:123` | | URL parameters `name==value` | Appends the given name/value pair as a querystring parameter to the URL. The `==` separator is used. | | Data Fields `field=value` | Request data fields to be serialized as a JSON object (default), to be form-encoded (with `--form, -f`), or to be serialized as `multipart/form-data` (with `--multipart`) | -| Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:=[1,2,3]` (note the quotes) | +| Raw JSON fields `field:=json` | Useful when sending JSON and one or more fields need to be a `Boolean`, `Number`, nested `Object`, or an `Array`, e.g., `meals:='["ham","spam"]'` or `pies:='[1,2,3]'` (note the quotes) | | File upload fields `field@/dir/file`, `field@file;type=mime` | Only available with `--form`, `-f` and `--multipart`. For example `screenshot@~/Pictures/img.png`, or `'cv@cv.txt;type=text/markdown'`. With `--form`, the presence of a file field results in a `--multipart` request | Note that the structured data fields aren’t the only way to specify request data: From 9eb8699873007947765f342088744775b0bbbb11 Mon Sep 17 00:00:00 2001 From: Dennis Heinrich Date: Thu, 31 Oct 2024 17:10:54 +0100 Subject: [PATCH 1174/1182] Added an alias for HTTPS in fish completions (#1598) Ensure that fish completion is working with the `https` command. It just wraps the identical completions from `http` to `https`. --- extras/httpie-completion.fish | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/extras/httpie-completion.fish b/extras/httpie-completion.fish index 8a711b6024..102399a4ec 100644 --- a/extras/httpie-completion.fish +++ b/extras/httpie-completion.fish @@ -112,3 +112,10 @@ complete -c http -l version -d 'Show version' complete -c http -l traceback -d 'Prints exception traceback should one occur' complete -c http -l default-scheme -x -d 'The default scheme to use' complete -c http -l debug -d 'Show debugging output' + + +# Alias for https to http + +function https --wraps http + http $argv; +end From cee82c825e3ed2eeb9f0fc5f31d478c6b8683fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?= Date: Thu, 31 Oct 2024 23:13:24 +0700 Subject: [PATCH 1175/1182] Fix link to CurliPie tool (#1582) * Fix link to CurliPie tool * Use the link to web version for CurliPie Co-authored-by: Jan Brasna <1784648+janbrasna@users.noreply.github.com> --------- Co-authored-by: Jan Brasna <1784648+janbrasna@users.noreply.github.com> --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 5107e73e73..51dff51aec 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2568,7 +2568,7 @@ HTTPie plays exceptionally well with the following tools: Helpers to convert from other client tools: -- [CurliPie](https://curlipie.now.sh/) help convert cURL command line to HTTPie command line +- [CurliPie](https://curlipie.open-api.vn) — library to convert cURL commands to HTTPie #### Alternatives From fd30c4ef6230a927f9dcfad6301c40e8bf846156 Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Fri, 1 Nov 2024 09:37:11 -0700 Subject: [PATCH 1176/1182] Explicitly load default certificates when creating SSL context (#1583) (#1596) * Explicitly load default certificates when creating SSL context (#1583) Requests prior to 2.32.3 always loaded the default (system-wide) set of trusted certificates into custom SSL contexts. 2.32.3 no longer does. This has broken a lot of users, but the fix is moving slowly upstream due to security considerations - see https://github.com/psf/requests/issues/6730 and https://github.com/psf/requests/pull/6731 . As suggested at https://github.com/psf/requests/pull/6710#issuecomment-2137802782 this can be worked around by explicitly loading the default certificates into the context. We check the method exists before calling it just to be safe, it was added in Python 3.4. Signed-off-by: Adam Williamson * Drop the upper bound on the requests dependency again As we can now work with requests 2.32.3+, we no longer need this pin. Signed-off-by: Adam Williamson --------- Signed-off-by: Adam Williamson --- httpie/ssl_.py | 7 +++++++ setup.cfg | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/httpie/ssl_.py b/httpie/ssl_.py index af5ca548db..33fde598bd 100644 --- a/httpie/ssl_.py +++ b/httpie/ssl_.py @@ -48,6 +48,13 @@ def __init__( ssl_version=ssl_version, ciphers=ciphers, ) + # workaround for a bug in requests 2.32.3, see: + # https://github.com/httpie/cli/issues/1583 + if getattr(self._ssl_context, 'load_default_certs', None) is not None: + # if load_default_certs is present, get_ca_certs must be + # also, no need for another getattr + if not self._ssl_context.get_ca_certs(): + self._ssl_context.load_default_certs() super().__init__(**kwargs) def init_poolmanager(self, *args, **kwargs): diff --git a/setup.cfg b/setup.cfg index 3766339326..85490981aa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,7 +50,7 @@ install_requires = pip charset_normalizer>=2.0.0 defusedxml>=0.6.0 - requests[socks] >=2.22.0, <=2.31.0 + requests[socks] >=2.22.0 Pygments>=2.5.2 requests-toolbelt>=0.9.1 multidict>=4.7.0 From ff742581f49dbc370b3288dd53d35f843c564c66 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Nov 2024 17:38:39 +0100 Subject: [PATCH 1177/1182] Cleanup default cert loading --- httpie/ssl_.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/httpie/ssl_.py b/httpie/ssl_.py index 33fde598bd..6df4ff45c4 100644 --- a/httpie/ssl_.py +++ b/httpie/ssl_.py @@ -32,7 +32,7 @@ class HTTPieCertificate(NamedTuple): def to_raw_cert(self): """Synthesize a requests-compatible (2-item tuple of cert and key file) object from HTTPie's internal representation of a certificate.""" - return (self.cert_file, self.key_file) + return self.cert_file, self.key_file class HTTPieHTTPSAdapter(HTTPAdapter): @@ -48,13 +48,6 @@ def __init__( ssl_version=ssl_version, ciphers=ciphers, ) - # workaround for a bug in requests 2.32.3, see: - # https://github.com/httpie/cli/issues/1583 - if getattr(self._ssl_context, 'load_default_certs', None) is not None: - # if load_default_certs is present, get_ca_certs must be - # also, no need for another getattr - if not self._ssl_context.get_ca_certs(): - self._ssl_context.load_default_certs() super().__init__(**kwargs) def init_poolmanager(self, *args, **kwargs): @@ -78,7 +71,7 @@ def _create_ssl_context( ssl_version: str = None, ciphers: str = None, ) -> 'ssl.SSLContext': - return create_urllib3_context( + context = create_urllib3_context( ciphers=ciphers, ssl_version=resolve_ssl_version(ssl_version), # Since we are using a custom SSL context, we need to pass this @@ -86,6 +79,11 @@ def _create_ssl_context( # in `super().cert_verify()`. cert_reqs=ssl.CERT_REQUIRED if verify else ssl.CERT_NONE ) + if not context.get_ca_certs(): + # Workaround for a bug in requests 2.32.3 + # See + context.load_default_certs() + return context @classmethod def get_default_ciphers_names(cls): From 2ef4a57d8c2a3defd189e0cc6e365fa8a9aaff2c Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Nov 2024 17:47:27 +0100 Subject: [PATCH 1178/1182] Fix/refactor default cert loading --- httpie/compat.py | 17 ++++++++++++++--- httpie/ssl_.py | 13 ++++++------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/httpie/compat.py b/httpie/compat.py index fcf167ca7d..d12abcff02 100644 --- a/httpie/compat.py +++ b/httpie/compat.py @@ -1,8 +1,9 @@ import sys +from ssl import SSLContext from typing import Any, Optional, Iterable from httpie.cookies import HTTPieCookiePolicy -from http import cookiejar # noqa +from http import cookiejar # noqa # Request does not carry the original policy attached to the @@ -10,7 +11,6 @@ # policy. cookiejar.DefaultCookiePolicy = HTTPieCookiePolicy - is_windows = 'win32' in str(sys.platform).lower() is_frozen = getattr(sys, 'frozen', False) @@ -66,7 +66,6 @@ def __get__(self, instance, cls=None): res = instance.__dict__[self.name] = self.func(instance) return res - # importlib_metadata was a provisional module, so the APIs changed quite a few times # between 3.8-3.10. It was also not included in the standard library until 3.8, so # we install the backport for <3.8. @@ -100,3 +99,15 @@ def get_dist_name(entry_point: importlib_metadata.EntryPoint) -> Optional[str]: return None else: return metadata.get('name') + + +def ensure_default_certs_loaded(ssl_context: SSLContext) -> None: + """ + Workaround for a bug in Requests 2.32.3 + + See + + """ + if hasattr(ssl_context, 'load_default_certs'): + if not ssl_context.get_ca_certs(): + ssl_context.load_default_certs() diff --git a/httpie/ssl_.py b/httpie/ssl_.py index 6df4ff45c4..6b3ef38cf6 100644 --- a/httpie/ssl_.py +++ b/httpie/ssl_.py @@ -1,13 +1,15 @@ import ssl from typing import NamedTuple, Optional -from httpie.adapters import HTTPAdapter # noinspection PyPackageRequirements from urllib3.util.ssl_ import ( create_urllib3_context, resolve_ssl_version, ) +from .adapters import HTTPAdapter +from .compat import ensure_default_certs_loaded + SSL_VERSION_ARG_MAPPING = { 'ssl2.3': 'PROTOCOL_SSLv23', @@ -71,7 +73,7 @@ def _create_ssl_context( ssl_version: str = None, ciphers: str = None, ) -> 'ssl.SSLContext': - context = create_urllib3_context( + ssl_context = create_urllib3_context( ciphers=ciphers, ssl_version=resolve_ssl_version(ssl_version), # Since we are using a custom SSL context, we need to pass this @@ -79,11 +81,8 @@ def _create_ssl_context( # in `super().cert_verify()`. cert_reqs=ssl.CERT_REQUIRED if verify else ssl.CERT_NONE ) - if not context.get_ca_certs(): - # Workaround for a bug in requests 2.32.3 - # See - context.load_default_certs() - return context + ensure_default_certs_loaded(ssl_context) + return ssl_context @classmethod def get_default_ciphers_names(cls): From 8560d1196d78fa839a4d69503680d95bed4552d4 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Nov 2024 18:01:03 +0100 Subject: [PATCH 1179/1182] Update test.yml --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0dbfae4edb..d98b63ae69 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,7 +24,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, macos-13, windows-latest] python-version: - '3.12' - '3.11' From 2105caa49bae87c5809c274e407619a0de2639d1 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Fri, 1 Nov 2024 18:29:56 +0100 Subject: [PATCH 1180/1182] 3.2.4 --- CHANGELOG.md | 4 ++++ extras/man/http.1 | 2 +- extras/man/httpie.1 | 2 +- extras/man/https.1 | 2 +- httpie/__init__.py | 4 ++-- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 310547435e..0497ac3508 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ This document records all notable changes to [HTTPie](https://httpie.io). This project adheres to [Semantic Versioning](https://semver.org/). +## [3.2.4](https://github.com/httpie/cli/compare/3.2.3...3.2.4) (2024-11-01) + +- Fix default certs loading and unpin `requests`. ([#1596](https://github.com/httpie/cli/issues/1596)) + ## [3.2.3](https://github.com/httpie/cli/compare/3.2.2...3.2.3) (2024-07-10) - Fix SSL connections by pinning the `requests` version to `2.31.0`. (#1583, #1581) diff --git a/extras/man/http.1 b/extras/man/http.1 index 09e4237006..f0c49d8d65 100644 --- a/extras/man/http.1 +++ b/extras/man/http.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/cli/definition.py by extras/scripts/generate_man_pages.py. -.TH http 1 "2024-07-10" "HTTPie 3.2.3" "HTTPie Manual" +.TH http 1 "2024-07-10" "HTTPie 3.2.4" "HTTPie Manual" .SH NAME http .SH SYNOPSIS diff --git a/extras/man/httpie.1 b/extras/man/httpie.1 index ba269b1acf..eb4028d753 100644 --- a/extras/man/httpie.1 +++ b/extras/man/httpie.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/manager/cli.py by extras/scripts/generate_man_pages.py. -.TH httpie 1 "2024-07-10" "HTTPie 3.2.3" "HTTPie Manual" +.TH httpie 1 "2024-07-10" "HTTPie 3.2.4" "HTTPie Manual" .SH NAME httpie .SH SYNOPSIS diff --git a/extras/man/https.1 b/extras/man/https.1 index dfb1b018ad..5158c63d31 100644 --- a/extras/man/https.1 +++ b/extras/man/https.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/cli/definition.py by extras/scripts/generate_man_pages.py. -.TH https 1 "2024-07-10" "HTTPie 3.2.3" "HTTPie Manual" +.TH https 1 "2024-07-10" "HTTPie 3.2.4" "HTTPie Manual" .SH NAME https .SH SYNOPSIS diff --git a/httpie/__init__.py b/httpie/__init__.py index d67c919042..a4dded9ced 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -3,7 +3,7 @@ """ -__version__ = '3.2.3' -__date__ = '2024-07-10' +__version__ = '3.2.4' +__date__ = '2024-11-01' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 2843b874c60bda30e7393f0500353b6fe8451542 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:35:35 -0700 Subject: [PATCH 1181/1182] [automated] Update generated content (#1607) Co-authored-by: jkbrzt --- extras/man/http.1 | 2 +- extras/man/httpie.1 | 2 +- extras/man/https.1 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extras/man/http.1 b/extras/man/http.1 index f0c49d8d65..889e82b31d 100644 --- a/extras/man/http.1 +++ b/extras/man/http.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/cli/definition.py by extras/scripts/generate_man_pages.py. -.TH http 1 "2024-07-10" "HTTPie 3.2.4" "HTTPie Manual" +.TH http 1 "2024-11-01" "HTTPie 3.2.4" "HTTPie Manual" .SH NAME http .SH SYNOPSIS diff --git a/extras/man/httpie.1 b/extras/man/httpie.1 index eb4028d753..b44172967b 100644 --- a/extras/man/httpie.1 +++ b/extras/man/httpie.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/manager/cli.py by extras/scripts/generate_man_pages.py. -.TH httpie 1 "2024-07-10" "HTTPie 3.2.4" "HTTPie Manual" +.TH httpie 1 "2024-11-01" "HTTPie 3.2.4" "HTTPie Manual" .SH NAME httpie .SH SYNOPSIS diff --git a/extras/man/https.1 b/extras/man/https.1 index 5158c63d31..14434b9a71 100644 --- a/extras/man/https.1 +++ b/extras/man/https.1 @@ -1,5 +1,5 @@ .\" This file is auto-generated from the parser declaration in httpie/cli/definition.py by extras/scripts/generate_man_pages.py. -.TH https 1 "2024-07-10" "HTTPie 3.2.4" "HTTPie Manual" +.TH https 1 "2024-11-01" "HTTPie 3.2.4" "HTTPie Manual" .SH NAME https .SH SYNOPSIS From 5b604c37c6c67e18e7c3e9aee6c88a8c22b98345 Mon Sep 17 00:00:00 2001 From: ash Date: Tue, 17 Dec 2024 17:30:35 +0000 Subject: [PATCH 1182/1182] Fix `https` behaviour in fish (#1611) Using the name `https` to invoke HTTPie should make HTTPie default to the https:// scheme, but using a fish function to replace invocations of `https` with invocations of `http` defeats this behaviour. Instead, just tell fish to complete `https` in the same way as `http`. --- extras/httpie-completion.fish | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/extras/httpie-completion.fish b/extras/httpie-completion.fish index 102399a4ec..c0cfc20ad9 100644 --- a/extras/httpie-completion.fish +++ b/extras/httpie-completion.fish @@ -116,6 +116,4 @@ complete -c http -l debug -d 'Show debugging output' # Alias for https to http -function https --wraps http - http $argv; -end +complete -c https -w http

      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 Date: Tue, 6 Nov 2018 11:37:33 +0100 Subject: [PATCH 0389/1182] Brew --- extras/httpie.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/extras/httpie.rb b/extras/httpie.rb index 1258b37827..a943284c78 100644 --- a/extras/httpie.rb +++ b/extras/httpie.rb @@ -9,12 +9,19 @@ class Httpie < Formula desc "User-friendly cURL replacement (command-line HTTP client)" homepage "https://httpie.org/" - head "https://github.com/jakubroztocil/httpie.git" - url "https://files.pythonhosted.org/packages/44/ee/7177b743400d7f82a69bf30cb3c24ea4bb1f4aea68878bc540f732bf4940/httpie-1.0.0.tar.gz" sha256 "1650342d2eca2622092196bf106ab8f68ea2dbb2ed265d37191185618e159a25" + head "https://github.com/jakubroztocil/httpie.git" - depends_on "python" + bottle do + cellar :any_skip_relocation + sha256 "7e9db255e324dd63b66106ca62ed7e4e81f6634c624dec3ff49c293aba1072a6" => :mojave + sha256 "437504a11416284b17d3a801c267d0fd5e15416f38cff3abf7ed99b096b4828a" => :high_sierra + sha256 "10b25fc787076719b1f1f9c242c5e9d872ebd1c7a6d83e6f1af983a17cd8ca55" => :sierra + sha256 "1bd35480d1ef401bdad9c322e7c1624aefc9b5056530ab990e327d0bc397e4fb" => :el_capitan + end + + depends_on "python" ["3.6.5_1"] resource "pygments" do url "https://files.pythonhosted.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz" @@ -51,7 +58,6 @@ class Httpie < Formula sha256 "3fe52c55890a248676fd69dc9e3c4e811718b777834bcaab7a8125cf9deac672" end - def install virtualenv_install_with_resources end From f6a19cf55264a9fa1c5c32f11a2ac945cb9bb641 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 8 Mar 2017 09:49:51 +0100 Subject: [PATCH 0390/1182] Don't call external URLs from tests #729 --- CHANGELOG.rst | 6 ++++++ httpie/__init__.py | 2 +- tests/test_binary.py | 27 +++++++++++---------------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2dc482c78c..f889302566 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,12 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. +`1.0.1`_ (2018-11-14) +------------------------- + +* Removed external URL calls from tests. + + `1.0.0`_ (2018-11-02) ------------------------- diff --git a/httpie/__init__.py b/httpie/__init__.py index 36bb65955d..90dc63beff 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -2,7 +2,7 @@ HTTPie - a CLI, cURL-like tool for humans. """ -__version__ = '1.0.0' +__version__ = '1.0.1' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' diff --git a/tests/test_binary.py b/tests/test_binary.py index cb6da2e85d..2adc2500be 100644 --- a/tests/test_binary.py +++ b/tests/test_binary.py @@ -1,6 +1,7 @@ """Tests for dealing with binary request and response data.""" +import requests + 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 MockEnvironment, http @@ -31,25 +32,19 @@ def test_binary_file_form(self, httpbin): class TestBinaryResponseData: - url = 'http://www.google.com/favicon.ico' - - @property - def bindata(self): - if not hasattr(self, '_bindata'): - self._bindata = urlopen(self.url).read() - return self._bindata - def test_binary_suppresses_when_terminal(self): - r = http('GET', self.url) + def test_binary_suppresses_when_terminal(self, httpbin): + r = http('GET', httpbin + '/bytes/1024') assert BINARY_SUPPRESSED_NOTICE.decode() in r - def test_binary_suppresses_when_not_terminal_but_pretty(self): + def test_binary_suppresses_when_not_terminal_but_pretty(self, httpbin): env = MockEnvironment(stdin_isatty=True, stdout_isatty=False) - r = http('--pretty=all', 'GET', self.url, - env=env) + r = http('--pretty=all', 'GET', httpbin + '/bytes/1024', env=env) assert BINARY_SUPPRESSED_NOTICE.decode() in r - def test_binary_included_and_correct_when_suitable(self): + def test_binary_included_and_correct_when_suitable(self, httpbin): env = MockEnvironment(stdin_isatty=True, stdout_isatty=False) - r = http('GET', self.url, env=env) - assert r == self.bindata + url = httpbin + '/bytes/1024?seed=1' + r = http('GET', url, env=env) + expected = requests.get(url).content + assert r == expected From d5032ca859b763d94cf829e39691d5a02d7e2587 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 14 Nov 2018 11:45:57 +0100 Subject: [PATCH 0391/1182] Fix changelog --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f889302566..84459bb0cf 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -347,3 +347,4 @@ This project adheres to `Semantic Versioning `_. .. _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 +.. _1.0.1: https://github.com/jakubroztocil/httpie/compare/1.0.0...1.0.1 From d1407baf76d3cffabf91bf5c94a174325513b00d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 14 Nov 2018 13:06:10 +0100 Subject: [PATCH 0392/1182] Add `make pdf` --- Makefile | 15 +++++++++++++++ README.rst | 3 +++ 2 files changed, 18 insertions(+) diff --git a/Makefile b/Makefile index 402017a252..5ffd5c0a23 100644 --- a/Makefile +++ b/Makefile @@ -124,6 +124,21 @@ uninstall-all: uninstall-httpie - pip uninstall --yes -r $(REQUIREMENTS) +############################################################################### +# Docs +############################################################################### + +pdf: + # NOTE: rst2pdf needs to be installed manually and against a Python 2 + @echo "Converting README.rst to PDF…" + rst2pdf \ + --strip-elements-with-class=no-pdf \ + README.rst \ + -o README.pdf + @echo "Done" + @echo + + ############################################################################### # Utils ############################################################################### diff --git a/README.rst b/README.rst index bdb99f8b78..3e91a47b15 100644 --- a/README.rst +++ b/README.rst @@ -134,6 +134,9 @@ 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. + +.. class:: no-pdf + |unix_build| From b88e88d2e373e2113015cb96c5e6edce9d2f1a91 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 14 Nov 2018 16:10:08 +0100 Subject: [PATCH 0393/1182] Fix tests for installation with pyOpenSSL #729 --- tests/test_ssl.py | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 63bfd11783..ef274dd508 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -2,17 +2,31 @@ import pytest import pytest_httpbin.certs -from requests.exceptions import SSLError +import requests.exceptions from httpie import ExitStatus from httpie.input import SSL_VERSION_ARG_MAPPING -from utils import http, HTTP_OK, TESTS_ROOT +from utils import HTTP_OK, TESTS_ROOT, http + + +try: + # Handle OpenSSL errors, if installed. + # See + # noinspection PyUnresolvedReferences + import OpenSSL.SSL + ssl_errors = ( + requests.exceptions.SSLError, + OpenSSL.SSL.Error, + ) +except ImportError: + ssl_errors = ( + requests.exceptions.SSLError, + ) CLIENT_CERT = os.path.join(TESTS_ROOT, 'client_certs', 'client.crt') CLIENT_KEY = os.path.join(TESTS_ROOT, 'client_certs', 'client.key') CLIENT_PEM = os.path.join(TESTS_ROOT, 'client_certs', 'client.pem') - # FIXME: # We test against a local httpbin instance which uses a self-signed cert. # Requests without --verify= will fail with a verification error. @@ -28,7 +42,7 @@ def test_ssl_version(httpbin_secure, ssl_version): httpbin_secure + '/get' ) assert HTTP_OK in r - except SSLError as e: + except ssl_errors as e: if ssl_version == 'ssl3': # pytest-httpbin doesn't support ssl3 assert 'SSLV3_ALERT_HANDSHAKE_FAILURE' in str(e) @@ -57,12 +71,12 @@ def test_cert_file_not_found(self, httpbin_secure): assert 'No such file or directory' in r.stderr def test_cert_file_invalid(self, httpbin_secure): - with pytest.raises(SSLError): + with pytest.raises(ssl_errors): http(httpbin_secure + '/get', '--cert', __file__) def test_cert_ok_but_missing_key(self, httpbin_secure): - with pytest.raises(SSLError): + with pytest.raises(ssl_errors): http(httpbin_secure + '/get', '--cert', CLIENT_CERT) @@ -79,21 +93,23 @@ def test_verify_false_OK(self, httpbin_secure, verify_value): assert HTTP_OK in r def test_verify_custom_ca_bundle_path( - self, httpbin_secure_untrusted): + self, httpbin_secure_untrusted + ): r = http(httpbin_secure_untrusted + '/get', '--verify', CA_BUNDLE) assert HTTP_OK in r def test_self_signed_server_cert_by_default_raises_ssl_error( - self, - httpbin_secure_untrusted): - with pytest.raises(SSLError): + self, + httpbin_secure_untrusted + ): + with pytest.raises(ssl_errors): http(httpbin_secure_untrusted.url + '/get') def test_verify_custom_ca_bundle_invalid_path(self, httpbin_secure): # since 2.14.0 requests raises IOError - with pytest.raises((SSLError, IOError)): + with pytest.raises(ssl_errors + (IOError,)): http(httpbin_secure.url + '/get', '--verify', '/__not_found__') def test_verify_custom_ca_bundle_invalid_bundle(self, httpbin_secure): - with pytest.raises(SSLError): + with pytest.raises(ssl_errors): http(httpbin_secure.url + '/get', '--verify', __file__) From 3898129e9c4711c7b234da3ebc9fe3e12738abad Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 14 Nov 2018 16:21:47 +0100 Subject: [PATCH 0394/1182] Changelog --- CHANGELOG.rst | 7 +++++++ httpie/__init__.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 84459bb0cf..d1bdebb066 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,12 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. +`1.0.2-dev`_ (unreleased) +------------------------- + +* Fixed tests for installation with pyOpenSSL. + + `1.0.1`_ (2018-11-14) ------------------------- @@ -348,3 +354,4 @@ This project adheres to `Semantic Versioning `_. .. _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 .. _1.0.1: https://github.com/jakubroztocil/httpie/compare/1.0.0...1.0.1 +.. _1.0.2-dev: https://github.com/jakubroztocil/httpie/compare/1.0.1...master diff --git a/httpie/__init__.py b/httpie/__init__.py index 90dc63beff..61519196a5 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -2,7 +2,7 @@ HTTPie - a CLI, cURL-like tool for humans. """ -__version__ = '1.0.1' +__version__ = '1.0.2-dev' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 0eba037037936425e9b81291643bea43db5cc698 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 14 Nov 2018 16:36:00 +0100 Subject: [PATCH 0395/1182] v1.0.2 Close #729 --- CHANGELOG.rst | 17 ++++++++++++----- httpie/__init__.py | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d1bdebb066..39da325332 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,13 @@ This document records all notable changes to `HTTPie `_. This project adheres to `Semantic Versioning `_. -`1.0.2-dev`_ (unreleased) +`1.0.3-dev`_ (unreleased) +------------------------- + +* No changes yet. + + +`1.0.2`_ (2018-11-14) ------------------------- * Fixed tests for installation with pyOpenSSL. @@ -320,13 +326,13 @@ This project adheres to `Semantic Versioning `_. * Many improvements and bug fixes -`0.1`_ (2012-02-25) -------------------- +`0.1.0`_ (2012-02-25) +--------------------- * Initial public release -.. _`0.1`: https://github.com/jakubroztocil/httpie/commit/b966efa +.. _`0.1.0`: 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 @@ -354,4 +360,5 @@ This project adheres to `Semantic Versioning `_. .. _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 .. _1.0.1: https://github.com/jakubroztocil/httpie/compare/1.0.0...1.0.1 -.. _1.0.2-dev: https://github.com/jakubroztocil/httpie/compare/1.0.1...master +.. _1.0.2: https://github.com/jakubroztocil/httpie/compare/1.0.1...1.0.2 +.. _1.0.3-dev: https://github.com/jakubroztocil/httpie/compare/1.0.2...master diff --git a/httpie/__init__.py b/httpie/__init__.py index 61519196a5..fc4d597e83 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -2,7 +2,7 @@ HTTPie - a CLI, cURL-like tool for humans. """ -__version__ = '1.0.2-dev' +__version__ = '1.0.2' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From c591a3810dcbfe541aa17326c40bbce35444fcd2 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Wed, 14 Nov 2018 16:36:47 +0100 Subject: [PATCH 0396/1182] 1.0.3-dev --- httpie/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpie/__init__.py b/httpie/__init__.py index fc4d597e83..6ff7658c58 100644 --- a/httpie/__init__.py +++ b/httpie/__init__.py @@ -2,7 +2,7 @@ HTTPie - a CLI, cURL-like tool for humans. """ -__version__ = '1.0.2' +__version__ = '1.0.3-dev' __author__ = 'Jakub Roztocil' __licence__ = 'BSD' From 358342d1c915d6462a080a77aefbb20166d0bd5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Rozto=C4=8Dil?= Date: Wed, 9 Jan 2019 12:30:44 +0100 Subject: [PATCH 0397/1182] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 5b092812ea..c145597541 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright © 2012-2017 Jakub Roztocil +Copyright © 2012-2019 Jakub Roztocil Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From 933b438e5f05ef5a2774f13181d1c47f133cb846 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 3 Feb 2019 14:26:05 +0100 Subject: [PATCH 0398/1182] Bump dependency versions #742 --- extras/get-homebrew-formula-vars.py | 2 +- extras/httpie.rb | 35 ++++++++++++++--------------- setup.py | 4 ++-- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/extras/get-homebrew-formula-vars.py b/extras/get-homebrew-formula-vars.py index 2e28d3eb92..8d8521fef5 100755 --- a/extras/get-homebrew-formula-vars.py +++ b/extras/get-homebrew-formula-vars.py @@ -12,7 +12,7 @@ PACKAGES = [ 'httpie', - 'pygments', + 'Pygments', 'requests', 'certifi', 'urllib3', diff --git a/extras/httpie.rb b/extras/httpie.rb index a943284c78..5db5aff9fd 100644 --- a/extras/httpie.rb +++ b/extras/httpie.rb @@ -9,43 +9,42 @@ class Httpie < Formula desc "User-friendly cURL replacement (command-line HTTP client)" homepage "https://httpie.org/" - url "https://files.pythonhosted.org/packages/44/ee/7177b743400d7f82a69bf30cb3c24ea4bb1f4aea68878bc540f732bf4940/httpie-1.0.0.tar.gz" - sha256 "1650342d2eca2622092196bf106ab8f68ea2dbb2ed265d37191185618e159a25" + url "https://files.pythonhosted.org/packages/09/8d/581ef7bd9a09dc30b621638a4fa805a2073bbfb45fa06ed37f998f172419/httpie-1.0.2.tar.gz" + sha256 "fc676c85febdf3d80abc1ef6fa71ec3764d8b838806a7ae4e55e5e5aa014a2ab" head "https://github.com/jakubroztocil/httpie.git" bottle do cellar :any_skip_relocation - sha256 "7e9db255e324dd63b66106ca62ed7e4e81f6634c624dec3ff49c293aba1072a6" => :mojave - sha256 "437504a11416284b17d3a801c267d0fd5e15416f38cff3abf7ed99b096b4828a" => :high_sierra - sha256 "10b25fc787076719b1f1f9c242c5e9d872ebd1c7a6d83e6f1af983a17cd8ca55" => :sierra - sha256 "1bd35480d1ef401bdad9c322e7c1624aefc9b5056530ab990e327d0bc397e4fb" => :el_capitan + sha256 "158258be68ac93de13860be2bef02da6fd8b68aa24b2e6609bcff1ec3f93e7a0" => :mojave + sha256 "54352116b6fa2c3bd65f26136fdcb57986dbff8a52de5febf7aea59c126d29e1" => :high_sierra + sha256 "9cce71768fe388808e11b26d651b44a6b54219f5406845b4273b5099f5c1f76f" => :sierra end - depends_on "python" ["3.6.5_1"] + depends_on "python" - resource "pygments" do - url "https://files.pythonhosted.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz" - sha256 "dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc" + resource "Pygments" do + url "https://files.pythonhosted.org/packages/64/69/413708eaf3a64a6abb8972644e0f20891a55e621c6759e2c3f3891e05d63/Pygments-2.3.1.tar.gz" + sha256 "5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a" end resource "requests" do - url "https://files.pythonhosted.org/packages/97/10/92d25b93e9c266c94b76a5548f020f3f1dd0eb40649cb1993532c0af8f4c/requests-2.20.0.tar.gz" - sha256 "99dcfdaaeb17caf6e526f32b6a7b780461512ab3f1d992187801694cba42770c" + url "https://files.pythonhosted.org/packages/52/2c/514e4ac25da2b08ca5a464c50463682126385c4272c18193876e91f4bc38/requests-2.21.0.tar.gz" + sha256 "502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e" end resource "certifi" do - url "https://files.pythonhosted.org/packages/41/b6/4f0cefba47656583217acd6cd797bc2db1fede0d53090fdc28ad2c8e0716/certifi-2018.10.15.tar.gz" - sha256 "6d58c986d22b038c8c0df30d639f23a3e6d172a05c3583e766f4c0b785c0986a" + url "https://files.pythonhosted.org/packages/55/54/3ce77783acba5979ce16674fc98b1920d00b01d337cfaaf5db22543505ed/certifi-2018.11.29.tar.gz" + sha256 "47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7" end resource "urllib3" do - url "https://files.pythonhosted.org/packages/a5/74/05ffd00b4b5c08306939c485869f5dc40cbc27357195b0a98b18e4c48893/urllib3-1.24.tar.gz" - sha256 "41c3db2fc01e5b907288010dec72f9d0a74e37d6994e6eb56849f59fea2265ae" + url "https://files.pythonhosted.org/packages/b1/53/37d82ab391393565f2f831b8eedbffd57db5a718216f82f1a8b4d381a1c1/urllib3-1.24.1.tar.gz" + sha256 "de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" end resource "idna" do - url "https://files.pythonhosted.org/packages/65/c4/80f97e9c9628f3cac9b98bfca0402ede54e0563b56482e3e6e45c43c4935/idna-2.7.tar.gz" - sha256 "684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" + url "https://files.pythonhosted.org/packages/ad/13/eb56951b6f7950cadb579ca166e448ba77f9d24efc03edd7e55fa57d04b7/idna-2.8.tar.gz" + sha256 "c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407" end resource "chardet" do diff --git a/setup.py b/setup.py index de1433ef9d..3cb04c8b6b 100644 --- a/setup.py +++ b/setup.py @@ -35,8 +35,8 @@ def run_tests(self): install_requires = [ - 'requests>=2.18.4', - 'Pygments>=2.1.3' + 'requests>=2.21.0', + 'Pygments>=2.3.1' ] From 42ff2434001d07dfad2cb43cf63a0ed562b5933d Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 3 Feb 2019 14:58:23 +0100 Subject: [PATCH 0399/1182] Add `make brew-test` --- Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5ffd5c0a23..e2ab3cd187 100644 --- a/Makefile +++ b/Makefile @@ -144,5 +144,11 @@ pdf: ############################################################################### -homebrew-formula-vars: +brew-vars: extras/get-homebrew-formula-vars.py + +brew-test: + - brew uninstall httpie + brew install --build-from-source ./extras/httpie.rb + brew test httpie + brew audit --strict httpie From 69d010a11b77e801a644470f3fac224ae71a8200 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 3 Feb 2019 15:08:29 +0100 Subject: [PATCH 0400/1182] Brew cleanup --- Makefile | 7 +++---- extras/{get-homebrew-formula-vars.py => brew-deps.py} | 8 +++++--- 2 files changed, 8 insertions(+), 7 deletions(-) rename extras/{get-homebrew-formula-vars.py => brew-deps.py} (83%) diff --git a/Makefile b/Makefile index e2ab3cd187..c477abe827 100644 --- a/Makefile +++ b/Makefile @@ -140,12 +140,11 @@ pdf: ############################################################################### -# Utils +# Homebrew ############################################################################### - -brew-vars: - extras/get-homebrew-formula-vars.py +brew-deps: + extras/brew-deps.py brew-test: - brew uninstall httpie diff --git a/extras/get-homebrew-formula-vars.py b/extras/brew-deps.py similarity index 83% rename from extras/get-homebrew-formula-vars.py rename to extras/brew-deps.py index 8d8521fef5..c5aeed6d0f 100755 --- a/extras/get-homebrew-formula-vars.py +++ b/extras/brew-deps.py @@ -1,9 +1,11 @@ #!/usr/bin/env python3 """ -Generate URLs and file hashes to be included in the Homebrew formula -after a new release of HTTPie has been published on PyPi. +Generate Ruby code with URLs and file hashes for packages from PyPi +(i.e., httpie itself as well as its dependencies) to be included +in the Homebrew formula after a new release of HTTPie has been published +on PyPi. -https://github.com/Homebrew/homebrew-core/blob/master/Formula/httpie.rb + """ import hashlib From b7c8bf08002b48b5c82df61f5aec09a556f91b74 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Sun, 3 Feb 2019 15:27:17 +0100 Subject: [PATCH 0401/1182] Add animation by @loranallensmith --- README.rst | 11 +++++++++-- httpie.gif | Bin 0 -> 1043348 bytes 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 httpie.gif diff --git a/README.rst b/README.rst index 3e91a47b15..9bcca0bda3 100644 --- a/README.rst +++ b/README.rst @@ -11,6 +11,12 @@ generally interacting with HTTP servers. .. class:: no-web + .. image:: https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.gif + :alt: HTTPie in action + :width: 100% + :align: center + + .. image:: https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.png :alt: HTTPie compared to cURL :width: 100% @@ -1685,7 +1691,9 @@ See `CHANGELOG `_ by `Cláudia Delgado `_. +* `Animation `_ by `Allen Smith `_ of GitHub. + Licence @@ -1707,7 +1715,6 @@ have contributed. .. _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 .. |pypi| image:: https://img.shields.io/pypi/v/httpie.svg?style=flat-square&label=latest%20stable%20version diff --git a/httpie.gif b/httpie.gif new file mode 100644 index 0000000000000000000000000000000000000000..53e3cb84b30b9dcab3d45d2b6530ffb8a1b43c95 GIT binary patch literal 1043348 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 |{3;;o4bb~JPhGjz%_d=bBD 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%0AnZeL*Yda!-zhR<3yJrCY%m2UTxe$jgPU(Z9P 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 z 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