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] 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 7f4dd754..d926e0b1 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 38761344..e25ad930 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 f6a8c0e6..6ebb50c5 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -497,12 +497,14 @@ output_options.add_argument( 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 c3567219..44b3f5c5 100644 --- a/httpie/core.py +++ b/httpie/core.py @@ -185,7 +185,7 @@ def program(args: argparse.Namespace, env: Environment) -> ExitStatus: 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 de0e76f6..36072b6f 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 @@ class TestQuietFlag: ) 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 @@ class TestQuietFlag: 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 @@ class TestQuietFlag: 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 @@ class TestQuietFlag: try: assert os.listdir('.') == [] r = http( - '--quiet', + *quiet_flags, '--output', str(output_path), *extra_args, url, @@ -142,7 +161,7 @@ class TestVerboseFlag: 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