[Lldb-commits] [lldb] Add the ability to define a Python based command that uses CommandObjectParsed (PR #70734)

via lldb-commits lldb-commits at lists.llvm.org
Mon Nov 13 17:40:57 PST 2023


github-actions[bot] wrote:

<!--LLVM CODE FORMAT COMMENT: {darker}-->


:warning: Python code formatter, darker found issues in your code. :warning:

<details>
<summary>
You can test this locally with the following command:
</summary>

``````````bash
darker --check --diff -r a41b149f481e2bcba24e81f208a1938247f040e0..aaeb653198f32386f8f7d38e4607fdd274f285d5 lldb/examples/python/parsed_cmd.py lldb/test/API/commands/command/script/add/TestAddParsedCommand.py lldb/test/API/commands/command/script/add/test_commands.py
``````````

</details>

<details>
<summary>
View the diff from darker here.
</summary>

``````````diff
--- test/API/commands/command/script/add/TestAddParsedCommand.py	2023-10-30 21:48:37.000000 +0000
+++ test/API/commands/command/script/add/TestAddParsedCommand.py	2023-11-14 01:40:47.807666 +0000
@@ -14,11 +14,11 @@
     NO_DEBUG_INFO_TESTCASE = True
 
     def test(self):
         self.pycmd_tests()
 
-    def check_help_options(self, cmd_name, opt_list, substrs = []):
+    def check_help_options(self, cmd_name, opt_list, substrs=[]):
         """
         Pass the command name in cmd_name and a vector of the short option, type & long option.
         This will append the checks for all the options and test "help command".
         Any strings already in substrs will also be checked.
         Any element in opt list that begin with "+" will be added to the checked strings as is.
@@ -28,119 +28,172 @@
                 substrs.append(elem[1:])
             else:
                 (short_opt, type, long_opt) = elem
                 substrs.append(f"-{short_opt} <{type}> ( --{long_opt} <{type}> )")
         print(f"Opt Vec\n{substrs}")
-        self.expect("help " + cmd_name, substrs = substrs)
+        self.expect("help " + cmd_name, substrs=substrs)
 
     def pycmd_tests(self):
         source_dir = self.getSourceDir()
         test_file_path = os.path.join(source_dir, "test_commands.py")
         self.runCmd("command script import " + test_file_path)
-        self.expect("help", substrs = ["no-args", "one-arg-no-opt", "two-args"])
+        self.expect("help", substrs=["no-args", "one-arg-no-opt", "two-args"])
 
         # Test that we did indeed add these commands as user commands:
 
         # This is the function to remove the custom commands in order to have a
         # clean slate for the next test case.
         def cleanup():
-            self.runCmd("command script delete no-args one-arg-no-opt two-args", check=False)
+            self.runCmd(
+                "command script delete no-args one-arg-no-opt two-args", check=False
+            )
 
         # Execute the cleanup function during test case tear down.
         self.addTearDownHook(cleanup)
 
         # First test the no arguments command.  Make sure the help is right:
-        no_arg_opts = [["b", "boolean", "bool-arg"],
-                       "+a boolean arg, defaults to True",
-                       ["d", "filename", "disk-file-name"],
-                       "+An on disk filename",
-                       ["e", "none", "enum-option"],
-                       "+An enum, doesn't actually do anything",
-                       "+Values: foo | bar | baz",
-                       ["l", "linenum", "line-num"],
-                       "+A line number",
-                       ["s", "shlib-name", "shlib-name"],
-                       "+A shared library name"]
-        substrs = ["Example command for use in debugging",
-                   "Syntax: no-args <cmd-options>"]
-        
+        no_arg_opts = [
+            ["b", "boolean", "bool-arg"],
+            "+a boolean arg, defaults to True",
+            ["d", "filename", "disk-file-name"],
+            "+An on disk filename",
+            ["e", "none", "enum-option"],
+            "+An enum, doesn't actually do anything",
+            "+Values: foo | bar | baz",
+            ["l", "linenum", "line-num"],
+            "+A line number",
+            ["s", "shlib-name", "shlib-name"],
+            "+A shared library name",
+        ]
+        substrs = [
+            "Example command for use in debugging",
+            "Syntax: no-args <cmd-options>",
+        ]
+
         self.check_help_options("no-args", no_arg_opts, substrs)
 
         # Make sure the command doesn't accept arguments:
-        self.expect("no-args an-arg", substrs=["'no-args' doesn't take any arguments."],
-                    error=True)
+        self.expect(
+            "no-args an-arg",
+            substrs=["'no-args' doesn't take any arguments."],
+            error=True,
+        )
 
         # Try setting the bool with the wrong value:
-        self.expect("no-args -b Something",
-                    substrs=["Error setting option: bool-arg to Something"],
-                    error=True)
+        self.expect(
+            "no-args -b Something",
+            substrs=["Error setting option: bool-arg to Something"],
+            error=True,
+        )
         # Try setting the enum to an illegal value as well:
-        self.expect("no-args --enum-option Something",
-                    substrs=["error: Error setting option: enum-option to Something"],
-                    error=True)
-        
+        self.expect(
+            "no-args --enum-option Something",
+            substrs=["error: Error setting option: enum-option to Something"],
+            error=True,
+        )
+
         # Check some of the command groups:
-        self.expect("no-args -b true -s Something -l 10",
-                    substrs=["error: invalid combination of options for the given command"],
-                    error=True)
-                    
+        self.expect(
+            "no-args -b true -s Something -l 10",
+            substrs=["error: invalid combination of options for the given command"],
+            error=True,
+        )
+
         # Now set the bool arg correctly, note only the first option was set:
-        self.expect("no-args -b true", substrs=["bool-arg (set: True): True",
-                                                "shlib-name (set: False):",
-                                                "disk-file-name (set: False):",
-                                                "line-num (set: False):",
-                                                "enum-option (set: False):"])
+        self.expect(
+            "no-args -b true",
+            substrs=[
+                "bool-arg (set: True): True",
+                "shlib-name (set: False):",
+                "disk-file-name (set: False):",
+                "line-num (set: False):",
+                "enum-option (set: False):",
+            ],
+        )
 
         # Now set the enum arg correctly, note only the first option was set:
-        self.expect("no-args -e foo", substrs=["bool-arg (set: False):",
-                                                "shlib-name (set: False):",
-                                                "disk-file-name (set: False):",
-                                                "line-num (set: False):",
-                                                "enum-option (set: True): foo"])
+        self.expect(
+            "no-args -e foo",
+            substrs=[
+                "bool-arg (set: False):",
+                "shlib-name (set: False):",
+                "disk-file-name (set: False):",
+                "line-num (set: False):",
+                "enum-option (set: True): foo",
+            ],
+        )
         # Try a pair together:
-        self.expect("no-args -b false -s Something", substrs=["bool-arg (set: True): False",
-                                                "shlib-name (set: True): Something",
-                                                "disk-file-name (set: False):",
-                                                "line-num (set: False):",
-                                                "enum-option (set: False):"])
+        self.expect(
+            "no-args -b false -s Something",
+            substrs=[
+                "bool-arg (set: True): False",
+                "shlib-name (set: True): Something",
+                "disk-file-name (set: False):",
+                "line-num (set: False):",
+                "enum-option (set: False):",
+            ],
+        )
 
         # Next try some completion tests:
 
         interp = self.dbg.GetCommandInterpreter()
         matches = lldb.SBStringList()
         descriptions = lldb.SBStringList()
 
-        # First try an enum completion: 
-        num_completions = interp.HandleCompletionWithDescriptions("no-args -e f", 12, 0,
-                                                                  1000, matches, descriptions)
+        # First try an enum completion:
+        num_completions = interp.HandleCompletionWithDescriptions(
+            "no-args -e f", 12, 0, 1000, matches, descriptions
+        )
         self.assertEqual(num_completions, 1, "Only one completion for foo")
-        self.assertEqual(matches.GetSize(), 2, "The first element is the complete additional text")
-        self.assertEqual(matches.GetStringAtIndex(0), "oo ", "And we got the right extra characters")
-        self.assertEqual(matches.GetStringAtIndex(1), "foo", "And we got the right match")
-        self.assertEqual(descriptions.GetSize(), 2, "descriptions matche the return length")
+        self.assertEqual(
+            matches.GetSize(), 2, "The first element is the complete additional text"
+        )
+        self.assertEqual(
+            matches.GetStringAtIndex(0), "oo ", "And we got the right extra characters"
+        )
+        self.assertEqual(
+            matches.GetStringAtIndex(1), "foo", "And we got the right match"
+        )
+        self.assertEqual(
+            descriptions.GetSize(), 2, "descriptions matche the return length"
+        )
         # FIXME: we don't return descriptions for enum elements
-        #self.assertEqual(descriptions.GetStringAtIndex(1), "does foo things", "And we got the right description")
+        # self.assertEqual(descriptions.GetStringAtIndex(1), "does foo things", "And we got the right description")
 
         # Now try an internal completer, the on disk file one is handy:
         partial_name = os.path.join(source_dir, "test_")
         cmd_str = f"no-args -d '{partial_name}'"
 
         matches.Clear()
         descriptions.Clear()
-        num_completions = interp.HandleCompletionWithDescriptions(cmd_str, len(cmd_str) - 1, 0,
-                                                                  1000, matches, descriptions)
-        print(f"First: {matches.GetStringAtIndex(0)}\nSecond: {matches.GetStringAtIndex(1)}\nThird: {matches.GetStringAtIndex(2)}")
+        num_completions = interp.HandleCompletionWithDescriptions(
+            cmd_str, len(cmd_str) - 1, 0, 1000, matches, descriptions
+        )
+        print(
+            f"First: {matches.GetStringAtIndex(0)}\nSecond: {matches.GetStringAtIndex(1)}\nThird: {matches.GetStringAtIndex(2)}"
+        )
         self.assertEqual(num_completions, 1, "Only one completion for source file")
         self.assertEqual(matches.GetSize(), 2, "The first element is the complete line")
-        self.assertEqual(matches.GetStringAtIndex(0), "commands.py' ", "And we got the right extra characters")
-        self.assertEqual(matches.GetStringAtIndex(1), test_file_path, "And we got the right match")
-        self.assertEqual(descriptions.GetSize(), 2, "descriptions match the return length")
+        self.assertEqual(
+            matches.GetStringAtIndex(0),
+            "commands.py' ",
+            "And we got the right extra characters",
+        )
+        self.assertEqual(
+            matches.GetStringAtIndex(1), test_file_path, "And we got the right match"
+        )
+        self.assertEqual(
+            descriptions.GetSize(), 2, "descriptions match the return length"
+        )
         # FIXME: we don't return descriptions for enum elements
-        #self.assertEqual(descriptions.GetStringAtIndex(1), "does foo things", "And we got the right description")
-        
+        # self.assertEqual(descriptions.GetStringAtIndex(1), "does foo things", "And we got the right description")
+
         # Try a command with arguments.
         # FIXME: It should be enough to define an argument and it's type to get the completer
         # wired up for that argument type if it is a known type. But that isn't wired up in the
         # command parser yet, so I don't have any tests for that.  We also don't currently check
         # that the arguments passed match the argument specifications, so here I just pass a couple
         # sets of arguments and make sure we get back what we put in:
-        self.expect("two-args 'First Argument' 'Second Argument'", substrs=["0: First Argument", "1: Second Argument"])
+        self.expect(
+            "two-args 'First Argument' 'Second Argument'",
+            substrs=["0: First Argument", "1: Second Argument"],
+        )
--- test/API/commands/command/script/add/test_commands.py	2023-10-30 21:48:37.000000 +0000
+++ test/API/commands/command/script/add/test_commands.py	2023-11-14 01:40:47.861762 +0000
@@ -4,10 +4,11 @@
 import inspect
 import sys
 import lldb
 from lldb.utils.parsed_cmd import ParsedCommandBase
 
+
 class ReportingCmd(ParsedCommandBase):
     def __init__(self, debugger, unused):
         super().__init__(debugger, unused)
 
     def __call__(self, debugger, args_array, exe_ctx, result):
@@ -15,20 +16,25 @@
         if len(opt_def):
             result.AppendMessage("Options:\n")
             for elem in opt_def:
                 long_option = elem["long_option"]
                 varname = elem["varname"]
-                result.AppendMessage(f"{long_option} (set: {elem['_value_set']}): {object.__getattribute__(self.ov_parser, varname)}\n")
+                result.AppendMessage(
+                    f"{long_option} (set: {elem['_value_set']}): {object.__getattribute__(self.ov_parser, varname)}\n"
+                )
         else:
             result.AppendMessage("No options\n")
 
         num_args = args_array.GetSize()
         if num_args > 0:
             result.AppendMessage(f"{num_args} arguments:")
-        for idx in range(0,num_args):
-          result.AppendMessage(f"{idx}: {args_array.GetItemAtIndex(idx).GetStringValue(10000)}\n")
-    
+        for idx in range(0, num_args):
+            result.AppendMessage(
+                f"{idx}: {args_array.GetItemAtIndex(idx).GetStringValue(10000)}\n"
+            )
+
+
 class NoArgsCommand(ReportingCmd):
     program = "no-args"
 
     def __init__(self, debugger, unused):
         super().__init__(debugger, unused)
@@ -40,62 +46,65 @@
     def setup_command_definition(self):
         self.ov_parser.add_option(
             "b",
             "bool-arg",
             "a boolean arg, defaults to True",
-            value_type = lldb.eArgTypeBoolean,
-            groups = [1,2],
-            varname = "bool_arg",
-            default = True
+            value_type=lldb.eArgTypeBoolean,
+            groups=[1, 2],
+            varname="bool_arg",
+            default=True,
         )
 
         self.ov_parser.add_option(
             "s",
             "shlib-name",
             "A shared library name.",
             value_type=lldb.eArgTypeShlibName,
-            groups = [1, [3,4]],
-            varname = "shlib_name",
-            default = None
+            groups=[1, [3, 4]],
+            varname="shlib_name",
+            default=None,
         )
 
         self.ov_parser.add_option(
             "d",
             "disk-file-name",
             "An on disk filename",
-            value_type = lldb.eArgTypeFilename,
-            varname = "disk_file_name",
-            default = None
+            value_type=lldb.eArgTypeFilename,
+            varname="disk_file_name",
+            default=None,
         )
 
         self.ov_parser.add_option(
             "l",
             "line-num",
             "A line number",
-            value_type = lldb.eArgTypeLineNum,
-            groups = 3,
-            varname = "line_num",
-            default = 0
-        )
-        
+            value_type=lldb.eArgTypeLineNum,
+            groups=3,
+            varname="line_num",
+            default=0,
+        )
+
         self.ov_parser.add_option(
             "e",
             "enum-option",
             "An enum, doesn't actually do anything",
-            enum_values = [["foo", "does foo things"],
-                           ["bar", "does bar things"],
-                           ["baz", "does baz things"]],
-            groups = 4,
-            varname = "enum_option",
-            default = "foo"
-        )
-        
+            enum_values=[
+                ["foo", "does foo things"],
+                ["bar", "does bar things"],
+                ["baz", "does baz things"],
+            ],
+            groups=4,
+            varname="enum_option",
+            default="foo",
+        )
+
     def get_short_help(self):
         return "Example command for use in debugging"
 
     def get_long_help(self):
         return self.help_string
+
 
 class OneArgCommandNoOptions(ReportingCmd):
     program = "one-arg-no-opt"
 
     def __init__(self, debugger, unused):
@@ -104,17 +113,20 @@
     @classmethod
     def register_lldb_command(cls, debugger, module_name):
         ParsedCommandBase.do_register_cmd(cls, debugger, module_name)
 
     def setup_command_definition(self):
-        self.ov_parser.add_argument_set([self.ov_parser.make_argument_element(lldb.eArgTypeSourceFile, "plain")])
-        
+        self.ov_parser.add_argument_set(
+            [self.ov_parser.make_argument_element(lldb.eArgTypeSourceFile, "plain")]
+        )
+
     def get_short_help(self):
         return "Example command for use in debugging"
 
     def get_long_help(self):
         return self.help_string
+
 
 class TwoArgGroupsCommand(ReportingCmd):
     program = "two-args"
 
     def __init__(self, debugger, unused):
@@ -127,46 +139,63 @@
     def setup_command_definition(self):
         self.ov_parser.add_option(
             "l",
             "language",
             "language defaults to None",
-            value_type = lldb.eArgTypeLanguage,
-            groups = [1,2],
-            varname = "language",
-            default = None
+            value_type=lldb.eArgTypeLanguage,
+            groups=[1, 2],
+            varname="language",
+            default=None,
         )
 
         self.ov_parser.add_option(
             "c",
             "log-channel",
             "log channel - defaults to lldb",
             value_type=lldb.eArgTypeLogChannel,
-            groups = [1, 3],
-            varname = "log_channel",
-            default = "lldb"
+            groups=[1, 3],
+            varname="log_channel",
+            default="lldb",
         )
 
         self.ov_parser.add_option(
             "p",
             "process-name",
             "A process name, defaults to None",
-            value_type = lldb.eArgTypeProcessName,
-            varname = "proc_name",
-            default = None
-        )
-
-        self.ov_parser.add_argument_set([self.ov_parser.make_argument_element(lldb.eArgTypeClassName, "plain", [1,2]),
-                         self.ov_parser.make_argument_element(lldb.eArgTypeOffset, "optional", [1,2])])
-
-        self.ov_parser.add_argument_set([self.ov_parser.make_argument_element(lldb.eArgTypePythonClass, "plain", [3,4]),
-                         self.ov_parser.make_argument_element(lldb.eArgTypePid, "optional", [3,4])])
-        
+            value_type=lldb.eArgTypeProcessName,
+            varname="proc_name",
+            default=None,
+        )
+
+        self.ov_parser.add_argument_set(
+            [
+                self.ov_parser.make_argument_element(
+                    lldb.eArgTypeClassName, "plain", [1, 2]
+                ),
+                self.ov_parser.make_argument_element(
+                    lldb.eArgTypeOffset, "optional", [1, 2]
+                ),
+            ]
+        )
+
+        self.ov_parser.add_argument_set(
+            [
+                self.ov_parser.make_argument_element(
+                    lldb.eArgTypePythonClass, "plain", [3, 4]
+                ),
+                self.ov_parser.make_argument_element(
+                    lldb.eArgTypePid, "optional", [3, 4]
+                ),
+            ]
+        )
+
     def get_short_help(self):
         return "Example command for use in debugging"
 
     def get_long_help(self):
         return self.help_string
+
 
 def __lldb_init_module(debugger, dict):
     # Register all classes that have a register_lldb_command method
     for _name, cls in inspect.getmembers(sys.modules[__name__]):
         if inspect.isclass(cls) and callable(

``````````

</details>


https://github.com/llvm/llvm-project/pull/70734


More information about the lldb-commits mailing list