fix: force sorting of (sub)commands when displaying with --help

This commit is contained in:
Lance Edgar 2024-12-12 21:27:57 -06:00
parent ede2e049f1
commit 214e83b1cb
2 changed files with 48 additions and 0 deletions

View file

@ -32,6 +32,8 @@ from typing import List, Optional
import makefun
import typer
from click import Context
from typer.core import TyperGroup
from typing_extensions import Annotated
from wuttjamaican.util import load_entry_points
@ -39,6 +41,28 @@ from rattail.config import make_config
from rattail.progress import ConsoleProgress, SocketProgress
# nb. typer "by design" will not sort the commands listing, but we
# definitely want that (until someone says otherwise).
# nb. thanks to the following, for pointers
# https://stackoverflow.com/a/78351533
# https://github.com/fastapi/typer/issues/428#issuecomment-1238866548
class OrderCommands(TyperGroup):
"""
Custom base class for top-level Typer command.
This exists only to ensure the commands listing is sorted when
displayed with ``--help`` param, since Typer "by design" will not
sort them.
See also this `Typer doc
<https://typer.tiangolo.com/tutorial/commands/#sorting-of-the-commands>`_.
"""
def list_commands(self, ctx: Context):
""" """
return sorted(self.commands)
def make_typer(**kwargs):
"""
Create a Typer command instance, per Rattail conventions.
@ -49,6 +73,7 @@ def make_typer(**kwargs):
:returns: ``typer.Typer`` instance
"""
kwargs.setdefault('cls', OrderCommands)
kwargs.setdefault('callback', typer_callback)
return typer.Typer(**kwargs)

View file

@ -8,6 +8,29 @@ from wuttjamaican.testing import FileConfigTestCase
from rattail.commands import typer as mod
class TestOrderCommands(TestCase):
def test_list_commands(self):
cmd = mod.make_typer()
ctx = MagicMock()
@cmd.command()
def func_xyz(ctx):
pass
@cmd.command()
def func_abc(ctx):
pass
# TODO: ultimately i could not figure out how to inspect the
# typer cmd well enough to test anything, so had to just
# instantiate and mock the class under test
self.assertIs(cmd.info.cls, mod.OrderCommands)
inst = mod.OrderCommands()
with patch.object(inst, 'commands', new=['func_xyz', 'func_abc']):
self.assertEqual(inst.list_commands(ctx), ['func_abc', 'func_xyz'])
class TestMakeCliConfig(FileConfigTestCase):
def test_basic(self):