Introduce a mode to suppress all warnings (#1283)

This commit is contained in:
Batuhan Taskaya 2022-03-07 15:40:35 +03:00 committed by GitHub
parent c901e70463
commit 55087a901e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 6 deletions

View File

@ -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)

View File

@ -230,9 +230,11 @@ class HTTPieArgumentParser(BaseHTTPieArgumentParser):
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.

View File

@ -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 .encoding import UTF8
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 @@ class Environment:
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 @@ class Environment:
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")

View File

@ -13,7 +13,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 .context import Environment, Levels
from .downloads import Downloader
from .models import (
RequestsMessageKind,
@ -221,7 +221,7 @@ def program(args: argparse.Namespace, env: Environment) -> ExitStatus:
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
))

View File

@ -5,6 +5,7 @@ from unittest import mock
import json
import os
import io
import warnings
from urllib.request import urlopen
import pytest
@ -90,6 +91,31 @@ class TestQuietFlag:
)
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 'Couldnt 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')

View File

@ -5,6 +5,7 @@ import sys
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 @@ class MockEnvironment(Environment):
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