launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #06672
[Merge] lp:~allenap/maas/papi-no-kwargs-2 into lp:maas
Gavin Panella has proposed merging lp:~allenap/maas/papi-no-kwargs-2 into lp:maas.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~allenap/maas/papi-no-kwargs-2/+merge/97249
--
https://code.launchpad.net/~allenap/maas/papi-no-kwargs-2/+merge/97249
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~allenap/maas/papi-no-kwargs-2 into lp:maas.
=== modified file 'src/provisioningserver/testing/fakeapi.py'
--- src/provisioningserver/testing/fakeapi.py 2012-03-13 14:13:08 +0000
+++ src/provisioningserver/testing/fakeapi.py 2012-03-13 15:55:24 +0000
@@ -30,19 +30,6 @@
from zope.interface.interface import Method
-def prevent_keyword_args(func):
- """Forbid use of keyword arguments.
-
- The Provisioning API is meant to be used via XML-RPC, at least for now, so
- we prevent all API methods from being used with keyword arguments, which
- are not supported via XML-RPC.
- """
- @wraps(func)
- def wrapper(*args):
- return func(*args)
- return wrapper
-
-
class FakeProvisioningDatabase(dict):
def __missing__(self, key):
@@ -77,12 +64,12 @@
@implementer(IProvisioningAPI)
-class FakeSynchronousProvisioningAPI:
+class FakeProvisioningAPIBase:
# TODO: Referential integrity might be a nice thing.
def __init__(self):
- super(FakeSynchronousProvisioningAPI, self).__init__()
+ super(FakeProvisioningAPIBase, self).__init__()
self.distros = FakeProvisioningDatabase()
self.profiles = FakeProvisioningDatabase()
self.nodes = FakeProvisioningDatabase()
@@ -97,18 +84,15 @@
# happened most recently).
self.power_status = {}
- @prevent_keyword_args
def add_distro(self, name, initrd, kernel):
self.distros[name]["initrd"] = initrd
self.distros[name]["kernel"] = kernel
return name
- @prevent_keyword_args
def add_profile(self, name, distro):
self.profiles[name]["distro"] = distro
return name
- @prevent_keyword_args
def add_node(self, name, profile, power_type, metadata):
self.nodes[name]["profile"] = profile
self.nodes[name]["mac_addresses"] = []
@@ -116,83 +100,107 @@
self.power_types[name] = power_type
return name
- @prevent_keyword_args
def modify_distros(self, deltas):
for name, delta in deltas.items():
distro = self.distros[name]
distro.update(delta)
- @prevent_keyword_args
def modify_profiles(self, deltas):
for name, delta in deltas.items():
profile = self.profiles[name]
profile.update(delta)
- @prevent_keyword_args
def modify_nodes(self, deltas):
for name, delta in deltas.items():
node = self.nodes[name]
node.update(delta)
- @prevent_keyword_args
def get_distros_by_name(self, names):
return self.distros.select(names)
- @prevent_keyword_args
def get_profiles_by_name(self, names):
return self.profiles.select(names)
- @prevent_keyword_args
def get_nodes_by_name(self, names):
return self.nodes.select(names)
- @prevent_keyword_args
def delete_distros_by_name(self, names):
return self.distros.delete(names)
- @prevent_keyword_args
def delete_profiles_by_name(self, names):
return self.profiles.delete(names)
- @prevent_keyword_args
def delete_nodes_by_name(self, names):
return self.nodes.delete(names)
- @prevent_keyword_args
def get_distros(self):
return self.distros.dump()
- @prevent_keyword_args
def get_profiles(self):
return self.profiles.dump()
- @prevent_keyword_args
def get_nodes(self):
return self.nodes.dump()
- @prevent_keyword_args
def start_nodes(self, names):
for name in names:
self.power_status[name] = 'start'
- @prevent_keyword_args
def stop_nodes(self, names):
for name in names:
self.power_status[name] = 'stop'
-def async(func):
- """Decorate a function so that it always return a `defer.Deferred`."""
- @wraps(func)
- def wrapper(*args, **kwargs):
- return defer.execute(func, *args, **kwargs)
- return wrapper
-
-
-# Generate an asynchronous variant based on the synchronous one.
+PAPI_METHODS = {
+ name: getattr(FakeProvisioningAPIBase, name)
+ for name in IProvisioningAPI.names(all=True)
+ if isinstance(IProvisioningAPI[name], Method)
+ }
+
+
+def sync_xmlrpc_func(func):
+ """Decorate a function so that it acts similarly to a synchronously
+ accessed remote XML-RPC call.
+
+ All method calls return synchronously.
+ """
+ @wraps(func)
+ def wrapper(*args, **kwargs):
+ assert len(kwargs) == 0, (
+ "The Provisioning API is meant to be used via XML-RPC, "
+ "for now, so its methods are prevented from use with "
+ "keyword arguments, which XML-RPC does not support.")
+ # TODO: Convert exceptions into Faults.
+ return func(*args)
+ return wrapper
+
+
+# Generate an synchronous variant.
+FakeSynchronousProvisioningAPI = type(
+ b"FakeSynchronousProvisioningAPI", (FakeProvisioningAPIBase,), {
+ name: sync_xmlrpc_func(func) for name, func in PAPI_METHODS.items()
+ })
+
+
+def async_xmlrpc_func(func):
+ """Decorate a function so that it acts similarly to an asynchronously
+ accessed remote XML-RPC call.
+
+ All method calls return asynchronously, via a :class:`defer.Deferred`.
+ """
+ @wraps(func)
+ def wrapper(*args, **kwargs):
+ assert len(kwargs) == 0, (
+ "The Provisioning API is meant to be used via XML-RPC, "
+ "for now, so its methods are prevented from use with "
+ "keyword arguments, which XML-RPC does not support.")
+ # TODO: Convert exceptions into Faults.
+ return defer.execute(func, *args)
+ return wrapper
+
+
+# Generate an asynchronous variant.
FakeAsynchronousProvisioningAPI = type(
- b"FakeAsynchronousProvisioningAPI", (FakeSynchronousProvisioningAPI,), {
- name: async(getattr(FakeSynchronousProvisioningAPI, name))
- for name in IProvisioningAPI.names(all=True)
- if isinstance(IProvisioningAPI[name], Method)
+ b"FakeAsynchronousProvisioningAPI", (FakeProvisioningAPIBase,), {
+ name: async_xmlrpc_func(func) for name, func in PAPI_METHODS.items()
})