Accept unknown options (for poetry plugin)
I require a way to make a cleo Command accept unknown options and arguments, and not inherit the application options.
The equivalent in argparse would be something like:
parser.add_argument("command_args", nargs=argparse.REMAINDER)
however I need to use cleo because I'm creating a poetry plugin for PoeThePoet which allows users to pass unknown arguments to a task e.g.
poe test <any args passed here will be forwarded to pytest>
It looks like this is currently not supported though I'd be happy to be proven wrong on that.
I'm willing to do the leg work to add support for this, since the only alternatives for integrating with poetry are either to drop key features when used as a plugin or to monkey patch Cleo at runtime 😞.
Workaround
I've found the following workaround that seems to produce the desired result (for now) by monkey patching cleo:
def monkey_patch_cleo(command: str):
"""Monkey patch cleo, e.g. while activating the poetry plugin"""
import cleo.application
continue_run = cleo.application.Application._run
def _run(self, io):
# Trick cleo to ignoring anything following the command from this plugin
# by injecting a '--' token at the start of the list of command line tokens
tokens = io.input._tokens
if tokens and tokens[0] == command:
# update tokens list in place
tokens.insert(0, "--")
continue_run(self, io)
# Apply the patch
cleo.application.Application._run = _run
class MyCommand(Command):
name = "my-command"
def __init__(self):
super().__init__()
self._ignore_validation_errors = True # Don't fail given unknown arguments
def handle(self):
args = self.io.input._tokens[:]
if args[0] == "--": # ignore the extra token introduced by the monkey patch
args = tokenized_input[1:]
...
Proposal
A better solution would involve being able to configure the Command to have freeform arguments, e.g.
class MyCommand(Command):
name = "my-command"
parse_options = False
Which carries over to resulting Definition object which in turn causes the ArgvInput instance to skip parsing of options. Parsing of positional arguments could still work the same I think.
Hi @Secrus, nice to see this is getting picked up :)
Here's a reference to how the poetry plugin for Poe the Poet currently deal's with cleo: https://github.com/nat-n/poethepoet/blob/0133c427523d3967c87475f2e220740f24797e3d/poethepoet/plugin.py#L238 And the relevant user facing docs: https://poethepoet.natn.io/poetry_plugin.html
@nat-n hi. The plan is for the new parser to expose "not consumed"/"remaining" args so that they can be passed down through the stack. It is similar to how optparse works in that matter.