diff options
Diffstat (limited to 'ipalib')
-rw-r--r-- | ipalib/cli.py | 19 | ||||
-rw-r--r-- | ipalib/frontend.py | 99 |
2 files changed, 109 insertions, 9 deletions
diff --git a/ipalib/cli.py b/ipalib/cli.py index 7148afc1c..365eea20a 100644 --- a/ipalib/cli.py +++ b/ipalib/cli.py @@ -154,25 +154,28 @@ class plugins(text_ui): """Show all loaded plugins""" def run(self): + plugins = sorted(self.api.plugins, key=lambda o: o.plugin) + return tuple( + (p.plugin, p.bases) for p in plugins + ) + + def output_for_cli(self, result): self.print_name() first = True - for p in sorted(self.api.plugins, key=lambda o: o.plugin): + for (plugin, bases) in result: if first: first = False else: print '' - print ' plugin: %s' % p.plugin - print ' in namespaces: %s' % ', '.join(p.bases) - if len(self.api.plugins) == 1: + print ' Plugin: %s' % plugin + print ' In namespaces: %s' % ', '.join(bases) + if len(result) == 1: s = '1 plugin loaded.' else: - s = '%d plugins loaded.' % len(self.api.plugins) + s = '%d plugins loaded.' % len(result) self.print_dashed(s) - - - cli_application_commands = ( help, console, diff --git a/ipalib/frontend.py b/ipalib/frontend.py index d2985fa73..e0d6fa787 100644 --- a/ipalib/frontend.py +++ b/ipalib/frontend.py @@ -121,7 +121,8 @@ class DefaultFrom(plugable.ReadOnly): raise TypeError('callback must be callable; got %r' % callback) self.callback = callback if len(keys) == 0: - self.keys = callback.func_code.co_varnames + fc = callback.func_code + self.keys = fc.co_varnames[:fc.co_argcount] else: self.keys = keys for key in self.keys: @@ -856,6 +857,40 @@ class Object(plugable.Plugin): class Attribute(plugable.Plugin): + """ + Base class implementing the attribute-to-object association. + + `Attribute` plugins are associated with an `Object` plugin to group + a common set of commands that operate on a common set of parameters. + + The association between attribute and object is done using a simple + naming convention: the first part of the plugin class name (up to the + first underscore) is the object name, and rest is the attribute name, + as this table shows: + + ============= =========== ============== + Class name Object name Attribute name + ============= =========== ============== + user_add user add + noun_verb noun verb + door_open_now door open_door + ============= =========== ============== + + For example: + + >>> class user_add(Attribute): + ... pass + ... + >>> instance = user_add() + >>> instance.obj_name + 'user' + >>> instance.attr_name + 'add' + + In practice the `Attribute` class is not used directly, but rather is + only the base class for the `Method` and `Property` classes. Also see + the `Object` class. + """ __public__ = frozenset(( 'obj', 'obj_name', @@ -893,6 +928,68 @@ class Attribute(plugable.Plugin): class Method(Attribute, Command): + """ + A command with an associated object. + + A `Method` plugin must have a corresponding `Object` plugin. The + association between object and method is done through a simple naming + convention: the first part of the method name (up to the first under + score) is the object name, as the examples in this table show: + + ============= =========== ============== + Method name Object name Attribute name + ============= =========== ============== + user_add user add + noun_verb noun verb + door_open_now door open_door + ============= =========== ============== + + There are three different places a method can be accessed. For example, + say you created a `Method` plugin and its corresponding `Object` plugin + like this: + + >>> api = plugable.API(Command, Object, Method, Property) + >>> class user_add(Method): + ... def run(self): + ... return 'Added the user!' + ... + >>> class user(Object): + ... pass + ... + >>> api.register(user_add) + >>> api.register(user) + >>> api.finalize() + + First, the ``user_add`` plugin can be accessed through the ``api.Method`` + namespace: + + >>> list(api.Method) + ['user_add'] + >>> api.Method.user_add() # Will call user_add.run() + 'Added the user!' + + Second, because `Method` is a subclass of `Command`, the ``user_add`` + plugin can also be accessed through the ``api.Command`` namespace: + + >>> list(api.Command) + ['user_add'] + >>> api.Command.user_add() # Will call user_add.run() + 'Added the user!' + + And third, ``user_add`` can be accessed as an attribute on the ``user`` + `Object`: + + >>> list(api.Object) + ['user'] + >>> list(api.Object.user.methods) + ['add'] + >>> api.Object.user.methods.add() # Will call user_add.run() + 'Added the user!' + + The `Attribute` base class implements the naming convention for the + attribute-to-object association. Also see the `Object` and the + `Property` classes. + """ __public__ = Attribute.__public__.union(Command.__public__) def __init__(self): |