The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/pylxd/pull/119
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === The best thing about a good API is that it's guessable, and that the process of extending it has a clear path. The manager methods we provided were nice, but it quickly became clear in #115 that we needed a better/quicker/cleaner way of adding a manager. This simplifies the process greatly.
From 727643767764fd5551fe59960ec6162ce5346c33 Mon Sep 17 00:00:00 2001 From: Paul Hummer <p...@eventuallyanyway.com> Date: Mon, 30 May 2016 15:14:07 -0600 Subject: [PATCH] Refactor the manager protocol to be a little cleaner --- pylxd/client.py | 95 +++--------------------------------------------------- pylxd/container.py | 12 ++----- pylxd/managers.py | 45 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 100 deletions(-) create mode 100644 pylxd/managers.py diff --git a/pylxd/client.py b/pylxd/client.py index bd097a2..9b1d115 100644 --- a/pylxd/client.py +++ b/pylxd/client.py @@ -11,7 +11,6 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -import functools import os try: @@ -22,11 +21,7 @@ import requests import requests_unixsocket -from pylxd import exceptions -from pylxd.container import Container -from pylxd.image import Image -from pylxd.operation import Operation -from pylxd.profile import Profile +from pylxd import exceptions, managers requests_unixsocket.monkeypatch() @@ -114,86 +109,6 @@ class Client(object): >>> print api.containers['test'].get().json() """ - class Containers(object): - """ - Manager for :class:`~pylxd.container.Container` of a :class:`Client`. - - .. attribute:: all - - Partial of :meth:`Container.all <pylxd.container.Container.all>`, - calling it without argument returns the same as calling that method - with just the client argument. - - .. attribute:: get - - Partial of of :meth:`Container.get - <pylxd.container.Container.get>`. - - .. attribute:: create - - Partial of of :meth:`Container.create - <pylxd.container.Container.create>`. - """ - def __init__(self, client): - self.get = functools.partial(Container.get, client) - self.all = functools.partial(Container.all, client) - self.create = functools.partial(Container.create, client) - - class Images(object): - """ - Manager for :py:class:`~pylxd.image.Image` of a :class:`Client`. - - .. attribute:: all - - Partial of :meth:`Image.all <pylxd.image.Image.all>`, - - .. attribute:: get - - Partial of of :meth:`Image.get <pylxd.image.Image.get>`. - - .. attribute:: create - - Partial of of :meth:`Image.create <pylxd.image.Image.create>`. - """ - def __init__(self, client): - self.get = functools.partial(Image.get, client) - self.all = functools.partial(Image.all, client) - self.create = functools.partial(Image.create, client) - - class Operations(object): - """ - Manager for :class:`~pylxd.operation.Operation` of a :class:`Client`. - - .. attribute:: get - - Partial of of :meth:`Operation.get - <pylxd.operation.Operation.get>`. - """ - def __init__(self, client): - self.get = functools.partial(Operation.get, client) - - class Profiles(object): - """ - Manager for :py:class:`~pylxd.profile.Profile` of a :class:`Client`. - - .. attribute:: all - - Partial of :meth:`Profile.all <pylxd.profile.Profile.all>`, - - .. attribute:: get - - Partial of of :meth:`Profile.get <pylxd.profile.Profile.get>`. - - .. attribute:: create - - Partial of of :meth:`Profile.create - <pylxd.profile.Profile.create>`. - """ - def __init__(self, client): - self.get = functools.partial(Profile.get, client) - self.all = functools.partial(Profile.all, client) - self.create = functools.partial(Profile.create, client) - def __init__(self, endpoint=None, version='1.0', cert=None, verify=True): if endpoint is not None: self.api = _APINode(endpoint, cert=cert, verify=verify) @@ -219,7 +134,7 @@ def __init__(self, endpoint=None, version='1.0', cert=None, verify=True): requests.exceptions.InvalidURL): raise exceptions.ClientConnectionFailed() - self.containers = self.Containers(self) - self.images = self.Images(self) - self.operations = self.Operations(self) - self.profiles = self.Profiles(self) + self.containers = managers.ContainerManager(self) + self.images = managers.ImageManager(self) + self.operations = managers.OperationManager(self) + self.profiles = managers.ProfileManager(self) diff --git a/pylxd/container.py b/pylxd/container.py index 66a751b..ce9de61 100644 --- a/pylxd/container.py +++ b/pylxd/container.py @@ -11,11 +11,9 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -import functools - import six -from pylxd import exceptions, mixin +from pylxd import exceptions, managers, mixin from pylxd.deprecation import deprecated from pylxd.operation import Operation @@ -33,12 +31,6 @@ class Container(mixin.Waitable, mixin.Marshallable): via `Client.containers.create`. """ - class Snapshots(object): - def __init__(self, client, container): - self.get = functools.partial(Snapshot.get, client, container) - self.all = functools.partial(Snapshot.all, client, container) - self.create = functools.partial(Snapshot.create, client, container) - __slots__ = [ '_client', 'architecture', 'config', 'created_at', 'devices', 'ephemeral', @@ -88,7 +80,7 @@ def __init__(self, **kwargs): for key, value in six.iteritems(kwargs): setattr(self, key, value) - self.snapshots = self.Snapshots(self._client, self) + self.snapshots = managers.SnapshotManager(self._client, self) def fetch(self): """Reload the container information.""" diff --git a/pylxd/managers.py b/pylxd/managers.py new file mode 100644 index 0000000..be33b7b --- /dev/null +++ b/pylxd/managers.py @@ -0,0 +1,45 @@ +import functools +import importlib +import inspect + + +class BaseManager(object): + """A BaseManager class for handling collection operations.""" + + @property + def manager_for(self): + raise AttributeError( + "Manager class requires 'manager_for' attribute") + + def __init__(self, *args, **kwargs): + manager_for = self.manager_for + module = '.'.join(manager_for.split('.')[0:-1]) + obj = manager_for.split('.')[-1] + target_module = importlib.import_module(module) + target = getattr(target_module, obj) + + methods = inspect.getmembers(target, predicate=inspect.ismethod) + for name, method in methods: + func = functools.partial(method, *args, **kwargs) + setattr(self, name, func) + return super(BaseManager, self).__init__() + + +class ContainerManager(BaseManager): + manager_for = 'pylxd.container.Container' + + +class ImageManager(BaseManager): + manager_for = 'pylxd.image.Image' + + +class ProfileManager(BaseManager): + manager_for = 'pylxd.profile.Profile' + + +class OperationManager(BaseManager): + manager_for = 'pylxd.operation.Operation' + + +class SnapshotManager(BaseManager): + manager_for = 'pylxd.container.Snapshot'
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel