summaryrefslogtreecommitdiffstats
path: root/ipalib
diff options
context:
space:
mode:
Diffstat (limited to 'ipalib')
-rw-r--r--ipalib/cli.py19
-rw-r--r--ipalib/frontend.py99
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):