Finish --quiet

This commit is contained in:
Jakub Roztocil 2020-08-15 15:25:05 +02:00
parent 2c7f24e3e5
commit 1aa1366f99
6 changed files with 112 additions and 130 deletions

2
.github/FUNDING.yml vendored
View File

@ -9,4 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl
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
custom:

View File

@ -10,8 +10,8 @@ This project adheres to `Semantic Versioning <https://semver.org/>`_.
-------------------------
* 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.
* Removed Tox testing entirely (`#943`_).
* Added a ``--quiet`` flag to enforce silent behaviour.
`2.2.0`_ (2020-06-18)

View File

@ -1156,12 +1156,34 @@ be printed via several options:
``--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`` Doesn't print anything. Overrides other output flags.
``--quiet, -q`` Don't print anything to ``stdout`` and ``stderr``.
================= =====================================================
If ``--quiet`` is used in conjuction with ``--output`` the flag is ignored
and ``stdout`` is still redirected. If ``--quiet`` is used with ``--download``
file is still downloaded as usual but ``stdout`` and ``stdin`` are redirected
to ``devnull``.
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 httpbin.org/put hello=world
Verbose output
--------------
``--verbose`` can often be useful for debugging the request and generating
documentation examples:
@ -1192,28 +1214,12 @@ documentation examples:
[…]
}
Quiet output
------------
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 httpbin.org/put hello=world
``--quiet`` redirects all output that would otherwise go to ``stdout``
and ``stderr`` (except for error messages) to ``/dev/null``.
This doesnt affect output to a file via ``--output`` or ``--download``.
Viewing intermediary requests/responses

View File

