Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove lazy property #991

Merged
merged 1 commit into from
Jul 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 0 additions & 84 deletions gcloud/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,49 +95,6 @@ def _ensure_tuple_or_list(arg_name, tuple_or_list):
return list(tuple_or_list)


class _LazyProperty(object):
"""Descriptor for lazy loaded property.

This follows the reify pattern: lazy evaluation and then replacement
after evaluation.

:type name: string
:param name: The name of the attribute / property being evaluated.

:type deferred_callable: callable that takes no arguments
:param deferred_callable: The function / method used to evaluate the
property.
"""

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

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

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)


def _app_engine_id():
"""Gets the App Engine application ID if it can be inferred.

Expand Down Expand Up @@ -211,44 +168,3 @@ def _determine_default_project(project=None):
project = _get_production_project()

return project


def set_default_project(project=None):
"""Set default project either explicitly or implicitly as fall-back.

:type project: string
:param project: Optional. The project name to use as default.

:raises: :class:`EnvironmentError` if no project was found.
"""
project = _determine_default_project(project=project)
if project is not None:
_DEFAULTS.project = project
else:
raise EnvironmentError('No project could be inferred.')


class _DefaultsContainer(object):
"""Container for defaults.

:type project: string
:param project: Persistent implied project from environment.

:type implicit: boolean
:param implicit: if False, assign the instance's ``project`` attribute
unconditionally; otherwise, assign it only if the
value is not None.
"""

@_lazy_property_deco
@staticmethod
def project():
"""Return the implicit default project."""
return _determine_default_project()

def __init__(self, project=None, implicit=False):
if project is not None or not implicit:
self.project = project


_DEFAULTS = _DefaultsContainer(implicit=True)
12 changes: 0 additions & 12 deletions gcloud/_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@

"""Shared testing utilities."""

from gcloud import _helpers
from gcloud._helpers import _DefaultsContainer


class _Monkey(object):
# context-manager for replacing module names in the scope of a test.
Expand All @@ -33,12 +30,3 @@ def __enter__(self):
def __exit__(self, exc_type, exc_val, exc_tb):
for key, value in self.to_restore.items():
setattr(self.module, key, value)


def _setup_defaults(test_case, *args, **kwargs):
test_case._replaced_defaults = _helpers._DEFAULTS
_helpers._DEFAULTS = _DefaultsContainer(*args, **kwargs)


def _tear_down_defaults(test_case):
_helpers._DEFAULTS = test_case._replaced_defaults
127 changes: 0 additions & 127 deletions gcloud/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,58 +70,6 @@ def test_invalid_iterable(self):
self._callFUT('ARGNAME', invalid_tuple_or_list)


class Test__LazyProperty(unittest2.TestCase):

def _getTargetClass(self):
from gcloud._helpers import _LazyProperty
return _LazyProperty

def _makeOne(self, *args, **kwargs):
return self._getTargetClass()(*args, **kwargs)

def test_prop_on_class(self):
# Don't actually need a callable for ``method`` since
# __get__ will just return ``self`` in this test.
data_prop = self._makeOne('dataset_id', None)

class FakeEnv(object):
dataset_id = data_prop

self.assertTrue(FakeEnv.dataset_id is data_prop)

def test_prop_on_instance(self):
RESULT = object()
data_prop = self._makeOne('dataset_id', lambda: RESULT)

class FakeEnv(object):
dataset_id = data_prop

self.assertTrue(FakeEnv().dataset_id is RESULT)


class Test__lazy_property_deco(unittest2.TestCase):

def _callFUT(self, deferred_callable):
from gcloud._helpers 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__app_engine_id(unittest2.TestCase):

def _callFUT(self):
Expand Down Expand Up @@ -254,81 +202,6 @@ def test_prod(self):
self.assertEqual(callers, ['prod_mock'])


class Test_set_default_project(unittest2.TestCase):

def setUp(self):
from gcloud._testing import _setup_defaults
_setup_defaults(self)

def tearDown(self):
from gcloud._testing import _tear_down_defaults
_tear_down_defaults(self)

def _callFUT(self, project=None):
from gcloud._helpers import set_default_project
return set_default_project(project=project)

def test_raises(self):
from gcloud._testing import _Monkey
from gcloud import _helpers
_called_project = []

def mock_determine(project):
_called_project.append(project)
return None

with _Monkey(_helpers, _determine_default_project=mock_determine):
self.assertRaises(EnvironmentError, self._callFUT)

self.assertEqual(_called_project, [None])

def test_set_correctly(self):
from gcloud._testing import _Monkey
from gcloud import _helpers

self.assertEqual(_helpers._DEFAULTS.project, None)

PROJECT = object()
_called_project = []

def mock_determine(project):
_called_project.append(project)
return PROJECT

with _Monkey(_helpers,
_determine_default_project=mock_determine):
self._callFUT()

self.assertEqual(_helpers._DEFAULTS.project, PROJECT)
self.assertEqual(_called_project, [None])


class Test_lazy_loading(unittest2.TestCase):

def setUp(self):
from gcloud._testing import _setup_defaults
_setup_defaults(self, implicit=True)

def tearDown(self):
from gcloud._testing import _tear_down_defaults
_tear_down_defaults(self)

def test_descriptor_for_project(self):
from gcloud._testing import _Monkey
from gcloud import _helpers

self.assertFalse('project' in _helpers._DEFAULTS.__dict__)

DEFAULT = object()

with _Monkey(_helpers,
_determine_default_project=lambda: DEFAULT):
lazy_loaded = _helpers._DEFAULTS.project

self.assertEqual(lazy_loaded, DEFAULT)
self.assertTrue('project' in _helpers._DEFAULTS.__dict__)


class _AppIdentity(object):

def __init__(self, app_id):
Expand Down