-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
click_repl always reparses the group's options and arguments and invokes it #92
Comments
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) This is my idea, but as your idea goes, getting the callback function of the command is the big deal 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. |
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 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,
The text was updated successfully, but these errors were encountered: