Skip to content

Commit

Permalink
Using lazy property decorator instead of test alias.
Browse files Browse the repository at this point in the history
- Ignoring method-hidden (PyLint) so we can decorate methods in a class.
- Making _lazy_property_deco(deferred_callable) to decorate and re-use
  the function name and use it as a callable
- Had to hack around Python2.6 differences in `staticmethod`
  • Loading branch information
dhermes committed Feb 19, 2015
1 parent d5d3118 commit b9d96ed
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 15 deletions.
43 changes: 28 additions & 15 deletions gcloud/datastore/_implicit_environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,6 @@ def _determine_default_dataset_id(dataset_id=None):
return dataset_id


def _lazy_dataset_id():
"""Alias wrapper for _determine_default_dataset_id.
Unit test need to be able to replace _determine_default_dataset_id()
so we can't wrap the actual ``function`` object in a ``_LazyProperty``.
"""
return _determine_default_dataset_id()


def set_default_dataset_id(dataset_id=None):
"""Set default dataset ID either explicitly or implicitly as fall-back.
Expand Down Expand Up @@ -170,22 +161,40 @@ class _LazyProperty(object):
:type name: string
:param name: The name of the attribute / property being evaluated.
:type method: callable that takes no arguments
:param method: The method used to evaluate the property.
:type deferred_callable: callable that takes no arguments
:param deferred_callable: The function / method used to evaluate the
property.
"""

def __init__(self, name, method):
def __init__(self, name, deferred_callable):
self._name = name
self._method = method
self._deferred_callable = deferred_callable

def __get__(self, obj, objtype):
if obj is None or objtype is not _DefaultsContainer:
return self

setattr(obj, self._name, self._method())
setattr(obj, self._name, self._deferred_callable())
return getattr(obj, self._name)


def _lazy_property_deco(deferred_callable):
"""Decorator a method to create a :class:`_LazyProperty`.
:type deferred_callable: callable that takes no arguments
:param deferred_callable: The function / method used to evaluate the
property.
:rtype: :class:`_LazyProperty`.
:returns: A lazy property which defers the deferred_callable.
"""
if isinstance(deferred_callable, staticmethod):
# H/T: http://stackoverflow.com/a/9527450/1068170
# For Python2.7+ deferred_callable.__func__ would suffice.
deferred_callable = deferred_callable.__get__(True)
return _LazyProperty(deferred_callable.__name__, deferred_callable)


class _DefaultsContainer(object):
"""Container for defaults.
Expand All @@ -196,7 +205,11 @@ class _DefaultsContainer(object):
:param dataset_id: Persistent implied dataset ID from environment.
"""

dataset_id = _LazyProperty('dataset_id', _lazy_dataset_id)
@_lazy_property_deco
@staticmethod
def dataset_id():
"""Return the implicit default dataset ID."""
return _determine_default_dataset_id()

def __init__(self, connection=None, dataset_id=None, implicit=False):
self.connection = connection
Expand Down
23 changes: 23 additions & 0 deletions gcloud/datastore/test__implicit_environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,29 @@ def test_set_implicit_three_env_appengine_and_compute(self):
self.assertEqual(connection.timeout, None)


class Test__lazy_property_deco(unittest2.TestCase):

def _callFUT(self, deferred_callable):
from gcloud.datastore._implicit_environ import _lazy_property_deco
return _lazy_property_deco(deferred_callable)

def test_on_function(self):
def test_func():
pass # pragma: NO COVER never gets called

lazy_prop = self._callFUT(test_func)
self.assertTrue(lazy_prop._deferred_callable is test_func)
self.assertEqual(lazy_prop._name, 'test_func')

def test_on_staticmethod(self):
def test_func():
pass # pragma: NO COVER never gets called

lazy_prop = self._callFUT(staticmethod(test_func))
self.assertTrue(lazy_prop._deferred_callable is test_func)
self.assertEqual(lazy_prop._name, 'test_func')


class Test_lazy_loaded_dataset_id(unittest2.TestCase):

def setUp(self):
Expand Down
5 changes: 5 additions & 0 deletions pylintrc_default
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,18 @@ ignore =
# identical implementation but different docstrings.
# - star-args: standard Python idioms for varargs:
# ancestor = Query().filter(*order_props)
# - method-hidden: Decorating a method in a class (e.g. in _DefaultsContainer)
# @_lazy_property_deco
# def dataset_id():
# ...
disable =
maybe-no-member,
no-member,
protected-access,
redefined-builtin,
similarities,
star-args,
method-hidden,


[REPORTS]
Expand Down

0 comments on commit b9d96ed

Please sign in to comment.