9
9
from py ._code .code import ReprFileLocation
10
10
11
11
import pytest
12
+ import re
12
13
13
14
from pytestqt .qt_compat import QtCore , QtTest , QApplication , QT_API , \
14
15
qInstallMsgHandler , QtDebugMsg , QtWarningMsg , QtCriticalMsg , QtFatalMsg
@@ -561,6 +562,9 @@ def pytest_addoption(parser):
561
562
'log level in which tests can fail: {0} (default: "{1}")'
562
563
.format (QtLoggingPlugin .LOG_FAIL_OPTIONS , default_log_fail ),
563
564
default = default_log_fail )
565
+ parser .addini ('qt_log_ignore' ,
566
+ 'list of regexes for messages that should not cause a tests '
567
+ 'to fails' , type = 'linelist' )
564
568
565
569
parser .addoption ('--no-qt-log' , dest = 'qt_log' , action = 'store_false' ,
566
570
default = True )
@@ -604,7 +608,7 @@ def qtlog(request):
604
608
if hasattr (request ._pyfuncitem , 'qt_log_capture' ):
605
609
return request ._pyfuncitem .qt_log_capture
606
610
else :
607
- return _QtMessageCapture () # pragma: no cover
611
+ return _QtMessageCapture ([] ) # pragma: no cover
608
612
609
613
610
614
class QtLoggingPlugin (object ):
@@ -619,7 +623,8 @@ def __init__(self, config):
619
623
self .config = config
620
624
621
625
def pytest_runtest_setup (self , item ):
622
- item .qt_log_capture = _QtMessageCapture ()
626
+ item .qt_log_capture = _QtMessageCapture (
627
+ item .config .getini ('qt_log_ignore' ))
623
628
previous_handler = qInstallMsgHandler (item .qt_log_capture ._handle )
624
629
item .qt_previous_handler = previous_handler
625
630
@@ -630,8 +635,6 @@ def pytest_runtest_makereport(self, item, call):
630
635
outcome = yield
631
636
report = outcome .result
632
637
633
- log_format = self .config .getoption ('qt_log_format' )
634
-
635
638
m = item .get_marker ('qt_log_level_fail' )
636
639
if m :
637
640
log_fail_level = m .args [0 ]
@@ -641,21 +644,27 @@ def pytest_runtest_makereport(self, item, call):
641
644
642
645
if call .when == 'call' :
643
646
647
+ # make test fail if any records were captured which match
648
+ # log_fail_level
644
649
if log_fail_level != 'NO' and report .outcome != 'failed' :
645
650
for rec in item .qt_log_capture .records :
646
- if rec .matches_level (log_fail_level ):
651
+ if rec .matches_level (log_fail_level ) and not rec . ignored :
647
652
report .outcome = 'failed'
648
653
if report .longrepr is None :
649
654
report .longrepr = \
650
655
_QtLogLevelErrorRepr (item , log_fail_level )
651
656
break
652
657
658
+ # if test has failed, add recorded messages to its terminal
659
+ # representation
653
660
if not report .passed :
654
661
long_repr = getattr (report , 'longrepr' , None )
655
662
if hasattr (long_repr , 'addsection' ): # pragma: no cover
663
+ log_format = self .config .getoption ('qt_log_format' )
656
664
lines = []
657
665
for rec in item .qt_log_capture .records :
658
- lines .append (log_format .format (rec = rec ))
666
+ suffix = ' (IGNORED)' if rec .ignored else ''
667
+ lines .append (log_format .format (rec = rec ) + suffix )
659
668
if lines :
660
669
long_repr .addsection ('Captured Qt messages' ,
661
670
'\n ' .join (lines ))
@@ -670,11 +679,14 @@ class _QtMessageCapture(object):
670
679
Captures Qt messages when its `handle` method is installed using
671
680
qInstallMsgHandler, and stores them into `messages` attribute.
672
681
673
- :attr messages: list of Record named-tuples.
682
+ :attr _records: list of Record instances.
683
+ :attr _ignore_regexes: list of regexes (as strings) that define if a record
684
+ should be ignored.
674
685
"""
675
686
676
- def __init__ (self ):
687
+ def __init__ (self , ignore_regexes ):
677
688
self ._records = []
689
+ self ._ignore_regexes = ignore_regexes or []
678
690
679
691
def _handle (self , msg_type , message ):
680
692
"""
@@ -683,7 +695,14 @@ def _handle(self, msg_type, message):
683
695
"""
684
696
if isinstance (message , bytes ):
685
697
message = message .decode ('utf-8' , 'replace' )
686
- self ._records .append (Record (msg_type , message ))
698
+
699
+ ignored = False
700
+ for regex in self ._ignore_regexes :
701
+ if re .search (regex , message ) is not None :
702
+ ignored = True
703
+ break
704
+
705
+ self ._records .append (Record (msg_type , message , ignored ))
687
706
688
707
@property
689
708
def records (self ):
@@ -704,20 +723,24 @@ class Record(object):
704
723
type name similar to the logging package, for example ``DEBUG``,
705
724
``WARNING``, etc.
706
725
:attr datetime.datetime when: when the message was sent
726
+ :attr ignored: If this record matches a regex from the "qt_log_ignore"
727
+ option.
707
728
"""
708
729
709
- def __init__ (self , msg_type , message ):
730
+ def __init__ (self , msg_type , message , ignored ):
710
731
self ._type = msg_type
711
732
self ._message = message
712
733
self ._type_name = self ._get_msg_type_name (msg_type )
713
734
self ._log_type_name = self ._get_log_type_name (msg_type )
714
735
self ._when = datetime .datetime .now ()
736
+ self ._ignored = ignored
715
737
716
738
message = property (lambda self : self ._message )
717
739
type = property (lambda self : self ._type )
718
740
type_name = property (lambda self : self ._type_name )
719
741
log_type_name = property (lambda self : self ._log_type_name )
720
742
when = property (lambda self : self ._when )
743
+ ignored = property (lambda self : self ._ignored )
721
744
722
745
@classmethod
723
746
def _get_msg_type_name (cls , msg_type ):
@@ -751,11 +774,11 @@ def _get_log_type_name(cls, msg_type):
751
774
752
775
def matches_level (self , level ):
753
776
if level == 'DEBUG' :
754
- return self .log_type_name in set ([ 'DEBUG' , 'WARNING' , 'CRITICAL' ] )
777
+ return self .log_type_name in ( 'DEBUG' , 'WARNING' , 'CRITICAL' )
755
778
elif level == 'WARNING' :
756
- return self .log_type_name in set ([ 'WARNING' , 'CRITICAL' ] )
779
+ return self .log_type_name in ( 'WARNING' , 'CRITICAL' )
757
780
elif level == 'CRITICAL' :
758
- return self .log_type_name in set ([ 'CRITICAL' ] )
781
+ return self .log_type_name in ( 'CRITICAL' , )
759
782
else :
760
783
raise ValueError ('log_fail_level unknown: {0}' .format (level ))
761
784
0 commit comments