cleo icon indicating copy to clipboard operation
cleo copied to clipboard

The "call" and "call_silent" methods are not working as expected

Open ianrodrigues opened this issue 3 years ago • 1 comments

I'm using this sample app.py:

from cleo.commands.command import Command
from cleo.application import Application
from cleo.helpers import argument


class FooCommand(Command):
    name = "foo"
    arguments = [argument("baz", "The baz argument.")]

    def handle(self):
        baz = self.argument("baz")
        self.line(baz)


class BarCommand(Command):
    name = "bar"

    def handle(self):
        self.call("foo", "baz")


application = Application()
application.add(FooCommand())
application.add(BarCommand())

if __name__ == "__main__":
    application.run()

When I'm calling the foo command itself, it works:

$ python app.py foo baz
baz

But when I'm calling the bar command, I'm getting this:

$ python app.py bar

Not enough arguments (missing: "baz")

If I replace self.call by self.call_silent that's the error:

$ python app.py bar

  AttributeError

  'builtin_function_or_method' object has no attribute 'bind'

  at ~/Library/Caches/pypoetry/virtualenvs/app-wSCSi1z6-py3.9/lib/python3.9/site-packages/cleo/commands/base_command.py:103 in run
       99│     def run(self, io: IO) -> int:
      100│         self.merge_application_definition()
      101│ 
      102│         try:
    → 103│             io.input.bind(self.definition)
      104│         except CleoException:
      105│             if not self._ignore_validation_errors:
      106│                 raise
      107│

ianrodrigues avatar Jan 28 '22 15:01 ianrodrigues

Faced the same issue today. Found out that in call() cleo parses the arguments differently, e.g.

# trying to call command "x" with a required argument "value" as "100"
return_code = self.call("x", "100")

leads to the internal representation as

self._arguments: {'command': '100'} # not  `x`!

though, when I call it from the terminal, the representation is:

# ./app.py x 100
self._arguments: {'command': 'x', 'value': '100'}

Eventually, I made it work with the following hack:

return_code = self.call("x", "x 100")
# inner:
self._arguments: {'command': 'x', 'value': '100'}

So, apparently the first word of the arguments is meaningless when calling a command.

return_code = self.call("x", "<anything> 100")
# inner:
self._arguments: {'command': '<anything>', 'value': '100'}

qezz avatar Jan 30 '22 16:01 qezz