You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by er...@apache.org on 2016/01/05 23:41:12 UTC
[1/2] libcloud git commit: Implemented LazyObject class,
which provides a .lazy class method. The lazy class method returns a
Proxy object that subclasses the target object class. Upon accessing the
proxy object in any way, the object is initialized.
Repository: libcloud
Updated Branches:
refs/heads/trunk 94c6b9143 -> 9a7556f46
Implemented LazyObject class, which provides a .lazy class method. The lazy class method returns a Proxy object that subclasses the target object class. Upon accessing the proxy object in any way, the object is initialized.
Modified Google Compute Engine License objects, GCELicense, to be such a lazy
object. This addresses https://issues.apache.org/jira/browse/LIBCLOUD-786.
Tests/Verification:
tox -e lint
python setup.py test
Added test/common/test_base.py which has LazyObjectTest
Signed-off-by: Eric Johnson <er...@google.com>
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/81a8dbc3
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/81a8dbc3
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/81a8dbc3
Branch: refs/heads/trunk
Commit: 81a8dbc324f870444e980aee523fea48fc37cbcc
Parents: 94c6b91
Author: Scott Crunkleton <cr...@google.com>
Authored: Tue Dec 22 00:21:06 2015 -0800
Committer: Eric Johnson <er...@google.com>
Committed: Tue Jan 5 22:29:27 2016 +0000
----------------------------------------------------------------------
libcloud/common/base.py | 35 +++++++++++++++++++
libcloud/compute/drivers/gce.py | 63 ++++++++++++++++------------------
libcloud/test/common/test_base.py | 44 ++++++++++++++++++++++++
3 files changed, 109 insertions(+), 33 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/libcloud/blob/81a8dbc3/libcloud/common/base.py
----------------------------------------------------------------------
diff --git a/libcloud/common/base.py b/libcloud/common/base.py
index 0825eca..959215a 100644
--- a/libcloud/common/base.py
+++ b/libcloud/common/base.py
@@ -76,6 +76,41 @@ __all__ = [
RETRY_FAILED_HTTP_REQUESTS = False
+class LazyObject(object):
+ """An object that doesn't get initialized until accessed."""
+
+ @classmethod
+ def _proxy(cls, *lazy_init_args, **lazy_init_kwargs):
+ class Proxy(cls, object):
+ _lazy_obj = None
+
+ def __init__(self):
+ # Must override the lazy_cls __init__
+ pass
+
+ def __getattribute__(self, attr):
+ lazy_obj = object.__getattribute__(self, '_get_lazy_obj')()
+ return getattr(lazy_obj, attr)
+
+ def __setattr__(self, attr, value):
+ lazy_obj = object.__getattribute__(self, '_get_lazy_obj')()
+ setattr(lazy_obj, attr, value)
+
+ def _get_lazy_obj(self):
+ lazy_obj = object.__getattribute__(self, '_lazy_obj')
+ if lazy_obj is None:
+ lazy_obj = cls(*lazy_init_args, **lazy_init_kwargs)
+ object.__setattr__(self, '_lazy_obj', lazy_obj)
+ return lazy_obj
+
+ return Proxy()
+
+ @classmethod
+ def lazy(cls, *lazy_init_args, **lazy_init_kwargs):
+ """Create a lazily instantiated instance of the subclass, cls."""
+ return cls._proxy(*lazy_init_args, **lazy_init_kwargs)
+
+
class HTTPResponse(httplib.HTTPResponse):
# On python 2.6 some calls can hang because HEAD isn't quite properly
# supported.
http://git-wip-us.apache.org/repos/asf/libcloud/blob/81a8dbc3/libcloud/compute/drivers/gce.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/gce.py b/libcloud/compute/drivers/gce.py
index 84ac64d..4a5181e 100644
--- a/libcloud/compute/drivers/gce.py
+++ b/libcloud/compute/drivers/gce.py
@@ -21,6 +21,7 @@ import datetime
import time
import sys
+from libcloud.common.base import LazyObject
from libcloud.common.google import GoogleResponse
from libcloud.common.google import GoogleBaseConnection
from libcloud.common.google import GoogleBaseError
@@ -231,15 +232,37 @@ class GCEList(object):
return self
-class GCELicense(UuidMixin):
+class GCELicense(UuidMixin, LazyObject):
"""A GCE License used to track software usage in GCE nodes."""
- def __init__(self, id, name, driver, charges_use_fee, extra=None):
- self.id = str(id)
+ def __init__(self, name, project, driver):
+ UuidMixin.__init__(self)
+ self.id = name
self.name = name
+ self.project = project
self.driver = driver
- self.charges_use_fee = charges_use_fee
- self.extra = extra or {}
- UuidMixin.__init__(self)
+ self.charges_use_fee = None # init in _request
+ self.extra = None # init in _request
+
+ self._request()
+
+ def _request(self):
+ # TODO(crunkleton@google.com): create new connection? or make
+ # connection thread-safe? Saving, modifying, and restoring
+ # driver.connection.request_path is really hacky and thread-unsafe.
+ saved_request_path = self.driver.connection.request_path
+ new_request_path = saved_request_path.replace(self.driver.project,
+ self.project)
+ self.driver.connection.request_path = new_request_path
+
+ request = '/global/licenses/%s' % self.name
+ response = self.driver.connection.request(request, method='GET').object
+ self.driver.connection.request_path = saved_request_path
+
+ self.extra = {
+ 'selfLink': response.get('selfLink'),
+ 'kind': response.get('kind')
+ }
+ self.charges_use_fee = response['chargesUseFee']
def destroy(self):
raise ProviderError("Can not destroy a License resource.")
@@ -3913,15 +3936,7 @@ class GCENodeDriver(NodeDriver):
:return: A DiskType object for the name
:rtype: :class:`GCEDiskType`
"""
- saved_request_path = self.connection.request_path
- new_request_path = saved_request_path.replace(self.project, project)
- self.connection.request_path = new_request_path
-
- request = '/global/licenses/%s' % (name)
- response = self.connection.request(request, method='GET').object
- self.connection.request_path = saved_request_path
-
- return self._to_license(response)
+ return GCELicense.lazy(name, project, self)
def ex_get_disktype(self, name, zone=None):
"""
@@ -5691,24 +5706,6 @@ class GCENodeDriver(NodeDriver):
maintenance_windows=zone.get('maintenanceWindows'),
deprecated=deprecated, driver=self, extra=extra)
- def _to_license(self, license):
- """
- Return a License object from the JSON-response dictionary.
-
- :param license: The dictionary describing the license.
- :type license: ``dict``
-
- :return: License object
- :rtype: :class:`GCELicense`
- """
- extra = {}
- extra['selfLink'] = license.get('selfLink')
- extra['kind'] = license.get('kind')
-
- return GCELicense(id=license['name'], name=license['name'],
- charges_use_fee=license['chargesUseFee'],
- driver=self, extra=extra)
-
def _set_project_metadata(self, metadata=None, force=False,
current_keys=""):
"""
http://git-wip-us.apache.org/repos/asf/libcloud/blob/81a8dbc3/libcloud/test/common/test_base.py
----------------------------------------------------------------------
diff --git a/libcloud/test/common/test_base.py b/libcloud/test/common/test_base.py
new file mode 100644
index 0000000..9c7070d
--- /dev/null
+++ b/libcloud/test/common/test_base.py
@@ -0,0 +1,44 @@
+import unittest
+import sys
+
+import mock
+
+from libcloud.common.base import LazyObject
+from libcloud.test import LibcloudTestCase
+
+
+class LazyObjectTest(LibcloudTestCase):
+
+ class A(LazyObject):
+ def __init__(self, x, y=None):
+ self.x = x
+ self.y = y
+
+ def test_lazy_init(self):
+ # Test normal init
+ a = self.A(1, y=2)
+ self.assertTrue(isinstance(a, self.A))
+
+ # Test lazy init
+ with mock.patch.object(self.A,
+ '__init__', return_value=None) as mock_init:
+ a = self.A.lazy(3, y=4)
+ self.assertTrue(isinstance(a, self.A)) # Proxy is a subclass of A
+ mock_init.assert_not_called()
+
+ # Since we have a mock init, an A object doesn't actually get
+ # created. But, we can still call __dict__ on the proxy, which will
+ # init the lazy object.
+ self.assertEqual(a.__dict__, {})
+ mock_init.assert_called_once_with(3, y=4)
+
+ def test_setattr(self):
+ a = self.A.lazy('foo', y='bar')
+ a.z = 'baz'
+ wrapped_lazy_obj = object.__getattribute__(a, '_lazy_obj')
+ self.assertEqual(a.z, 'baz')
+ self.assertEqual(wrapped_lazy_obj.z, 'baz')
+
+
+if __name__ == '__main__':
+ sys.exit(unittest.main())
[2/2] libcloud git commit: updating changes.rst file
Posted by er...@apache.org.
updating changes.rst file
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/9a7556f4
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/9a7556f4
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/9a7556f4
Branch: refs/heads/trunk
Commit: 9a7556f469e45baf8d404ace99927c5cddf7e829
Parents: 81a8dbc
Author: Eric Johnson <er...@google.com>
Authored: Tue Jan 5 22:36:51 2016 +0000
Committer: Eric Johnson <er...@google.com>
Committed: Tue Jan 5 22:36:51 2016 +0000
----------------------------------------------------------------------
CHANGES.rst | 4 ++++
1 file changed, 4 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/libcloud/blob/9a7556f4/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index efa3f5c..3270266 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -14,6 +14,10 @@ General
Compute
~~~~~~~
+- Add LazyObject class that provides lazy-loading, see `GCELicense` for usage
+ (LIBCLOUD-786, GITHUB-665)
+ [Scott Crunkleton]
+
- Added t2.nano instance type to EC2 Compute driver
(GITHUB-663)
[Anthony Shaw]