Skip to content

Commit ea18549

Browse files
committed
No longer change the level of any logger unless requested explicitly
Ref: pytest-dev#3013
1 parent 58e6452 commit ea18549

File tree

2 files changed

+35
-32
lines changed

2 files changed

+35
-32
lines changed

_pytest/logging.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -82,26 +82,29 @@ def add_option_ini(option, dest, default=None, type=None, **kwargs):
8282

8383

8484
@contextmanager
85-
def catching_logs(handler, formatter=None, level=logging.NOTSET):
85+
def catching_logs(handler, formatter=None, level=None):
8686
"""Context manager that prepares the whole logging machinery properly."""
8787
root_logger = logging.getLogger()
8888

8989
if formatter is not None:
9090
handler.setFormatter(formatter)
91-
handler.setLevel(level)
91+
if level is not None:
92+
handler.setLevel(level)
9293

9394
# Adding the same handler twice would confuse logging system.
9495
# Just don't do that.
9596
add_new_handler = handler not in root_logger.handlers
9697

9798
if add_new_handler:
9899
root_logger.addHandler(handler)
99-
orig_level = root_logger.level
100-
root_logger.setLevel(min(orig_level, level))
100+
if level is not None:
101+
orig_level = root_logger.level
102+
root_logger.setLevel(level)
101103
try:
102104
yield handler
103105
finally:
104-
root_logger.setLevel(orig_level)
106+
if level is not None:
107+
root_logger.setLevel(orig_level)
105108
if add_new_handler:
106109
root_logger.removeHandler(handler)
107110

@@ -159,14 +162,10 @@ def clear(self):
159162
def set_level(self, level, logger=None):
160163
"""Sets the level for capturing of logs.
161164
162-
By default, the level is set on the handler used to capture
163-
logs. Specify a logger name to instead set the level of any
164-
logger.
165+
:param int level: the logger to level.
166+
:param str logger: the logger to update the level. If not given, the root logger level is updated.
165167
"""
166-
if logger is None:
167-
logger = self.handler
168-
else:
169-
logger = logging.getLogger(logger)
168+
logger = logging.getLogger(logger)
170169
logger.setLevel(level)
171170

172171
@contextmanager
@@ -252,6 +251,7 @@ def __init__(self, config):
252251
self.formatter = logging.Formatter(
253252
get_option_ini(config, 'log_format'),
254253
get_option_ini(config, 'log_date_format'))
254+
self.log_level = get_actual_log_level(config, 'log_level')
255255

256256
if config.getini('log_cli'):
257257
log_cli_handler = logging.StreamHandler(sys.stderr)
@@ -262,8 +262,7 @@ def __init__(self, config):
262262
log_cli_formatter = logging.Formatter(
263263
log_cli_format,
264264
datefmt=log_cli_date_format)
265-
log_cli_level = get_actual_log_level(
266-
config, 'log_cli_level', 'log_level') or logging.WARNING
265+
log_cli_level = get_actual_log_level(config, 'log_cli_level', 'log_level')
267266
self.log_cli_handler = log_cli_handler # needed for a single unittest
268267
self.live_logs_context = catching_logs(log_cli_handler,
269268
formatter=log_cli_formatter,
@@ -274,8 +273,7 @@ def __init__(self, config):
274273

275274
log_file = get_option_ini(config, 'log_file')
276275
if log_file:
277-
self.log_file_level = get_actual_log_level(
278-
config, 'log_file_level') or logging.WARNING
276+
self.log_file_level = get_actual_log_level(config, 'log_file_level')
279277

280278
log_file_format = get_option_ini(
281279
config, 'log_file_format', 'log_format')
@@ -296,7 +294,7 @@ def __init__(self, config):
296294
def _runtest_for(self, item, when):
297295
"""Implements the internals of pytest_runtest_xxx() hook."""
298296
with catching_logs(LogCaptureHandler(),
299-
formatter=self.formatter) as log_handler:
297+
formatter=self.formatter, level=self.log_level) as log_handler:
300298
item.catch_log_handler = log_handler
301299
try:
302300
yield # run test

testing/logging/test_reporting.py

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def test_foo():
3535
logger.info('text going to logger')
3636
assert False
3737
''')
38-
result = testdir.runpytest()
38+
result = testdir.runpytest('--log-level=INFO')
3939
assert result.ret == 1
4040
result.stdout.fnmatch_lines(['*- Captured *log call -*',
4141
'*text going to logger*'])
@@ -58,7 +58,7 @@ def test_foo():
5858
logger.info('text going to logger from call')
5959
assert False
6060
''')
61-
result = testdir.runpytest()
61+
result = testdir.runpytest('--log-level=INFO')
6262
assert result.ret == 1
6363
result.stdout.fnmatch_lines(['*- Captured *log setup -*',
6464
'*text going to logger from setup*',
@@ -79,7 +79,7 @@ def teardown_function(function):
7979
logger.info('text going to logger from teardown')
8080
assert False
8181
''')
82-
result = testdir.runpytest()
82+
result = testdir.runpytest('--log-level=INFO')
8383
assert result.ret == 1
8484
result.stdout.fnmatch_lines(['*- Captured *log call -*',
8585
'*text going to logger from call*',
@@ -168,9 +168,9 @@ def test_log_cli_default_level(testdir):
168168
import logging
169169
def test_log_cli(request):
170170
plugin = request.config.pluginmanager.getplugin('logging-plugin')
171-
assert plugin.log_cli_handler.level == logging.WARNING
172-
logging.getLogger('catchlog').info("This log message won't be shown")
173-
logging.getLogger('catchlog').warning("This log message will be shown")
171+
assert plugin.log_cli_handler.level == logging.NOTSET
172+
logging.getLogger('catchlog').info("INFO message won't be shown")
173+
logging.getLogger('catchlog').warning("WARNING message will be shown")
174174
print('PASSED')
175175
''')
176176
testdir.makeini('''
@@ -185,15 +185,9 @@ def test_log_cli(request):
185185
'test_log_cli_default_level.py PASSED',
186186
])
187187
result.stderr.fnmatch_lines([
188-
"* This log message will be shown"
188+
'*WARNING message will be shown*',
189189
])
190-
for line in result.errlines:
191-
try:
192-
assert "This log message won't be shown" in line
193-
pytest.fail("A log message was shown and it shouldn't have been")
194-
except AssertionError:
195-
continue
196-
190+
assert "INFO message won't be shown" not in result.stderr.str()
197191
# make sure that that we get a '0' exit code for the testsuite
198192
assert result.ret == 0
199193

@@ -307,7 +301,7 @@ def test_log_file(request):
307301

308302
log_file = testdir.tmpdir.join('pytest.log').strpath
309303

310-
result = testdir.runpytest('-s', '--log-file={0}'.format(log_file))
304+
result = testdir.runpytest('-s', '--log-file={0}'.format(log_file), '--log-file-level=WARNING')
311305

312306
# fnmatch_lines does an assertion internally
313307
result.stdout.fnmatch_lines([
@@ -356,13 +350,24 @@ def test_log_file(request):
356350
assert "This log message won't be shown" not in contents
357351

358352

353+
def test_log_level_not_changed_by_default(testdir):
354+
testdir.makepyfile('''
355+
import logging
356+
def test_log_file():
357+
assert logging.getLogger().level == logging.WARNING
358+
''')
359+
result = testdir.runpytest('-s')
360+
result.stdout.fnmatch_lines('* 1 passed in *')
361+
362+
359363
def test_log_file_ini(testdir):
360364
log_file = testdir.tmpdir.join('pytest.log').strpath
361365

362366
testdir.makeini(
363367
"""
364368
[pytest]
365369
log_file={0}
370+
log_file_level=WARNING
366371
""".format(log_file))
367372
testdir.makepyfile('''
368373
import pytest

0 commit comments

Comments
 (0)