Repository: xonsh/xonsh

Issue:
Completion exception when input ends with `@(`
I'm encountering an exception related to completions when the input ends with `@(`. This is particularly annoying with $UPDATE_COMPLETIONS_ON_KEYPRESS=True.

```
$xonsh --no-rc
$xonsh --version
xonsh/0.18.2
$$UPDATE_COMPLETIONS_ON_KEYPRESS = True
$echo @(
Unhandled exception in event loop:
  File "/home/tuesday/.pyenv/versions/3.12.1/envs/dev/lib/python3.12/site-packages/prompt_toolkit/buffer.py", line 1920, in new_coroutine
    await coroutine(*a, **kw)
  File "/home/tuesday/.pyenv/versions/3.12.1/envs/dev/lib/python3.12/site-packages/prompt_toolkit/buffer.py", line 1744, in async_completer
    async for completion in async_generator:
  File "/home/tuesday/.pyenv/versions/3.12.1/envs/dev/lib/python3.12/site-packages/prompt_toolkit/completion/base.py", line 323, in get_completions_async
    async for completion in completer.get_completions_async(
  File "/home/tuesday/.pyenv/versions/3.12.1/envs/dev/lib/python3.12/site-packages/prompt_toolkit/completion/base.py", line 199, in get_completions_async
    for item in self.get_completions(document, complete_event):
  File "/home/tuesday/.pyenv/versions/3.12.1/envs/dev/lib/python3.12/site-packages/xonsh/shells/ptk_shell/completer.py", line 59, in get_completions
    completions, plen = self.completer.complete(
                        ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/tuesday/.pyenv/versions/3.12.1/envs/dev/lib/python3.12/site-packages/xonsh/completer.py", line 122, in complete
    return self.complete_from_context(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/tuesday/.pyenv/versions/3.12.1/envs/dev/lib/python3.12/site-packages/xonsh/completer.py", line 289, in complete_from_context
    prefix = completion_context.command.prefix
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Exception 'NoneType' object has no attribute 'prefix'
Press ENTER to continue...
```

Has anyone come across this issue or a solution?

_Originally posted by @aidaco in https://github.com/xonsh/xonsh/discussions/5621_

Discussion:

Patch:
diff --git a/news/fix_python_only_completion.rst b/news/fix_python_only_completion.rst
new file mode 100644
index 00000000..496dd6d9
--- /dev/null
+++ b/news/fix_python_only_completion.rst
@@ -0,0 +1,23 @@
+**Added:**
+
+* <news item>
+
+**Changed:**
+
+* <news item>
+
+**Deprecated:**
+
+* <news item>
+
+**Removed:**
+
+* <news item>
+
+**Fixed:**
+
+* completer: Fixed exception when in python-only completion context (#5632).
+
+**Security:**
+
+* <news item>
diff --git a/xonsh/completer.py b/xonsh/completer.py
index e0700ad1..63e8b86f 100644
--- a/xonsh/completer.py
+++ b/xonsh/completer.py
@@ -48,10 +48,16 @@ class Completer:
         suffix is not supported; text after last space is parsed as prefix.
         """
         ctx = self.parse(text)
-        cmd_ctx = ctx.command
-        if not cmd_ctx:
-            raise RuntimeError("Only Command context is empty")
-        prefix = cmd_ctx.prefix
+
+        if not ctx:
+            raise RuntimeError("CompletionContext is None")
+
+        if ctx.python is not None:
+            prefix = ctx.python.prefix
+        elif ctx.command is not None:
+            prefix = ctx.command.prefix
+        else:
+            raise RuntimeError("CompletionContext is empty")
 
         line = text
         begidx = text.rfind(prefix)
@@ -284,9 +290,14 @@ class Completer:
                     )
                 break
 
-        prefix = None
         if completion_context:
-            prefix = completion_context.command.prefix
+            if completion_context.python is not None:
+                prefix = completion_context.python.prefix
+            elif completion_context.command is not None:
+                prefix = completion_context.command.prefix
+            else:
+                raise RuntimeError("Completion context is empty")
+
             if prefix.startswith("$"):
                 prefix = prefix[1:]
 


Test patch:
diff --git a/tests/test_completer.py b/tests/test_completer.py
index 67af4890..384e59f1 100644
--- a/tests/test_completer.py
+++ b/tests/test_completer.py
@@ -168,3 +168,8 @@ def test_env_completer_sort(completer, completers_mock):
         "$WOW", "$WOW", 4, 0, {}, multiline_text="'$WOW'", cursor_index=4
     )
     assert set(comps[0]) == {"$WOW0", "$WOW1", "$MID_WOW", "$SUPER_WOW"}
+
+
+def test_python_only_context(completer, completers_mock):
+    assert completer.complete_line("echo @(") != ()
+    assert completer.complete("", "echo @(", 0, 0, {}, "echo @(", 7) != ()