Skip to content

Commit

Permalink
Performance optimisations, bumped to 1.0.2
Browse files Browse the repository at this point in the history
Cached property no longer works like @Property, cannot have a setter.
  • Loading branch information
simoncoulton committed Feb 11, 2014
1 parent 5c1e8ca commit 13b6363
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 24 deletions.
3 changes: 2 additions & 1 deletion tests/watson/common/test_decorators.py
Expand Up @@ -14,5 +14,6 @@ def expensive_prop(self):

c = MyClass()
assert c.expensive_prop == 'This is an expensive call'
del c.expensive_prop
assert hasattr(c, '_expensive_prop')
del c._expensive_prop
assert not hasattr(c, '_expensive_prop')
5 changes: 3 additions & 2 deletions tests/watson/common/test_imports.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from pytest import raises
from watson.common import imports
from tests.watson.common.support import some_func

Expand All @@ -17,5 +18,5 @@ def test_load_definition_from_string(self):
assert isinstance(data, dict)

def test_load_invalid_definition(self):
assert None == imports.load_definition_from_string(
'invalid.module.Class')
with raises(ImportError):
imports.load_definition_from_string('invalid.module.Class')
2 changes: 1 addition & 1 deletion watson/common/__init__.py
@@ -1,2 +1,2 @@
# -*- coding: utf-8 -*-
__version__ = '1.0.1'
__version__ = '1.0.2'
8 changes: 8 additions & 0 deletions watson/common/datastructures.py
Expand Up @@ -80,6 +80,11 @@ class MultiDict(dict):
print(multi_dict) # {'one': [1, 'itchi']}
"""

def __init__(self, args=None):
items = args.items() if isinstance(args, dict) else args or ()
for key, value in items:
self.set(key, value)

def set(self, key, value, replace=False):
"""Add a new item to the dictionary.
Expand Down Expand Up @@ -113,6 +118,9 @@ def __setitem__(self, key, value, replace=False):
value = existing
dict.__setitem__(self, key, value)

def __getitem__(self, key, default=None):
return self.get(key, default)

def update(self, a_dict):
for key, value in a_dict.items():
self[key] = value
Expand Down
32 changes: 14 additions & 18 deletions watson/common/decorators.py
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
from functools import update_wrapper


def cached_property(func):
class cached_property(object):

"""Allows expensive property calls to be cached.
Once the property is called, it's result is stored in the corresponding
property name prefixed with an underscore.
Example:
.. code-block:: python
Expand All @@ -18,20 +18,16 @@ def expensive_call(self):
klass = MyClass()
klass.expensive_call # initial call is made
klass.expensive_call # return value is retrieved from an internal cache
del klass._expensive_call
"""
prop = '_{name}'.format(name=func.__name__)

def _get_property(self):
try:
value = getattr(self, prop)
except AttributeError:
value = func(self)
setattr(self, prop, value)
return value

update_wrapper(_get_property, func)

def _del_property(self):
delattr(self, prop)
def __init__(self, func):
self.__name__ = func.__name__
self.__doc__ = func.__doc__
self.key = '_{name}'.format(name=self.__name__)
self.func = func

return property(_get_property, None, _del_property)
def __get__(self, obj, type=None):
if self.key not in obj.__dict__:
obj.__dict__[self.key] = self.func(obj)
return obj.__dict__[self.key]
10 changes: 8 additions & 2 deletions watson/common/imports.py
Expand Up @@ -2,7 +2,10 @@
from importlib import import_module


def load_definition_from_string(qualified_module):
definition_lookup = {}


def load_definition_from_string(qualified_module, cache=True):
"""Load a definition based on a fully qualified string.
Returns:
Expand All @@ -15,13 +18,16 @@ def load_definition_from_string(qualified_module):
definition = load_definition_from_string('watson.http.messages.Request')
request = definition()
"""
if qualified_module in definition_lookup and cache:
return definition_lookup[qualified_module]
parts = qualified_module.split('.')
try:
module = import_module('.'.join(parts[:-1]))
obj = getattr(module, parts[-1:][0])
definition_lookup[qualified_module] = obj
return obj
except ImportError:
return None
raise


def get_qualified_name(obj):
Expand Down

0 comments on commit 13b6363

Please sign in to comment.