@@ -427,12 +427,15 @@ class Missing(Failure):
427427 def __init__ (self , missing_item , collection , help = None ):
428428 if isinstance (collection , list ):
429429 collection = _process_list (collection , _raw )
430- super ().__init__ (rationale = _ ("Did not find {} in {}" ).format (_raw (missing_item ), _raw (collection )), help = help )
430+
431+ truncated_collection = _truncate (collection , missing_item , preserve_sentinels = True )
432+
433+ super ().__init__ (rationale = _ ("Did not find {} in {}" ).format (_raw (missing_item ), _raw (truncated_collection )), help = help )
431434
432435 if missing_item == EOF :
433436 missing_item = "EOF"
434437
435- self .payload .update ({"missing_item" : str (missing_item ), "collection" : str (collection )})
438+ self .payload .update ({"missing_item" : str (missing_item ), "collection" : str (truncated_collection )})
436439
437440
438441class Mismatch (Failure ):
@@ -458,10 +461,8 @@ class Mismatch(Failure):
458461 """
459462
460463 def __init__ (self , expected , actual , help = None ):
461- def _safe_truncate (x , y ):
462- return _truncate (x , y ) if x not in (EOF , TIMEOUT ) else x
463-
464- expected , actual = _safe_truncate (expected , actual ), _safe_truncate (actual , expected )
464+ expected , actual = (_truncate (expected , actual , preserve_sentinels = True ),
465+ _truncate (actual , expected , preserve_sentinels = True ))
465466
466467 rationale = _ ("expected: {}\n actual: {}" ).format (
467468 _raw (expected ),
@@ -541,12 +542,32 @@ def _flatten_deep(x):
541542 # for "none" and every other case
542543 return [processor (item ) for item in lst ]
543544
544- def _truncate (s , other ):
545+ def _truncate (s , other , preserve_sentinels = False ):
546+ """
547+ Truncates a string `s` to at most `config.truncate_len` characters, adding
548+ "..." to the end, beginning, or both if truncation occurs. If
549+ `config.dynamic_truncate` is True, truncation will look for the first index
550+ at which `s` and `other` differ and center the truncated string around that
551+ index. If `preserve_sentinels` is True, truncation will not be applied to
552+ `s` if it is equal to the sentinels `EOF` or `TIMEOUT`. If `s` is a list,
553+ we process it with `_process_list`, using its default arguments.
554+
555+ :param s: The string to be truncated
556+ :type s: str | list | EOF | TIMEOUT
557+ :param other: The string to compare `s` to when determining where to truncate.
558+ :type other: str | list | EOF | TIMEOUT
559+ :param preserve_sentinels: Whether to preserve `EOF` and `TIMEOUT`.
560+ :type preserve_sentinels: bool
561+ :rtype: str | EOF | TIMEOUT
562+ """
545563 def normalize (obj ):
546564 if isinstance (obj , list ):
547565 return _process_list (obj , str )
548566 else :
549567 return str (obj )
568+
569+ if s in (EOF , TIMEOUT ) and preserve_sentinels :
570+ return s
550571
551572 s , other = normalize (s ), normalize (other )
552573
0 commit comments