Handling Arbitrary Extra Positional Arguments

It is common practice to accept additional positional arguments at command line, rather than option flags. For example:

$ myapp some-command some-argument --foo=bar

In the above, some-command would be the function under whatever controller it is exposed from, and some-argument would be just an arbtrary argument. In most cases, the argument within the code is generic, but its uses vary. For example:

$ myapp create-user john.doe

$ myapp create-group admins

In the above, the sub-commands are create-user and create-group, and in this use case they are under the same controller. The argument however differs for each command, though it is passed to the app the same (the first positional argument, that is not a controller/command).

The following example outlines how you might handle arbitrary (or generic) positional arguments.

Example

from cement.core.foundation import CementApp
from cement.core.controller import CementBaseController, expose

class MyBaseController(CementBaseController):
    class Meta:
        label = 'base'

class MySecondController(CementBaseController):
    class Meta:
        label = 'second'
        stacked_type = 'nested'
        stacked_on = 'base'
        description = 'this is the second controller namespace'
        arguments = [
            (['-f', '--foo'],
             dict(help='the notorious foo option', action='store')),
            (['extra_arguments'],
             dict(action='store', nargs='*')),
        ]

    @expose()
    def cmd1(self):
        print "Inside MySecondController.cmd1()"

        if self.app.pargs.extra_arguments:
            print "Extra Argument 0: %s" % self.app.pargs.extra_arguments[0]
            print "Extra Argument 1: %s" % self.app.pargs.extra_arguments[1]


class MyApp(CementApp):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        handlers = [
            MyBaseController,
            MySecondController,
            ]

def main():
    with MyApp() as app:
        app.run()

if __name__ == '__main__':
    main()

And this would look something like:

$ python argtest.py second cmd1 extra1 extra2
Inside MySecondController.cmd1()
Extra Argument 0: extra1
Extra Argument 1: extra2