Skip to content
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

How to create nested commands? #7

Closed
LexSong opened this issue Jul 14, 2019 · 4 comments · Fixed by #8
Closed

How to create nested commands? #7

LexSong opened this issue Jul 14, 2019 · 4 comments · Fixed by #8

Comments

@LexSong
Copy link

LexSong commented Jul 14, 2019

Take conda for example. We have commands like this:

conda create
conda list

conda env create
conda env list
conda env export

or git:

git init
git commit

git stack push
git stack pop

git remote add
git remote show

I think one way to handle this is to create subcommand class and explicitly pass args to it's parse function:

from cliar import Cliar

class StackCommand(Cliar):
    def push(self, ...):
       ...
    def pop(self, ...):
       ...
 
class MainCommand(Cliar):
    def __init__(self):
        self.stack_command = StackCommand()
    def stack(self, args):
        self.stack_command.parse(args)

Currently, the Cliar class impliedly take args from the command line.
However, I think taking args from another command may be useful to build complex CLI.

@moigagoo
Copy link
Owner

Thanks for opening the issue. The problem of multilevel subcommands has been bugging me since the very start, but I haven't come up with a clever solution so far. I'll investigate closer into your proposal, thanks!

@AgarwalPragy
Copy link

How about something like the following?

class Env(Cliar):
    def create(self):
        ...

    def list(self):
        ...

    def export(self):
        ...


class Conda(Cliar):
    env: Env

    def create(self):
        ...

    def list(self):
        ...

Cliar's metaclass will read the class definition of Conda. It will see that it has a class variable annotated as Env, and that Env is itself a subclass of Cliar. The metaclass will then add a function to the class Conda that will do the work of directing any nested command like conda env create to an object of the Env class instead.

Of course, the nesting could be made more explicit by using descriptors.

class Conda(Cliar):
  env = Env()
  ...

For this, the Cliar class should itself support the descriptor protocol.

@moigagoo
Copy link
Owner

OK, I got it :-) I've implemented this feature in https://github.com/moigagoo/cliar/tree/feature/nested_commands

Have to fix the tests and add a new test.

The syntax will be as follows:

class Env(Cliar):
    def create(self):
        ...

    def list(self):
        ...

    def export(self):
        ...


class Conda(Cliar):
    env = Env

    def create(self):
        ...

    def list(self):
        ...

@moigagoo
Copy link
Owner

moigagoo commented Jul 21, 2019

Added in version 1.3.0: https://moigagoo.github.io/cliar/tutorial/#nested-commands

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants