Abstract Base Controllers for Shared Arguments and Commands¶
For larger, complex applications it is often very useful to have abstract base controllers that hold shared arguments and commands that a number of other controllers have in common. Note that in the example below, you can not override the Meta.arguments in a sub-class or you overwrite the shared arguments, but it is possible to append to them in order to maintain the defaults while having unique options/arguments for the sub-classed controller. As well, you can add any number of additional commands in the sub-class but still maintain the existing shared commands (or override them as necessary).
from cement.core.foundation import CementApp
from cement.core.controller import CementBaseController, expose
class AbstractBaseController(CementBaseController):
"""
This is an abstract base class that is useless on its own, but used
by other classes to sub-class from and to share common commands and
arguments. This should not be confused with the `MyAppBaseController`
used as the ``base_controller`` namespace.
"""
class Meta:
stacked_on = 'base'
stacked_type = 'nested'
arguments = [
( ['-f', '--foo'], dict(help='notorious foo option')),
]
def _setup(self, base_app):
super(AbstractBaseController, self)._setup(base_app)
# add a common object that will be used in any sub-class
self.reusable_dict = dict()
@expose(hide=True)
def default(self):
"""
This command will be shared within all controllers that sub-class
from here. It can also be overridden in the sub-class, but for
this example we are making it dynamic.
"""
# do something with self.my_shared_obj here?
if 'some_key' in self.reusable_dict.keys():
pass
# or do something with parsed args?
if self.app.pargs.foo:
print "Foo option was passed with value: %s" % self.app.pargs.foo
# or maybe do something dynamically
print("Inside %s.default()" % self.__class__.__name__)
class MyAppBaseController(CementBaseController):
"""
This is the application base controller, but we don't want to use our
abstract base class here.
"""
class Meta:
label = 'base'
@expose(hide=True)
def default(self):
print("Inside MyAppBaseController.default()")
class Controller1(AbstractBaseController):
"""
This controller sub-classes from the abstract base class as to inherite
shared arguments, and commands.
"""
class Meta:
label = 'controller1'
@expose()
def command1(self):
print("Inside Controller1.command1()")
class Controller2(AbstractBaseController):
"""
This controller also sub-classes from the abstract base class as to
inherite shared arguments, and commands.
"""
class Meta:
label = 'controller2'
@expose()
def command2(self):
print("Inside Controller2.command2()")
class MyApp(CementApp):
class Meta:
label = 'myapp'
base_controller = 'base'
handlers = [
MyAppBaseController,
Controller1,
Controller2,
]
def main():
with MyApp() as app:
app.run()
if __name__ == '__main__':
main()
And:
$ python myapp.py
Inside MyAppBaseController.default()
$ python myapp.py --help
usage: myapp.py (sub-commands ...) [options ...] {arguments ...}
Base Controller
commands:
controller1
Controller1 Controller
controller2
Controller2 Controller
optional arguments:
-h, --help show this help message and exit
--debug toggle debug output
--quiet suppress all output
$ python myapp.py controller1
Inside Controller1.default()
$ python myapp.py controller1 --foo=bar
Foo option was passed with value: bar
Inside Controller1.default()
$ python myapp.py controller2
Inside Controller2.default()