@ -35,7 +35,6 @@ class Environment:
stdout_encoding: str = None
stderr: IO = sys.stderr
stderr_isatty: bool = stderr.isatty()
_devnull = None
colors = 256
program_name: str = 'http'
if not is_windows:
@ -58,7 +57,7 @@ class Environment:
)
del colorama
def __init__(self, **kwargs):
def __init__(self, devnull=None, **kwargs):
"""
Use keyword arguments to overwrite
any of the class attributes for this instance.
@ -67,6 +66,10 @@ class Environment:
assert all(hasattr(type(self), attr) for attr in kwargs.keys())
self.__dict__.update(**kwargs)
# The original STDERR unaffected by --quieting.
self._orig_stderr = self.stderr
self._devnull = devnull
# Keyword arguments > stream.encoding > default utf8
if self.stdin and self.stdin_encoding is None:
self.stdin_encoding = getattr(
@ -122,4 +125,4 @@ class Environment:
def log_error(self, msg, level='error'):
assert level in ['error', 'warning']
self.stderr.write(f'\n{self.program_name}: {level}: {msg}\n\n')
self._orig_stderr.write(f'\n{self.program_name}: {level}: {msg}\n\n')

View File

@ -183,52 +183,11 @@ class TestDownloads:
# 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)
def test_download_with_quiet_flag(self, httpbin):
robots_txt = '/robots.txt'
expected_body = requests.get(httpbin + robots_txt).text
expected_filename = 'robots.txt'
env = MockEnvironment(stdin_isatty=True, stdout_isatty=True)
orig_cwd = os.getcwd()
os.chdir(tempfile.mkdtemp(prefix='httpie_download_quiet_test_'))
try:
assert os.listdir('.') == []
r = http('--quiet', '--download', httpbin + robots_txt, env=env)
assert os.listdir('.') == [expected_filename]
assert r.stderr == ''
assert env.devnull == env.stderr
assert env.devnull == env.stdout
with open(expected_filename, 'r') as f:
assert f.read() == expected_body
finally:
os.chdir(orig_cwd)
def test_download_with_quiet_and_output_flag(self, httpbin):
robots_txt = '/robots.txt'
expected_body = requests.get(httpbin + robots_txt).text
expected_filename = 'test.txt'
env = MockEnvironment(stdin_isatty=True, stdout_isatty=True)
orig_cwd = os.getcwd()
os.chdir(tempfile.mkdtemp(prefix='httpie_download_quiet_test_'))
try:
assert os.listdir('.') == []
r = http('--quiet',
'--download',
'--output=' + expected_filename,
httpbin + robots_txt,
env=env)
assert os.listdir('.') == [expected_filename]
assert r.stderr == ''
assert env.devnull == env.stderr
assert env.devnull == env.stdout
with open(expected_filename, 'r') as f:
assert f.read() == expected_body
finally:
os.chdir(orig_cwd)
with tempfile.TemporaryDirectory() as tmp_dirname:
os.chdir(tmp_dirname)
try:
assert os.listdir('.') == []
http('--download', httpbin.url + '/redirect/1')
assert os.listdir('.') == [expected_filename]
finally:
os.chdir(orig_cwd)

View File

@ -1,4 +1,6 @@
import argparse
from pathlib import Path
import mock
import json
import os
@ -40,69 +42,81 @@ class TestQuietFlag:
@pytest.mark.parametrize('argument_name', ['--quiet', '-q'])
def test_quiet(self, httpbin, argument_name):
env = MockEnvironment(stdin_isatty=True, stdout_isatty=True)
env = MockEnvironment(
stdin_isatty=True,
stdout_isatty=True,
devnull=io.BytesIO()
)
r = http(argument_name, 'GET', httpbin.url + '/get', env=env)
assert env.stdout == env.devnull
assert env.stderr == env.devnull
assert r.stderr == ''
assert str(r) == ''
@pytest.mark.parametrize('argument_name', ['--quiet', '-q'])
def test_quiet_correct_message(self, httpbin, argument_name):
sim_devnull = io.BytesIO()
env = MockEnvironment(stdin_isatty=True, stdout_isatty=True)
env.devnull = sim_devnull
r = http(argument_name, 'GET', httpbin.url + '/get', env=env)
assert env.stdout == env.devnull
assert env.stderr == env.devnull
assert r.stderr == ''
assert env.stdout is env.devnull
assert env.stderr is env.devnull
assert HTTP_OK in r.devnull
assert str(r) == ''
assert r == ''
assert r.stderr == ''
@mock.patch('httpie.cli.argtypes.AuthCredentials._getpass',
new=lambda self, prompt: 'password')
def test_quiet_password_prompt(self, httpbin):
""" Tests whether httpie still prompts for password when request
requires authetication and only username is provided"""
env = MockEnvironment(stdin_isatty=True, stdout_isatty=True)
env.devnull = io.BytesIO()
r = http('--quiet', '--auth', 'user', 'GET', httpbin.url + '/basic-auth/user/password', env=env)
def test_quiet_with_password_prompt(self, httpbin):
"""
Tests whether httpie still prompts for a password when request
requires authentication and only username is provided
"""
env = MockEnvironment(
stdin_isatty=True,
stdout_isatty=True,
devnull=io.BytesIO()
)
r = http(
'--quiet', '--auth', 'user', 'GET',
httpbin.url + '/basic-auth/user/password',
env=env
)
assert env.stdout is env.devnull
assert env.stderr is env.devnull
assert HTTP_OK in r.devnull
assert env.stdout == env.devnull
assert env.stderr == env.devnull
assert str(r) == ''
assert r == ''
assert r.stderr == ''
@pytest.mark.parametrize('argument_name', ['-h', '-b', '-v', '-p=hH'])
def test_quiet_flag_overrides_other_output_options(self, httpbin, argument_name):
def test_quiet_with_explicit_output_options(self, httpbin, argument_name):
env = MockEnvironment(stdin_isatty=True, stdout_isatty=True)
r = http('--quiet', argument_name, httpbin.url + '/GET', env=env)
assert env.stdout == env.devnull
assert env.stderr == env.devnull
assert str(r) == ''
r = http('--quiet', argument_name, httpbin.url + '/get', env=env)
assert env.stdout is env.devnull
assert env.stderr is env.devnull
assert r == ''
assert r.stderr == ''
def test_quiet_flag_with_output_redirection(self, httpbin):
robots_txt = '/robots.txt'
expected_body = requests.get(httpbin + robots_txt).text
expected_filename = 'test.txt'
env = MockEnvironment(stdin_isatty=True, stdout_isatty=True)
@pytest.mark.parametrize('with_download', [True, False])
def test_quiet_with_output_redirection(self, httpbin, with_download):
url = httpbin + '/robots.txt'
output_path = Path('output.txt')
env = MockEnvironment()
orig_cwd = os.getcwd()
os.chdir(tempfile.mkdtemp(prefix='httpie_download_quiet_test_'))
try:
assert os.listdir('.') == []
r = http('--quiet',
'--output=' + expected_filename,
httpbin + robots_txt,
env=env)
assert os.listdir('.') == [expected_filename]
assert r.stderr == ''
assert env.devnull == env.stderr
assert env.devnull != env.stdout
with open(expected_filename, 'r') as f:
assert f.read() == expected_body
finally:
os.chdir(orig_cwd)
output = requests.get(url).text
extra_args = ['--download'] if with_download else []
with tempfile.TemporaryDirectory() as tmp_dirname:
os.chdir(tmp_dirname)
try:
assert os.listdir('.') == []
r = http(
'--quiet',
'--output', str(output_path),
*extra_args,
url,
env=env
)
assert os.listdir('.') == [str(output_path)]
assert r == ''
assert r.stderr == ''
assert env.stderr is env.devnull
if with_download:
assert env.stdout is env.devnull
else:
assert env.stdout is not env.devnull # --output swaps stdout.
assert output_path.read_text() == output
finally:
os.chdir(orig_cwd)
class TestVerboseFlag: