Normalize sort column names

Make --sort-column consistent with --column by normalizing case,
whitespace, and spaces in requested column names. Preserve exact-match
priority when normalized column names are ambiguous.

Closes-bug: #2168826
Change-Id: I9c6a93caa50df47f237b100b5a359c7bacba685c
Signed-off-by: t.hosseini <taaahaaa75@gmail.com>
This commit is contained in:
t.hosseini committed 2026-09-29 10:19:49 +03:30
1 parent 89efc71e36
commit 7b8e5dd270
4 files changed
+92 -10

No files matched your search

+10 -5
View File
@@ -135,12 +135,13 @@ class DisplayCommandBase(
if not parsed_args.columns:
return list(column_names), None
def normalize_column(column_name: str) -> str:
return column_name.lower().strip().replace(' ', '_')
requested_columns = [normalize_column(c) for c in parsed_args.columns]
requested_columns = [
self._normalize_column_name(c) for c in parsed_args.columns
]
columns_to_include = [
c for c in column_names if normalize_column(c) in requested_columns
c
for c in column_names
if self._normalize_column_name(c) in requested_columns
]
if not columns_to_include:
raise ValueError(
@@ -152,6 +153,10 @@ class DisplayCommandBase(
selector = [(c in columns_to_include) for c in column_names]
return columns_to_include, selector
@staticmethod
def _normalize_column_name(column_name: str) -> str:
return column_name.lower().strip().replace(' ', '_')
def run(self, parsed_args: argparse.Namespace) -> int:
parsed_args = self._run_before_hooks(parsed_args)
formatter = self._formatter_plugins[parsed_args.formatter].obj
+15 -5
View File
@@ -69,7 +69,8 @@ class Lister(
help=(
'specify the column(s) to sort the data (columns specified '
'first have a priority, non-existing columns are ignored), '
'can be repeated'
'column names are case-insensitive and accept underscores '
'for spaces, can be repeated'
),
)
sort_dir_group = group.add_mutually_exclusive_group()
@@ -96,11 +97,20 @@ class Lister(
data: Iterable[Sequence[Any]],
) -> int:
if parsed_args.sort_columns and self.need_sort_by_cliff:
indexes = [
column_names.index(c)
for c in parsed_args.sort_columns
if c in column_names
normalized_column_names = [
self._normalize_column_name(c) for c in column_names
]
indexes = []
for column in parsed_args.sort_columns:
if column in column_names:
indexes.append(column_names.index(column))
continue
normalized_column = self._normalize_column_name(column)
if normalized_column in normalized_column_names:
indexes.append(
normalized_column_names.index(normalized_column)
)
reverse = parsed_args.sort_direction == 'desc'
for index in indexes[::-1]:
try:
+60
View File
@@ -118,6 +118,66 @@ class TestLister(base.TestBase):
data = list(args[1])
self.assertEqual([['a', 'A'], ['c', 'A'], ['b', 'B']], data)
def test_sort_by_column_normalized(self):
test_lister = ExerciseLister(mock.Mock(), None)
parsed_args = mock.Mock()
parsed_args.columns = ('Col1', 'Col2')
parsed_args.formatter = 'test'
parsed_args.sort_columns = ['col2', 'COL1']
test_lister.run(parsed_args)
f = test_lister._formatter_plugins['test']
assert isinstance(f, FauxFormatter)
args = f.args[0]
data = list(args[1])
self.assertEqual([['a', 'A'], ['c', 'A'], ['b', 'B']], data)
def test_sort_by_column_normalized_spaces(self):
test_lister = ExerciseLister(mock.Mock(), None)
parsed_args = mock.Mock()
parsed_args.columns = ('Column One', 'Column Two')
parsed_args.formatter = 'test'
parsed_args.sort_columns = ['column_two', 'column_one']
test_lister.run(parsed_args)
f = test_lister._formatter_plugins['test']
assert isinstance(f, FauxFormatter)
args = f.args[0]
data = list(args[1])
self.assertEqual([['a', 'A'], ['c', 'A'], ['b', 'B']], data)
def test_sort_by_column_normalized_whitespace(self):
test_lister = ExerciseLister(mock.Mock(), None)
parsed_args = mock.Mock()
parsed_args.columns = ('Column One', 'Column Two')
parsed_args.formatter = 'test'
parsed_args.sort_columns = [' column_two ']
test_lister.run(parsed_args)
f = test_lister._formatter_plugins['test']
assert isinstance(f, FauxFormatter)
args = f.args[0]
data = list(args[1])
self.assertEqual([['a', 'A'], ['c', 'A'], ['b', 'B']], data)
def test_sort_by_column_exact_match_takes_priority(self):
test_lister = ExerciseLister(mock.Mock(), None)
parsed_args = mock.Mock()
parsed_args.columns = ('Column One', 'column_one')
parsed_args.formatter = 'test'
parsed_args.sort_columns = ['column_one']
test_lister.run(parsed_args)
f = test_lister._formatter_plugins['test']
assert isinstance(f, FauxFormatter)
args = f.args[0]
data = list(args[1])
self.assertEqual([['a', 'A'], ['c', 'A'], ['b', 'B']], data)
def test_sort_by_column_reverse_order(self):
test_lister = ExerciseLister(mock.Mock(), None)
parsed_args = mock.Mock()
@@ -0,0 +1,7 @@
---
fixes:
- |
Values passed to ``--sort-column`` are now normalized in the same way as
values passed to ``--column``. Sorting is therefore case-insensitive and
accepts underscores in place of spaces in column names, including leading
or trailing whitespace around the requested name.