From 7114afa8999d03606bcfae3394de477bb93bf826 Mon Sep 17 00:00:00 2001 From: ivanharvard Date: Mon, 23 Feb 2026 14:21:45 -0500 Subject: [PATCH 1/3] added truncation to `Missing` output --- check50/_api.py | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/check50/_api.py b/check50/_api.py index 6ed1d4f..2887b70 100644 --- a/check50/_api.py +++ b/check50/_api.py @@ -427,12 +427,15 @@ class Missing(Failure): def __init__(self, missing_item, collection, help=None): if isinstance(collection, list): collection = _process_list(collection, _raw) - super().__init__(rationale=_("Did not find {} in {}").format(_raw(missing_item), _raw(collection)), help=help) + + truncated_collection = _truncate(collection, missing_item, preserve_sentinels=True) + + super().__init__(rationale=_("Did not find {} in {}").format(_raw(missing_item), _raw(truncated_collection)), help=help) if missing_item == EOF: missing_item = "EOF" - self.payload.update({"missing_item": str(missing_item), "collection": str(collection)}) + self.payload.update({"missing_item": str(missing_item), "collection": str(truncated_collection)}) class Mismatch(Failure): @@ -458,10 +461,8 @@ class Mismatch(Failure): """ def __init__(self, expected, actual, help=None): - def _safe_truncate(x, y): - return _truncate(x, y) if x not in (EOF, TIMEOUT) else x - - expected, actual = _safe_truncate(expected, actual), _safe_truncate(actual, expected) + expected, actual = (_truncate(expected, actual, preserve_sentinels=True), + _truncate(actual, expected, preserve_sentinels=True)) rationale = _("expected: {}\n actual: {}").format( _raw(expected), @@ -541,12 +542,32 @@ def _flatten_deep(x): # for "none" and every other case return [processor(item) for item in lst] -def _truncate(s, other): +def _truncate(s, other, preserve_sentinels=False): + """ + Truncates a string `s` to at most `config.truncate_len` characters, adding + "..." to the end, beginning, or both if truncation occurs. If + `config.dynamic_truncate` is True, truncation will look for the first index + at which `s` and `other` differ and center the truncated string around that + index. If `preserve_sentinels` is True, truncation will not be applied to + `s` if it is equal to the sentinels `EOF` or `TIMEOUT`. If `s` is a list, + we process it with `_process_list`, using its default arguments. + + :param s: The string to be truncated + :type s: str | list | EOF | TIMEOUT + :param other: The string to compare `s` to when determining where to truncate. + :type other: str | list | EOF | TIMEOUT + :param preserve_sentinels: Whether to preserve `EOF` and `TIMEOUT`. + :type preserve_sentinels: bool + :rtype: str | EOF | TIMEOUT + """ def normalize(obj): if isinstance(obj, list): return _process_list(obj, str) else: return str(obj) + + if s in (EOF, TIMEOUT) and preserve_sentinels: + return s s, other = normalize(s), normalize(other) From 27ac2a5383c4481129a0ec1f3e19e0c3e14b5dc1 Mon Sep 17 00:00:00 2001 From: ivanharvard Date: Wed, 25 Feb 2026 00:14:29 -0500 Subject: [PATCH 2/3] make preserve_sentinels true by default --- check50/_api.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/check50/_api.py b/check50/_api.py index 2887b70..cce0531 100644 --- a/check50/_api.py +++ b/check50/_api.py @@ -428,7 +428,7 @@ def __init__(self, missing_item, collection, help=None): if isinstance(collection, list): collection = _process_list(collection, _raw) - truncated_collection = _truncate(collection, missing_item, preserve_sentinels=True) + truncated_collection = _truncate(collection, missing_item) super().__init__(rationale=_("Did not find {} in {}").format(_raw(missing_item), _raw(truncated_collection)), help=help) @@ -461,8 +461,7 @@ class Mismatch(Failure): """ def __init__(self, expected, actual, help=None): - expected, actual = (_truncate(expected, actual, preserve_sentinels=True), - _truncate(actual, expected, preserve_sentinels=True)) + expected, actual = _truncate(expected, actual), _truncate(actual, expected) rationale = _("expected: {}\n actual: {}").format( _raw(expected), @@ -542,7 +541,7 @@ def _flatten_deep(x): # for "none" and every other case return [processor(item) for item in lst] -def _truncate(s, other, preserve_sentinels=False): +def _truncate(s, other, preserve_sentinels=True): """ Truncates a string `s` to at most `config.truncate_len` characters, adding "..." to the end, beginning, or both if truncation occurs. If From b696728dedfc955a6680bfeb8b8cc1b9cf0db3a4 Mon Sep 17 00:00:00 2001 From: ivanharvard Date: Wed, 25 Feb 2026 01:19:52 -0500 Subject: [PATCH 3/3] keep truth in json/html --- check50/_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check50/_api.py b/check50/_api.py index cce0531..18091fc 100644 --- a/check50/_api.py +++ b/check50/_api.py @@ -435,7 +435,7 @@ def __init__(self, missing_item, collection, help=None): if missing_item == EOF: missing_item = "EOF" - self.payload.update({"missing_item": str(missing_item), "collection": str(truncated_collection)}) + self.payload.update({"missing_item": str(missing_item), "collection": str(collection)}) class Mismatch(Failure):