@@ -1380,19 +1380,24 @@ def _log(self, *args) -> None:
1380
1380
def _log_text (self ) -> str :
1381
1381
return "\n " .join (self ._log_output )
1382
1382
1383
- def fnmatch_lines (self , lines2 : Sequence [str ]) -> None :
1383
+ def fnmatch_lines (
1384
+ self , lines2 : Sequence [str ], * , consecutive : bool = False
1385
+ ) -> None :
1384
1386
"""Check lines exist in the output (using :func:`python:fnmatch.fnmatch`).
1385
1387
1386
1388
The argument is a list of lines which have to match and can use glob
1387
1389
wildcards. If they do not match a pytest.fail() is called. The
1388
1390
matches and non-matches are also shown as part of the error message.
1389
1391
1390
1392
:param lines2: string patterns to match.
1393
+ :param consecutive: match lines consecutive?
1391
1394
"""
1392
1395
__tracebackhide__ = True
1393
- self ._match_lines (lines2 , fnmatch , "fnmatch" )
1396
+ self ._match_lines (lines2 , fnmatch , "fnmatch" , consecutive = consecutive )
1394
1397
1395
- def re_match_lines (self , lines2 : Sequence [str ]) -> None :
1398
+ def re_match_lines (
1399
+ self , lines2 : Sequence [str ], * , consecutive : bool = False
1400
+ ) -> None :
1396
1401
"""Check lines exist in the output (using :func:`python:re.match`).
1397
1402
1398
1403
The argument is a list of lines which have to match using ``re.match``.
@@ -1401,17 +1406,23 @@ def re_match_lines(self, lines2: Sequence[str]) -> None:
1401
1406
The matches and non-matches are also shown as part of the error message.
1402
1407
1403
1408
:param lines2: string patterns to match.
1409
+ :param consecutive: match lines consecutively?
1404
1410
"""
1405
1411
__tracebackhide__ = True
1406
1412
self ._match_lines (
1407
- lines2 , lambda name , pat : bool (re .match (pat , name )), "re.match"
1413
+ lines2 ,
1414
+ lambda name , pat : bool (re .match (pat , name )),
1415
+ "re.match" ,
1416
+ consecutive = consecutive ,
1408
1417
)
1409
1418
1410
1419
def _match_lines (
1411
1420
self ,
1412
1421
lines2 : Sequence [str ],
1413
1422
match_func : Callable [[str , str ], bool ],
1414
1423
match_nickname : str ,
1424
+ * ,
1425
+ consecutive : bool = False
1415
1426
) -> None :
1416
1427
"""Underlying implementation of ``fnmatch_lines`` and ``re_match_lines``.
1417
1428
@@ -1422,6 +1433,7 @@ def _match_lines(
1422
1433
pattern
1423
1434
:param str match_nickname: the nickname for the match function that
1424
1435
will be logged to stdout when a match occurs
1436
+ :param consecutive: match lines consecutively?
1425
1437
"""
1426
1438
if not isinstance (lines2 , collections .abc .Sequence ):
1427
1439
raise TypeError ("invalid type for lines2: {}" .format (type (lines2 ).__name__ ))
@@ -1431,20 +1443,30 @@ def _match_lines(
1431
1443
extralines = []
1432
1444
__tracebackhide__ = True
1433
1445
wnick = len (match_nickname ) + 1
1446
+ started = False
1434
1447
for line in lines2 :
1435
1448
nomatchprinted = False
1436
1449
while lines1 :
1437
1450
nextline = lines1 .pop (0 )
1438
1451
if line == nextline :
1439
1452
self ._log ("exact match:" , repr (line ))
1453
+ started = True
1440
1454
break
1441
1455
elif match_func (nextline , line ):
1442
1456
self ._log ("%s:" % match_nickname , repr (line ))
1443
1457
self ._log (
1444
1458
"{:>{width}}" .format ("with:" , width = wnick ), repr (nextline )
1445
1459
)
1460
+ started = True
1446
1461
break
1447
1462
else :
1463
+ if consecutive and started :
1464
+ msg = "no consecutive match: {!r}" .format (line )
1465
+ self ._log (msg )
1466
+ self ._log (
1467
+ "{:>{width}}" .format ("with:" , width = wnick ), repr (nextline )
1468
+ )
1469
+ self ._fail (msg )
1448
1470
if not nomatchprinted :
1449
1471
self ._log (
1450
1472
"{:>{width}}" .format ("nomatch:" , width = wnick ), repr (line )
0 commit comments