From 2be2e08bb28d4f2779ea41caa63d4e57f345804d Mon Sep 17 00:00:00 2001 From: Gerry Campion Date: Thu, 9 Jul 2026 11:20:02 -0400 Subject: [PATCH] Missed csv sort key change --- .../services/reporting/base_report_data.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/cdisc_rules_engine/services/reporting/base_report_data.py b/cdisc_rules_engine/services/reporting/base_report_data.py index 4d1b351fd..16a7aa25f 100644 --- a/cdisc_rules_engine/services/reporting/base_report_data.py +++ b/cdisc_rules_engine/services/reporting/base_report_data.py @@ -56,14 +56,30 @@ def process_values( processed_values.append(value) return processed_values + @staticmethod + def _csv_sort_key(row: list[str]) -> tuple: + """ + Sorts numeric fields numerically rather than lexicographically. + + Each field becomes (0, int_value) for pure integers or (1, str_value) + for everything else, so numbers sort before strings and 2 < 10. + """ + parts = [] + for field in row: + try: + parts.append((0, int(field), "")) + except ValueError: + parts.append((1, 0, field)) + return tuple(parts) + def get_csv_rows(self) -> tuple[list[str], list[list[str]]]: """ Return (header, sorted_rows) for the CSV output format. Each row is a list of string values matching the header columns. - Sorting is applied lexicographically by full column order. + Sorting is applied by full column order. """ header, rows = self._get_csv_rows() - return header, sorted(rows, key=lambda row: tuple(row)) + return header, sorted(rows, key=self._csv_sort_key) @abstractmethod def _get_csv_rows(self) -> tuple[list[str], list[list[str]]]: