You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Due to various reasons, remote pdb client does not sync with the server entirely. For example, for multi-line inputs, it will read the full content on the client then send it to the server.
However, this introduced the issue for completion - the server doesn't know it. When user requests a completion for the multi-line code, server pdb doesn't know what completion should be provided (more specifically, whether pdb commands should be provided).
The simplest way to deal with it is to add an extra field "mode" in completion protocol - unless we sync the client and server perfectly, we will need it because the server knows nothing about the client.
I put it under the bug label for now, but maybe it's a feature. It's very close to beta freeze now, I think we should at least update the protocol so we can try to keep the protocol version and solve the issue for 3.14. I don't think the code is too complicated.
Hm. I see two alternative fixes that wouldn't require changing the protocol schema:
If we're doing a multi-line input and asking for completion for a line other than the first, prefix the line we send to the server with ! so that the server knows it must be a Python command. We'll need to adjust the offsets by 1, but otherwise I think things would Just Work.
Maybe we should send the whole buffered multi-line input to the server, instead of just the current line? PDB doesn't currently use that information in its completions, but maybe it should, in a perfect world. As an example, imagine someone writes:
PDB can't currently complete the local variable name, but wouldn't it be nice if it could? It could heuristically do that by parsing the written-but-not-yet-executed text looking for assignment statements and adding the names on the LHS to its list of possible completions. But for that to work, the server would need to get the full context of what's buffered, not just the last line of it. (Admittedly though this is a slippery slope, you'll never get something perfect without being able to actually execute the code and introspect its objects, so it's reasonable to decide that you don't want to implement this feature at all because of the fact that there would always be requests to do more - like recognize that it's a list and complete list methods for it, or the like.)
I don't like sending with ! because that's the explicit "pdb command" indicator for pdb. The server needs to know that this is something that should not include pdb command completions.
PyREPL does not even handle the local variable names defined in the previous lines for now. I think that is rather complicated because that requires constantly compile code that might not be compilable.
Even if you passed the whole multi-line string, you probably will need some logic to figure out whether that's a Python command or not (checking \n? not sure if it's reliable). The existing protocol is mimicking what readline actually does - if we change the text, we probably will simulate something that readline is not supposed to deal with (does readline work with multiline context?).
If you think it's easier to deal with this case with a full context, we can try that.
I don't like sending with ! because that's the explicit "pdb command" indicator for pdb. The server needs to know that this is something that should not include pdb command completions.
Huh. It seems like this is something that regular PDB gets wrong, actually. If I do:
I would expect it to complete the two variable names, since the ! means that it's completing in the context of a Python statement to be exec'd, but it doesn't show any completions.
If we fix that, so that
(Pdb) !anything<Tab>
and
(Pdb) if True:
... anything<Tab>
show the same completions, then my quick fix will work.
parseline can return with cmd set to None, and if it does the if cmd == '': block doesn't run, so it instead tries to do compfunc = getattr(self, 'complete_' + cmd), but since cmd is None that fails with a TypeError instead of the AttributeError that it's expecting to handle, and so it never falls back to completedefault like it was meant to.
After fixing that, ! a<Tab> (with a space after the !) does complete the 'a' names that it should, and we should be able to get the behavior that we want by having remote PDB send a "! " prefix for the line, and incrementing both the indexes by 2.
Ah right my brain went somewhere else. ! should forces default behavior.
Do you want to make a PR to fix that? I can do it too. Either change line 276 to cmd == '' or cmd is None or just flip the logic and do if cmd:. We do need regression test and a news entry.
I guess text was the only thing used in completedefault in pdb.Pdb so the others do not matter, but yeah we should fix it or it will confuse the people in the future.
Activity
gaogaotiantian commentedon May 3, 2025
I put it under the bug label for now, but maybe it's a feature. It's very close to beta freeze now, I think we should at least update the protocol so we can try to keep the protocol version and solve the issue for 3.14. I don't think the code is too complicated.
@pablogsal @godlygeek
godlygeek commentedon May 3, 2025
Hm. I see two alternative fixes that wouldn't require changing the protocol schema:
If we're doing a multi-line input and asking for completion for a line other than the first, prefix the line we send to the server with
!so that the server knows it must be a Python command. We'll need to adjust the offsets by 1, but otherwise I think things would Just Work.Maybe we should send the whole buffered multi-line input to the server, instead of just the current line? PDB doesn't currently use that information in its completions, but maybe it should, in a perfect world. As an example, imagine someone writes:
PDB can't currently complete the local variable name, but wouldn't it be nice if it could? It could heuristically do that by parsing the written-but-not-yet-executed text looking for assignment statements and adding the names on the LHS to its list of possible completions. But for that to work, the server would need to get the full context of what's buffered, not just the last line of it. (Admittedly though this is a slippery slope, you'll never get something perfect without being able to actually execute the code and introspect its objects, so it's reasonable to decide that you don't want to implement this feature at all because of the fact that there would always be requests to do more - like recognize that it's a list and complete list methods for it, or the like.)
gaogaotiantian commentedon May 4, 2025
I don't like sending with
!because that's the explicit "pdb command" indicator for pdb. The server needs to know that this is something that should not include pdb command completions.PyREPL does not even handle the local variable names defined in the previous lines for now. I think that is rather complicated because that requires constantly compile code that might not be compilable.
Even if you passed the whole multi-line string, you probably will need some logic to figure out whether that's a Python command or not (checking
\n? not sure if it's reliable). The existing protocol is mimicking whatreadlineactually does - if we change thetext, we probably will simulate something that readline is not supposed to deal with (does readline work with multiline context?).If you think it's easier to deal with this case with a full context, we can try that.
godlygeek commentedon May 4, 2025
Huh. It seems like this is something that regular PDB gets wrong, actually. If I do:
I would expect it to complete the two variable names, since the
!means that it's completing in the context of a Python statement to be exec'd, but it doesn't show any completions.If we fix that, so that
and
show the same completions, then my quick fix will work.
godlygeek commentedon May 4, 2025
There's a
cmd.Cmdbug here, that's why it's not working.cpython/Lib/cmd.py
Lines 275 to 280 in 2bc8365
parselinecan return withcmdset toNone, and if it does theif cmd == '':block doesn't run, so it instead tries to docompfunc = getattr(self, 'complete_' + cmd), but sincecmd is Nonethat fails with aTypeErrorinstead of theAttributeErrorthat it's expecting to handle, and so it never falls back tocompletedefaultlike it was meant to.After fixing that,
! a<Tab>(with a space after the!) does complete the 'a' names that it should, and we should be able to get the behavior that we want by having remote PDB send a"! "prefix for the line, and incrementing both the indexes by 2.gaogaotiantian commentedon May 4, 2025
Ah right my brain went somewhere else.
!should forces default behavior.Do you want to make a PR to fix that? I can do it too. Either change line 276 to
cmd == '' or cmd is Noneor just flip the logic and doif cmd:. We do need regression test and a news entry.godlygeek commentedon May 4, 2025
After #133364 is applied I think this patch makes completion do what you want:
Can you try that out and see if you spot any other problems?
gaogaotiantian commentedon May 4, 2025
Is this correct? Shouldn't it be
line = "! " + line?godlygeek commentedon May 4, 2025
Hah! Yes it should. Believe it or not it actually works even with that bug! 😆
godlygeek commentedon May 4, 2025
It does also work with that bug fixed, so we should definitely do what you suggest, heh
gaogaotiantian commentedon May 4, 2025
I guess
textwas the only thing used incompletedefaultinpdb.Pdbso the others do not matter, but yeah we should fix it or it will confuse the people in the future.gh-133351: Fix remote PDB's multi-line block tab completion (#133387)
Merge remote-tracking branch 'origin/main' into call-len
godlygeek commentedon May 4, 2025
I think this can be closed now
pythongh-133351: Fix remote PDB's multi-line block tab completion (py…