File cmd2-3.1.0-compat.patch of Package python-cliff

From 29fa87c0687063fdb3fd9c58e58c44aca7bce8a8 Mon Sep 17 00:00:00 2001
From: Stephen Finucane <sfinucan@redhat.com>
Date: Tue, 3 Mar 2026 12:10:54 +0000
Subject: [PATCH] Fix compatibility with cmd2 3.1.0+

cmd2 3.1.0 has removed the dependency on the stdlib cmd library [1]. For
our use cases, the largest change is that we no longer have the
'completenames' helper, which was defined in `cmd.Cmd` rather than
`cmd2.Cmd`. However, upon further inspection is seems this helper was
never actually used. It was not called directly in cmd2 2.x and was only
used in cmd in two locations: `Cmd.complete` [2] and `Cmd.complete_help`
[3]. cmd2 2.x entirely overrode the former [4] and deleted the latter,
meaning we were not actually using any of that code. Therefore we can
just delete the helper and any tests for same and suffer no ill effects.
To be safe though, we bump our cmd2 minimum to 3.0.0.

While here, we also need to fix some type hints to account for the cmd2
bump along with a related autopage bump.

[1] https://github.com/python-cmd2/cmd2/releases/tag/3.1.0
[2] https://github.com/python/cpython/blob/v3.10.20/Lib/cmd.py#L274
[3] https://github.com/python/cpython/blob/v3.10.20/Lib/cmd.py#L287
[4] https://github.com/python-cmd2/cmd2/blob/2.7.0/cmd2/cmd2.py#L2192-L2294
[5] https://github.com/python-cmd2/cmd2/blob/2.7.0/cmd2/cmd2.py#L3770-L3772

Change-Id: I75933ec1ffc2dc8d57d4105c5683892ddbf50bff
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
---
 cliff/formatters/table.py          |  2 +-
 cliff/interactive.py               | 16 +++-------------
 cliff/tests/base.py                |  2 +-
 cliff/tests/test_commandmanager.py |  8 ++++++++
 cliff/tests/test_interactive.py    | 28 ----------------------------
 requirements.txt                   |  2 +-
 6 files changed, 14 insertions(+), 44 deletions(-)

diff --git a/cliff/formatters/table.py b/cliff/formatters/table.py
index 6546a76c..771130fc 100644
--- a/cliff/formatters/table.py
+++ b/cliff/formatters/table.py
@@ -51,7 +51,7 @@ def _do_fit(fit_width: bool) -> bool:
 
 
 class TableFormatter(base.ListFormatter, base.SingleFormatter):
-    ALIGNMENTS = {
+    ALIGNMENTS: dict[type[int | str | float], ty.Literal['l', 'c', 'r']] = {
         int: 'r',
         str: 'l',
         float: 'r',
diff --git a/cliff/interactive.py b/cliff/interactive.py
index 607d3f81..0f65abb5 100644
--- a/cliff/interactive.py
+++ b/cliff/interactive.py
@@ -73,7 +73,7 @@ class InteractiveApp(cmd2.Cmd):
             parts.insert(0, line.command)
         return parts
 
-    def default(self, line: str) -> bool | None:  # type: ignore[override]
+    def default(self, line: str) -> bool | None:
         # Tie in the default command processor to
         # dispatch commands known to the command manager.
         # We send the message through our parent app,
@@ -87,17 +87,7 @@ class InteractiveApp(cmd2.Cmd):
             return bool(ret)
         return None
 
-    def completenames(self, text: str, *ignored: ty.Any) -> list[str]:
-        """Tab-completion for command prefix without completer delimiter.
-
-        This method returns cmd style and cliff style commands matching
-        provided command prefix (text).
-        """
-        completions = cmd2.Cmd.completenames(self, text)
-        completions += self._complete_prefix(text)
-        return completions
-
-    def completedefault(
+    def completedefault(  # type: ignore[override]
         self, text: str, line: str, begidx: int, endidx: int
     ) -> list[str]:
         """Default tab-completion for command prefix with completer delimiter.
@@ -146,7 +136,7 @@ class InteractiveApp(cmd2.Cmd):
         else:
             stdout = self.stdout
             try:
-                with autopage.argparse.help_pager(stdout) as paged_out:  # type: ignore
+                with autopage.argparse.help_pager(stdout) as paged_out:
                     self.stdout = paged_out
 
                     cmd2.Cmd.do_help(self, arg)  # type: ignore
diff --git a/cliff/tests/base.py b/cliff/tests/base.py
index cace1227..4e55fce1 100644
--- a/cliff/tests/base.py
+++ b/cliff/tests/base.py
@@ -11,7 +11,7 @@
 #  License for the specific language governing permissions and limitations
 #  under the License.
 
-import testtools  # type: ignore
+import testtools
 
 import fixtures
 
diff --git a/cliff/tests/test_commandmanager.py b/cliff/tests/test_commandmanager.py
index f17b5b70..53ff464d 100644
--- a/cliff/tests/test_commandmanager.py
+++ b/cliff/tests/test_commandmanager.py
@@ -30,6 +30,8 @@ class TestLookupAndFind(base.TestBase):
         ('three-words', {'argv': ['three', 'word', 'command']}),
     ]
 
+    argv: list[str]
+
     def test(self):
         mgr = utils.TestCommandManager(utils.TEST_NAMESPACE)
         cmd, name, remaining = mgr.find_command(self.argv)
@@ -45,6 +47,8 @@ class TestLookupWithRemainder(base.TestBase):
         ('three', {'argv': ['three', 'word', 'command', '--opt']}),
     ]
 
+    argv: list[str]
+
     def test(self):
         mgr = utils.TestCommandManager(utils.TEST_NAMESPACE)
         cmd, name, remaining = mgr.find_command(self.argv)
@@ -58,6 +62,8 @@ class TestFindInvalidCommand(base.TestBase):
         ('no-command-given', {'argv': ['-b']}),
     ]
 
+    argv: list[str]
+
     def test(self):
         mgr = utils.TestCommandManager(utils.TEST_NAMESPACE)
         try:
@@ -246,6 +252,8 @@ class TestLookupAndFindPartialName(base.TestBase):
         ('three-words', {'argv': ['t', 'w', 'c']}),
     ]
 
+    argv: list[str]
+
     def test(self):
         mgr = utils.TestCommandManager(utils.TEST_NAMESPACE)
         cmd, name, remaining = mgr.find_command(self.argv)
diff --git a/cliff/tests/test_interactive.py b/cliff/tests/test_interactive.py
index 2936f073..55645bdb 100644
--- a/cliff/tests/test_interactive.py
+++ b/cliff/tests/test_interactive.py
@@ -11,7 +11,6 @@
 #  License for the specific language governing permissions and limitations
 #  under the License.
 
-import cmd2
 
 from cliff import app
 from cliff.interactive import InteractiveApp
@@ -32,33 +31,6 @@ class TestInteractive(base.TestBase):
             errexit=errexit,
         )
 
-    def _test_completenames(self, expecteds, prefix):
-        app = self.make_interactive_app(False, 'hips', 'hippo', 'nonmatching')
-        self.assertEqual(
-            set(app.completenames(prefix, '', 0, 1)), set(expecteds)
-        )
-
-    def test_cmd2_completenames(self):
-        # cmd2.Cmd define do_help method
-        self._test_completenames(['help'], 'he')
-
-    def test_cliff_completenames(self):
-        self._test_completenames(['hips', 'hippo'], 'hip')
-
-    def test_no_completenames(self):
-        self._test_completenames([], 'taz')
-
-    def test_both_completenames(self):
-        # cmd2.Cmd define do_history method
-        # NOTE(dtroyer): Before release 0.7.0 do_hi was also defined so we need
-        #                to account for that in the list of possible responses.
-        #                Remove this check after cmd2 0.7.0 is the minimum
-        #                requirement.
-        if hasattr(cmd2.Cmd, "do_hi"):
-            self._test_completenames(['hi', 'history', 'hips', 'hippo'], 'hi')
-        else:
-            self._test_completenames(['history', 'hips', 'hippo'], 'hi')
-
     def _test_completedefault(self, expecteds, line, begidx):
         command_names = set(
             ['show file', 'show folder', 'show  long', 'list all']
diff --git a/requirements.txt b/requirements.txt
index 94ac040d..bc95ac51 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
 autopage>=0.4.0 # Apache 2.0
-cmd2>=1.0.0 # MIT
+cmd2>=3.0.0 # MIT
 PrettyTable>=0.7.2 # BSD
 stevedore>=5.6.0 # Apache-2.0
 PyYAML>=3.12 # MIT
openSUSE Build Service is sponsored by