Skip to content

Fix AttributeError in docstring meta init and improve test isolation across shell tests#43

Merged
RobertBlackhart merged 2 commits into
mainfrom
copilot/fix-attribute-error-in-docstring-meta
Apr 17, 2026
Merged

Fix AttributeError in docstring meta init and improve test isolation across shell tests#43
RobertBlackhart merged 2 commits into
mainfrom
copilot/fix-attribute-error-in-docstring-meta

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 17, 2026

command_class.docstring.meta was only initialized inside if args or kwargs:, causing an AttributeError when a command had examples but no args/kwargs. Several shell tests also shared the same command name "single command", risking cross-test registry pollution with no cleanup.

test_man_utils.py

  • Initialize docstring.meta = [] unconditionally before the conditional append, fixing the AttributeError path
# Before
if args or kwargs:
    command_class.docstring.meta = [DocstringMeta(["arg"], "")]
for label, description in examples.items():
    command_class.docstring.meta.append(...)  # AttributeError if no args/kwargs

# After
command_class.docstring.meta = []
if args or kwargs:
    command_class.docstring.meta.append(DocstringMeta(["arg"], ""))
for label, description in examples.items():
    command_class.docstring.meta.append(...)

test_shell.py

  • Assign unique command names per test ("single command dash c", "single command non repl", "single command one shot", "single command sys argv") to eliminate inter-test interference
  • Rename inner single_command functions to single_cmd to avoid shadowing the outer single_command kwarg in relax()
  • Add try/finally cleanup in test_run_with_dash_c with pre/post assertions on COMMAND_REGISTRY
  • Replace monkeypatch.setattr(bc, "debug", lambda: debug_called.__setitem__(0, True)) with a named mock_debug() closure
  • Use monkeypatch.setitem(recline.commands.COMMAND_REGISTRY, ...) in test_run_one_command_command_cancelled so pytest handles teardown automatically
Original prompt
Please apply the following diffs and create a pull request.
Once the PR is ready, give it a title based on the messages of the fixes being applied.

[{"message":"The condition `if args or kwargs:` initializes `command_class.docstring.meta` only when there are args or kwargs, but line 96 always attempts to append to `command_class.docstring.meta` regardless of whether it was initialized. If there are no args or kwargs but there are examples, this will fail with an AttributeError. Consider initializing `command_class.docstring.meta` unconditionally or adding a check before appending.","fixFiles":[{"filePath":"tests/test_commands/test_man_utils.py","diff":"diff --git a/tests/test_commands/test_man_utils.py b/tests/test_commands/test_man_utils.py\n--- a/tests/test_commands/test_man_utils.py\n+++ b/tests/test_commands/test_man_utils.py\n@@ -90,8 +90,9 @@\n         Parameter(arg, Parameter.KEYWORD_ONLY, default=val)\n         for arg, val in kwargs.items()\n     ]\n+    command_class.docstring.meta = []\n     if args or kwargs:\n-        command_class.docstring.meta = [DocstringMeta([\"arg\"], \"\")]\n+        command_class.docstring.meta.append(DocstringMeta([\"arg\"], \"\"))\n     for label, description in examples.items():\n         command_class.docstring.meta.append(\n             DocstringMeta([\"examples\", label], description)\n"}]},{"message":"The test does not verify cleanup of the command from the registry after execution. Consider adding assertions to ensure that command registration doesn't leak across tests.","fixFiles":[{"filePath":"tests/test_repl/test_shell.py","diff":"diff --git a/tests/test_repl/test_shell.py b/tests/test_repl/test_shell.py\n--- a/tests/test_repl/test_shell.py\n+++ b/tests/test_repl/test_shell.py\n@@ -108,13 +108,24 @@\n def test_run_with_dash_c():\n     \"\"\"Verify only a single command is run when -c is passed in\"\"\"\n \n-    @recline.command(name=\"single command\")\n+    command_name = \"single command\"\n+    preexisting = command_name in recline.commands.COMMANDS\n+\n+    @recline.command(name=command_name)\n     def single_command():\n         return 73\n \n-    assert shell.relax(argv=[\"ut_program\", \"-c\", \"single\", \"command\"]) == 73\n+    try:\n+        assert shell.relax(argv=[\"ut_program\", \"-c\", \"single\", \"command\"]) == 73\n+        assert command_name in recline.commands.COMMANDS\n+    finally:\n+        if not preexisting:\n+            recline.commands.COMMANDS.pop(command_name, None)\n \n+    if not preexisting:\n+        assert command_name not in recline.commands.COMMANDS\n \n+\n def test_run_non_repl():\n     \"\"\"Verify that if a program is not trying to be a repl, then we will parse\n     a command from the input and exit\n"}]},{"message":"The function name 'single_command' shadows the outer scope variable (the decorator parameter). Consider renaming the function to 'single_cmd' or 'cmd_single' to avoid confusion.","fixFiles":[{"filePath":"tests/test_repl/test_shell.py","diff":"diff --git a/tests/test_repl/test_shell.py b/tests/test_repl/test_shell.py\n--- a/tests/test_repl/test_shell.py\n+++ b/tests/test_repl/test_shell.py\n@@ -109,7 +109,7 @@\n     \"\"\"Verify only a single command is run when -c is passed in\"\"\"\n \n     @recline.command(name=\"single command\")\n-    def single_command():\n+    def single_cmd():\n         return 73\n \n     assert shell.relax(argv=[\"ut_program\", \"-c\", \"single\", \"command\"]) == 73\n@@ -121,7 +121,7 @@\n     \"\"\"\n \n     @recline.command(name=\"single command\")\n-    def single_command():\n+    def single_cmd():\n         return 73\n \n     assert shell.relax(argv=[\"ut_program\", \"single\", \"command\"], repl_mode=False) == 73\n@@ -133,7 +133,7 @@\n     \"\"\"\n \n     @recline.command(name=\"single command\")\n-    def single_command():\n+    def single_cmd():\n         return 73\n \n     assert shell.relax(argv=[\"ut_program\"], single_command=\"single command\") == 73\n"}]},{"message":"The function name 'single_command' is reused across multiple tests (lines 113, 123, 136, 148). This could lead to test interference if the command registry is not properly cleaned between tests. Consider using unique names for each test or ensure proper cleanup.","fixFiles":[{"filePath":"tests/test_repl/test_shell.py","diff":"diff --git a/tests/test_repl/test_shell.py b/tests/test_repl/test_shell.py\n--- a/tests/test_repl/test_shell.py\n+++ b/tests/test_repl/test_shell.py\n@@ -108,11 +108,11 @@\n def test_run_with_dash_c():\n     \"\"\"Verify only a single command is run when -c is passed in\"\"\"\n \n-    @recline.command(name=\"single command\")\n+    @recline.command(name=\"single command dash c\")\n     def single_command():\n         return 73\n \n-    assert shell.relax(argv=[\"ut_program\", \"-c\", \"single\", \"command\"]) == 73\n+    assert shell.relax(argv=[\"ut_program\", \"-c\", \"single\", \"command\", \"dash\", \"c\"]) == 73\n \n \n def test_run_non_repl():\n@@ -120,11 +117,...

…ell tests

Agent-Logs-Url: https://github.com/NetApp/recline/sessions/f54164fb-39cc-4b8c-bfa9-2cc5f0d302cb

Co-authored-by: RobertBlackhart <5414318+RobertBlackhart@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix AttributeError in command_class.docstring.meta initialization Fix AttributeError in docstring meta init and improve test isolation across shell tests Apr 17, 2026
Copilot AI requested a review from RobertBlackhart April 17, 2026 17:10
@RobertBlackhart RobertBlackhart marked this pull request as ready for review April 17, 2026 17:12
@RobertBlackhart RobertBlackhart merged commit 1fbdc82 into main Apr 17, 2026
9 checks passed
@RobertBlackhart RobertBlackhart deleted the copilot/fix-attribute-error-in-docstring-meta branch April 17, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants