summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2021-02-10 12:26:18 +0000
committerGerrit Code Review <review@openstack.org>2021-02-10 12:26:18 +0000
commit421f20c9c8aa155d1c986aecd6af1504640c4596 (patch)
tree5927d275f1ee15e0430d336679159051549cb485
parent4d16d2bf6997fbbb5d160261eec3dc39425ff3bb (diff)
parent7798cb2e3786f803518afc9334e99b6de0a3cb15 (diff)
downloadcliff-421f20c9c8aa155d1c986aecd6af1504640c4596.tar.gz
Merge "Add '--sort-ascending', '--sort-descending' parameters"
-rw-r--r--cliff/lister.py67
-rw-r--r--cliff/tests/test_lister.py15
-rw-r--r--releasenotes/notes/add-Lister-sort-direction-5f34dba3c9743572.yaml21
3 files changed, 82 insertions, 21 deletions
diff --git a/cliff/lister.py b/cliff/lister.py
index dde0f2d..eed4875 100644
--- a/cliff/lister.py
+++ b/cliff/lister.py
@@ -10,8 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""Application base class for providing a list of data as output.
-"""
+"""Application base class for providing a list of data as output."""
+
import abc
import logging
@@ -19,8 +19,7 @@ from . import display
class Lister(display.DisplayCommandBase, metaclass=abc.ABCMeta):
- """Command base class for providing a list of data as output.
- """
+ """Command base class for providing a list of data as output."""
log = logging.getLogger(__name__)
@@ -37,13 +36,16 @@ class Lister(display.DisplayCommandBase, metaclass=abc.ABCMeta):
"""Whether sort procedure is performed by cliff itself.
Should be overridden (return False) when there is a need to implement
- custom sorting procedure or data is already sorted."""
+ custom sorting procedure or data is already sorted.
+ """
return True
@abc.abstractmethod
def take_action(self, parsed_args):
- """Return a tuple containing the column names and an iterable
- containing the data to be listed.
+ """Run command.
+
+ Return a tuple containing the column names and an iterable containing
+ the data to be listed.
"""
def get_parser(self, prog_name):
@@ -55,16 +57,36 @@ class Lister(display.DisplayCommandBase, metaclass=abc.ABCMeta):
default=[],
dest='sort_columns',
metavar='SORT_COLUMN',
- help=("specify the column(s) to sort the data (columns specified "
- "first have a priority, non-existing columns are ignored), "
- "can be repeated")
+ help=(
+ 'specify the column(s) to sort the data (columns specified '
+ 'first have a priority, non-existing columns are ignored), '
+ 'can be repeated'
+ ),
+ )
+ sort_dir_group = group.add_mutually_exclusive_group()
+ sort_dir_group.add_argument(
+ '--sort-ascending',
+ action='store_const',
+ dest='sort_direction',
+ const='asc',
+ help=('sort the column(s) in ascending order'),
+ )
+ sort_dir_group.add_argument(
+ '--sort-descending',
+ action='store_const',
+ dest='sort_direction',
+ const='desc',
+ help=('sort the column(s) in descending order'),
)
return parser
def produce_output(self, parsed_args, column_names, data):
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]
+ indexes = [
+ column_names.index(c) for c in parsed_args.sort_columns
+ if c in column_names
+ ]
+ reverse = parsed_args.sort_direction == 'desc'
for index in indexes[::-1]:
try:
# We need to handle unset values (i.e. None) so we sort on
@@ -76,6 +98,7 @@ class Lister(display.DisplayCommandBase, metaclass=abc.ABCMeta):
# the same, i.e. both None or both not-None
data = sorted(
data, key=lambda k: (k[index] is None, k[index]),
+ reverse=reverse,
)
except TypeError:
# Simply log and then ignore this; sorting is best effort
@@ -84,18 +107,20 @@ class Lister(display.DisplayCommandBase, metaclass=abc.ABCMeta):
parsed_args.sort_columns[index],
)
- (columns_to_include, selector) = self._generate_columns_and_selector(
- parsed_args, column_names)
+ columns_to_include, selector = self._generate_columns_and_selector(
+ parsed_args, column_names,
+ )
if selector:
# Generator expression to only return the parts of a row
# of data that the user has expressed interest in
# seeing. We have to convert the compress() output to a
# list so the table formatter can ask for its length.
- data = (list(self._compress_iterable(row, selector))
- for row in data)
- self.formatter.emit_list(columns_to_include,
- data,
- self.app.stdout,
- parsed_args,
- )
+ data = (
+ list(self._compress_iterable(row, selector)) for row in data
+ )
+
+ self.formatter.emit_list(
+ columns_to_include, data, self.app.stdout, parsed_args,
+ )
+
return 0
diff --git a/cliff/tests/test_lister.py b/cliff/tests/test_lister.py
index 7fc7222..5dfa69a 100644
--- a/cliff/tests/test_lister.py
+++ b/cliff/tests/test_lister.py
@@ -106,6 +106,21 @@ class TestLister(base.TestBase):
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(), [])
+ parsed_args = mock.Mock()
+ parsed_args.columns = ('Col1', 'Col2')
+ parsed_args.formatter = 'test'
+ parsed_args.sort_columns = ['Col2', 'Col1']
+ parsed_args.sort_direction = 'desc'
+
+ test_lister.run(parsed_args)
+
+ f = test_lister._formatter_plugins['test']
+ args = f.args[0]
+ data = list(args[1])
+ self.assertEqual([['b', 'B'], ['c', 'A'], ['a', 'A']], data)
+
def test_sort_by_column_data_already_sorted(self):
test_lister = ExerciseListerCustomSort(mock.Mock(), [])
parsed_args = mock.Mock()
diff --git a/releasenotes/notes/add-Lister-sort-direction-5f34dba3c9743572.yaml b/releasenotes/notes/add-Lister-sort-direction-5f34dba3c9743572.yaml
new file mode 100644
index 0000000..219e20c
--- /dev/null
+++ b/releasenotes/notes/add-Lister-sort-direction-5f34dba3c9743572.yaml
@@ -0,0 +1,21 @@
+---
+features:
+ - |
+ The ``cliff.lister.Lister`` base class now implements ``--sort-ascending``
+ and ``--sort-descending`` options, which can be used to configure the sort
+ direction. For example::
+
+ $ hello-world list-users --sort-column email --sort-descending
+ +----------------+-----------------------------+
+ | Name | Email |
+ +----------------+-----------------------------+
+ | Charles Xavier | therealcharliex@example.com |
+ | Jim Hendrix | jim@example.com |
+ | John Doe | doe.john@example.com |
+ | Alice Baker | abaker@example.com |
+ +----------------+-----------------------------+
+upgrade:
+ - |
+ ``cliff.lister.Lister`` implementations that override the
+ ``need_sort_by_cliff`` property should now consider the
+ ``--sort-ascending`` and ``--sort-descending`` options.