summaryrefslogtreecommitdiffstats
path: root/ipalib/__init__.py
diff options
context:
space:
mode:
authorPetr Viktorin <pviktori@redhat.com>2012-06-21 08:20:26 -0400
committerMartin Kosek <mkosek@redhat.com>2013-02-21 16:26:09 +0100
commit7336a176b43989b9d459a2536af88f89e849213f (patch)
tree46c2ab141dc545e8f0c148871508fe7c952d22e5 /ipalib/__init__.py
parent246bc3f3eaccf2a84310df84dc85fe455c24ac65 (diff)
downloadfreeipa-7336a176b43989b9d459a2536af88f89e849213f.tar.gz
freeipa-7336a176b43989b9d459a2536af88f89e849213f.tar.xz
freeipa-7336a176b43989b9d459a2536af88f89e849213f.zip
Add the version option to all Commands
Several Commands were missing the 'version' option. Add it to those that were missing it. Do not remove the version option before calling commands. This means methods such as execute(), forward(), run() receive it. Several of these needed `**options` added to their signatures. Commands in the Cert plugin passed any unknown options to the underlying functions, these are changed to pass what's needed explicitly. Some commands in DNS and Batch plugins now pass version to commands they call. When the option is not given, fill it in automatically. (In a subsequent commit, a warning will be added in this case). Note that the public API did not change: all RPC calls already accepted a version option. There's no need for an API version bump (even though API.txt changes substantially). Design page: http://freeipa.org/page/V3/Messages Tickets: https://fedorahosted.org/freeipa/ticket/2732 https://fedorahosted.org/freeipa/ticket/3294
Diffstat (limited to 'ipalib/__init__.py')
-rw-r--r--ipalib/__init__.py51
1 files changed, 29 insertions, 22 deletions
diff --git a/ipalib/__init__.py b/ipalib/__init__.py
index 8bf37f048..aab740081 100644
--- a/ipalib/__init__.py
+++ b/ipalib/__init__.py
@@ -134,7 +134,7 @@ implement a ``run()`` method, like this:
>>> class my_command(Command):
... """My example plugin with run()."""
...
-... def run(self):
+... def run(self, **options):
... return dict(result='My run() method was called!')
...
>>> api = create_api()
@@ -174,17 +174,22 @@ For example, say you have a command plugin like this:
>>> class my_command(Command):
... """Forwarding vs. execution."""
...
-... def forward(self):
+... def forward(self, **options):
... return dict(
... result='forward(): in_server=%r' % self.env.in_server
... )
...
-... def execute(self):
+... def execute(self, **options):
... return dict(
... result='execute(): in_server=%r' % self.env.in_server
... )
...
+The ``options`` will contain a dict of command options. One option is added
+automatically: ``version``. It contains the API version of the client.
+In order to maintain forward compatibility, you should always specify the
+API version current at the time you're writing your client.
+
If ``my_command`` is loaded in a *client* context, ``forward()`` will be
called:
@@ -192,7 +197,7 @@ called:
>>> api.env.in_server = False # run() will dispatch to forward()
>>> api.register(my_command)
>>> api.finalize()
->>> api.Command.my_command() # Call your command plugin
+>>> api.Command.my_command(version=u'2.47') # Call your command plugin
{'result': 'forward(): in_server=False'}
On the other hand, if ``my_command`` is loaded in a *server* context,
@@ -202,7 +207,7 @@ On the other hand, if ``my_command`` is loaded in a *server* context,
>>> api.env.in_server = True # run() will dispatch to execute()
>>> api.register(my_command)
>>> api.finalize()
->>> api.Command.my_command() # Call your command plugin
+>>> api.Command.my_command(version=u'2.47') # Call your command plugin
{'result': 'execute(): in_server=True'}
Normally there should be no reason to override `frontend.Command.forward()`,
@@ -314,7 +319,7 @@ Second, we have our frontend plugin, the command:
>>> class my_command(Command):
... """My example command plugin."""
...
-... def execute(self):
+... def execute(self, **options):
... """Implemented against Backend.my_backend"""
... return dict(result=self.Backend.my_backend.do_stuff())
...
@@ -324,7 +329,7 @@ Lastly, we call ``api.finalize()`` and see what happens when we call
``my_command()``:
>>> api.finalize()
->>> api.Command.my_command()
+>>> api.Command.my_command(version=u'2.47')
{'result': 'my_backend.do_stuff() indeed did do stuff!'}
When not in a server context, ``my_command.execute()`` never gets called, so
@@ -337,11 +342,11 @@ example:
>>> class my_command(Command):
... """My example command plugin."""
...
-... def execute(self):
+... def execute(self, **options):
... """Same as above."""
... return dict(result=self.Backend.my_backend.do_stuff())
...
-... def forward(self):
+... def forward(self, **options):
... return dict(result='Just my_command.forward() getting called here.')
...
>>> api.register(my_command)
@@ -371,7 +376,7 @@ several other commands in a single operation. For example:
>>> class meta_command(Command):
... """My meta-command plugin."""
...
-... def execute(self):
+... def execute(self, **options):
... """Calls command_1(), command_2()"""
... msg = '%s; %s.' % (
... self.Command.command_1()['result'],
@@ -379,18 +384,18 @@ several other commands in a single operation. For example:
... )
... return dict(result=msg)
>>> class command_1(Command):
-... def execute(self):
+... def execute(self, **options):
... return dict(result='command_1.execute() called')
...
>>> class command_2(Command):
-... def execute(self):
+... def execute(self, **options):
... return dict(result='command_2.execute() called')
...
>>> api.register(meta_command)
>>> api.register(command_1)
>>> api.register(command_2)
>>> api.finalize()
->>> api.Command.meta_command()
+>>> api.Command.meta_command(version=u'2.47')
{'result': 'command_1.execute() called; command_2.execute() called.'}
Because this is quite useful, we are going to revise our golden rule somewhat:
@@ -425,9 +430,9 @@ For example:
>>> api.env.in_server = True
>>> api.register(nudge)
>>> api.finalize()
->>> api.Command.nudge(u'Jason')
+>>> api.Command.nudge(u'Jason', version=u'2.47')
{'result': u'Jason, go write more documentation!'}
->>> api.Command.nudge(u'Jason', stuff=u'unit tests')
+>>> api.Command.nudge(u'Jason', stuff=u'unit tests', version=u'2.47')
{'result': u'Jason, go write more unit tests!'}
The ``args`` and ``options`` attributes are `plugable.NameSpace` instances
@@ -438,25 +443,27 @@ containing a command's arguments and options, respectively, as you can see:
>>> api.Command.nudge.args.programmer
Str('programmer')
>>> list(api.Command.nudge.options) # Iterates through option names
-['stuff']
+['stuff', 'version']
>>> api.Command.nudge.options.stuff
Str('stuff', default=u'documentation')
>>> api.Command.nudge.options.stuff.default
u'documentation'
+The 'version' option is added to commands automatically.
+
The arguments and options must not contain colliding names. They are both
merged together into the ``params`` attribute, another `plugable.NameSpace`
instance, as you can see:
>>> api.Command.nudge.params
-NameSpace(<2 members>, sort=False)
+NameSpace(<3 members>, sort=False)
>>> list(api.Command.nudge.params) # Iterates through the param names
-['programmer', 'stuff']
+['programmer', 'stuff', 'version']
When calling a command, its positional arguments can also be provided as
keyword arguments, and in any order. For example:
->>> api.Command.nudge(stuff=u'lines of code', programmer=u'Jason')
+>>> api.Command.nudge(stuff=u'lines of code', programmer=u'Jason', version=u'2.47')
{'result': u'Jason, go write more lines of code!'}
When a command plugin is called, the values supplied for its parameters are
@@ -669,7 +676,7 @@ For example:
...
... takes_args = 'color'
...
-... def execute(self, color):
+... def execute(self, color, **options):
... """Uses self.log.error()"""
... if color not in ('red', 'blue', 'green'):
... self.log.error("I don't have %s paint!", color) # Log error
@@ -746,14 +753,14 @@ For example:
>>> class motd(Command):
... """Print message of the day."""
...
-... def execute(self):
+... def execute(self, **options):
... return dict(result=self.env.message)
...
>>> api = create_api()
>>> api.bootstrap(in_server=True, message='Hello, world!')
>>> api.register(motd)
>>> api.finalize()
->>> api.Command.motd()
+>>> api.Command.motd(version=u'2.47')
{'result': u'Hello, world!'}
Also see the `plugable.API.bootstrap_with_global_options()` method.