From a3082437df1bccc89391b45d3f3a99ab51c2d812 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 1 Feb 2026 12:47:05 -0600 Subject: [PATCH] scripts: Relaxed lost results due to unstable by fields to a warning So it turns out this _can_ happen, without an in-script coding error. Consider the behavior of a script with overlapping by/field fields: $ cat test.csv a,b x,2 x,1 x,1 $ ./scripts/csv.py test.csv -ba -bb -fb During the first fold, rows 2 and 3 will contain b=1, but during the second fold they will have been merged, resulting in b=2. So, relaxing to a warning for now. Maybe the table renderer should be rewritten to avoid folding? (note diffing results may be tricky) --- scripts/code.py | 16 +++++++++++----- scripts/cov.py | 16 +++++++++++----- scripts/csv.py | 16 +++++++++++----- scripts/ctx.py | 16 +++++++++++----- scripts/data.py | 16 +++++++++++----- scripts/perf.py | 16 +++++++++++----- scripts/perfbd.py | 16 +++++++++++----- scripts/stack.py | 16 +++++++++++----- scripts/structs.py | 16 +++++++++++----- 9 files changed, 99 insertions(+), 45 deletions(-) diff --git a/scripts/code.py b/scripts/code.py index 13ca938f..8d68d1f0 100755 --- a/scripts/code.py +++ b/scripts/code.py @@ -653,11 +653,17 @@ def table(Result, results, diff_results=None, *, for k in by): r for r in diff_results or []} - # lost results? this only happens if we didn't fold by the same - # by field, which is an error and risks confusing results - assert len(table) == len(results) - if diff_results is not None: - assert len(diff_table) == len(diff_results) + # lost results? note this can happen if a by field references the + # same field as a field field, and the field field changes during + # folding + # + # it's not an _error_, but can lead to really confusing results, so + # at least warn + if (len(table) != len(results) + or (diff_results is not None + and len(diff_table) != len(diff_results))): + print("warning: by fields are unstable", + file=sys.stderr) # find compare entry if there is one if compare: diff --git a/scripts/cov.py b/scripts/cov.py index 25a23aae..a409cb05 100755 --- a/scripts/cov.py +++ b/scripts/cov.py @@ -516,11 +516,17 @@ def table(Result, results, diff_results=None, *, for k in by): r for r in diff_results or []} - # lost results? this only happens if we didn't fold by the same - # by field, which is an error and risks confusing results - assert len(table) == len(results) - if diff_results is not None: - assert len(diff_table) == len(diff_results) + # lost results? note this can happen if a by field references the + # same field as a field field, and the field field changes during + # folding + # + # it's not an _error_, but can lead to really confusing results, so + # at least warn + if (len(table) != len(results) + or (diff_results is not None + and len(diff_table) != len(diff_results))): + print("warning: by fields are unstable", + file=sys.stderr) # find compare entry if there is one if compare: diff --git a/scripts/csv.py b/scripts/csv.py index a4ae4c65..96dc4009 100755 --- a/scripts/csv.py +++ b/scripts/csv.py @@ -1975,11 +1975,17 @@ def table(Result, results, diff_results=None, *, for k in by): r for r in diff_results or []} - # lost results? this only happens if we didn't fold by the same - # by field, which is an error and risks confusing results - assert len(table) == len(results) - if diff_results is not None: - assert len(diff_table) == len(diff_results) + # lost results? note this can happen if a by field references the + # same field as a field field, and the field field changes during + # folding + # + # it's not an _error_, but can lead to really confusing results, so + # at least warn + if (len(table) != len(results) + or (diff_results is not None + and len(diff_table) != len(diff_results))): + print("warning: by fields are unstable", + file=sys.stderr) # find compare entry if there is one if compare: diff --git a/scripts/ctx.py b/scripts/ctx.py index b7f8a044..a4f41669 100755 --- a/scripts/ctx.py +++ b/scripts/ctx.py @@ -912,11 +912,17 @@ def table(Result, results, diff_results=None, *, for k in by): r for r in diff_results or []} - # lost results? this only happens if we didn't fold by the same - # by field, which is an error and risks confusing results - assert len(table) == len(results) - if diff_results is not None: - assert len(diff_table) == len(diff_results) + # lost results? note this can happen if a by field references the + # same field as a field field, and the field field changes during + # folding + # + # it's not an _error_, but can lead to really confusing results, so + # at least warn + if (len(table) != len(results) + or (diff_results is not None + and len(diff_table) != len(diff_results))): + print("warning: by fields are unstable", + file=sys.stderr) # find compare entry if there is one if compare: diff --git a/scripts/data.py b/scripts/data.py index c2c7096a..72a32198 100755 --- a/scripts/data.py +++ b/scripts/data.py @@ -653,11 +653,17 @@ def table(Result, results, diff_results=None, *, for k in by): r for r in diff_results or []} - # lost results? this only happens if we didn't fold by the same - # by field, which is an error and risks confusing results - assert len(table) == len(results) - if diff_results is not None: - assert len(diff_table) == len(diff_results) + # lost results? note this can happen if a by field references the + # same field as a field field, and the field field changes during + # folding + # + # it's not an _error_, but can lead to really confusing results, so + # at least warn + if (len(table) != len(results) + or (diff_results is not None + and len(diff_table) != len(diff_results))): + print("warning: by fields are unstable", + file=sys.stderr) # find compare entry if there is one if compare: diff --git a/scripts/perf.py b/scripts/perf.py index bdf03b99..3d462af4 100755 --- a/scripts/perf.py +++ b/scripts/perf.py @@ -1011,11 +1011,17 @@ def table(Result, results, diff_results=None, *, for k in by): r for r in diff_results or []} - # lost results? this only happens if we didn't fold by the same - # by field, which is an error and risks confusing results - assert len(table) == len(results) - if diff_results is not None: - assert len(diff_table) == len(diff_results) + # lost results? note this can happen if a by field references the + # same field as a field field, and the field field changes during + # folding + # + # it's not an _error_, but can lead to really confusing results, so + # at least warn + if (len(table) != len(results) + or (diff_results is not None + and len(diff_table) != len(diff_results))): + print("warning: by fields are unstable", + file=sys.stderr) # find compare entry if there is one if compare: diff --git a/scripts/perfbd.py b/scripts/perfbd.py index 4b231323..d5a2d615 100755 --- a/scripts/perfbd.py +++ b/scripts/perfbd.py @@ -985,11 +985,17 @@ def table(Result, results, diff_results=None, *, for k in by): r for r in diff_results or []} - # lost results? this only happens if we didn't fold by the same - # by field, which is an error and risks confusing results - assert len(table) == len(results) - if diff_results is not None: - assert len(diff_table) == len(diff_results) + # lost results? note this can happen if a by field references the + # same field as a field field, and the field field changes during + # folding + # + # it's not an _error_, but can lead to really confusing results, so + # at least warn + if (len(table) != len(results) + or (diff_results is not None + and len(diff_table) != len(diff_results))): + print("warning: by fields are unstable", + file=sys.stderr) # find compare entry if there is one if compare: diff --git a/scripts/stack.py b/scripts/stack.py index e1017901..bf283d17 100755 --- a/scripts/stack.py +++ b/scripts/stack.py @@ -653,11 +653,17 @@ def table(Result, results, diff_results=None, *, for k in by): r for r in diff_results or []} - # lost results? this only happens if we didn't fold by the same - # by field, which is an error and risks confusing results - assert len(table) == len(results) - if diff_results is not None: - assert len(diff_table) == len(diff_results) + # lost results? note this can happen if a by field references the + # same field as a field field, and the field field changes during + # folding + # + # it's not an _error_, but can lead to really confusing results, so + # at least warn + if (len(table) != len(results) + or (diff_results is not None + and len(diff_table) != len(diff_results))): + print("warning: by fields are unstable", + file=sys.stderr) # find compare entry if there is one if compare: diff --git a/scripts/structs.py b/scripts/structs.py index f28abb39..d43ba6de 100755 --- a/scripts/structs.py +++ b/scripts/structs.py @@ -801,11 +801,17 @@ def table(Result, results, diff_results=None, *, for k in by): r for r in diff_results or []} - # lost results? this only happens if we didn't fold by the same - # by field, which is an error and risks confusing results - assert len(table) == len(results) - if diff_results is not None: - assert len(diff_table) == len(diff_results) + # lost results? note this can happen if a by field references the + # same field as a field field, and the field field changes during + # folding + # + # it's not an _error_, but can lead to really confusing results, so + # at least warn + if (len(table) != len(results) + or (diff_results is not None + and len(diff_table) != len(diff_results))): + print("warning: by fields are unstable", + file=sys.stderr) # find compare entry if there is one if compare: