Open flacoste opened 1 year ago
can you please come with a proposed fix of the part you think is not working correctly in this library? relevant test case to verify that will be highly appreciated
Like I said, I don't know click's internal API well-enough to know how this should be fixed.
I could attempt writing a failing test documenting the expected behavior. But first I'd like to know that my expectations are the right ones. I mean, do you expect the group's options and arguments to be parsed on each subcommands in the repl? And is it expected that the group command is also invoked on each subcommand in the repl?
Also, can you point an existing test to serve as an example? Looking at the existing tests, I don't see any tests confirming that subcommands actually work from the repl. There are tests that shows that things are hooked together, but not that subcommands are actually dispatched.
@flacoste In order to make your code work, you have to call the group function at the end of the file, with no args, to make it work
@click.group(invoke_without_command=True)
@click.option('--db', type=click.Path(exists=False, file_okay=False, writable=True, readable=True, path_type=pathlib.Path), help="the DB where entries are cached")
@click.pass_context
def shell(ctx: click.Context, db: pathlib.Path) -> None:
# Only initializes ctx.obj on the first invocation. We are being called on every subcommands through click_repl
if ctx.obj is None:
if db is None:
db = click.prompt("Enter the DB")
ctx.obj = MyDB(db)
if ctx.invoked_subcommand is None:
ctx.invoke(repl)
shell() # at the end of the file
so can u give me some failing test cases, and a potential fix?
@GhostOps77 well, do you think it's actually a bug? are my expectations about how this should have worked correct? And can you point to an existing test that I can use as a starting point? I can't find any existing test making sure that registered subcommands are actually working in the repl.
@flacoste You are right, there's no existing test cases that shows that this module can work with subcommands, (idk about [this] one, you tell me)
But from what i can see is, idk what to do, but i think the main group (i.e., shell here in your case) must be invoked by mentioning it through the sys.argv
i guess (thats already too much work-around, to make it work imo), and i think that would also work if there's more than one groups that has invoke_without_command=True
decorator in it
This is my idea, but as your idea goes, getting the callback function of the command is the big deal And also if you are successful in it, there's a great difficulty in testing this module as sending user input through stdin is not possible for now. I wish there's a way for that
If thats possible, it would be easy to test your above code with our other test cases
@GhostOps77, ok, yes, I should at least able to write some tests for this. I'll look at this later this week.
I finally got to write those tests. They reproduce the problem pretty briefly. I'll research how to fix the underlying issue, but would welcome any pointers.
@flacoste Thanks for doing your part But, I actually have a fix for that, like, I've solved the command invocation part But, now I've to make the repl suggest commands properly
To get my updated code on solving those issues, you can check the code in my repo
Thanks for the pointer @GhostOps77. Looking at the context around resolve_command(), I realize that actually we should simply set the group context's protected_args to the new args, and let group.invoke() handle the dispatch. That way, it also handles chain commands and pipelines.
That means though that it's normal for the group command to be invoked on each subcommand invocation - that's part of click's behaviour. It should probably be documented though.
I've updated the tests and they are now passing with this change on the related PR #97
@flacoste Very good! Even I haven't come up with that idea Now all that's left is to make the REPL show tab-completions properly for this implementation But, are you having the idea of passing the group command arguments again in the REPL? cuz i've decided to remove that thing
But without implementing that, you PR works smooth
Also, how do you think this implementation can handle chain commands and piplines?
GhostOps can you also review the PR?
@GhostOps77 are you talking about untested functionality? Because the existing autocompletion tests continue to work on this branch.
There is a test for chaining command (there is no test for pipelining the result, but I expect it to work as all of this is implemented within invoke() itself).
Reviewing the call sites of resolve_command(), I noticed that they were usually two code paths once for chain and one for unchained command. I thought that we didn't want to have to reimplement this, so better to just rely on click() itself via the invoke() method.
@GhostOps77 sorry, I just realized that for some reasons these tests are skipped here.
I'm writing a repl that looked like this:
That code didn't work as expected. I was expecting something like this:
Instead, I got an exception about no command 1. Digging through the code, I discovered that "entry" is parsed as the argument to the group command, and not as the subcommand.
I also discovered that shell() will also be invoked in each subcommands invocation. My hunch is that the way click_repl dispatches to the parser isn't correct:
But I'm not familiar enough with the click API to know how we should be dispatching the subcommands. From the documentation, it seems that the proper way to delegate to a subcommand is through
ctx.invoke()
. But that takes a callable/command which we don't know at this point.I was able to work around the issue by rewriting my code like this:
Thanks,