Implemented Decorator Pattern.
This commit is contained in:
@@ -3,31 +3,71 @@ from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Decorator(object, metaclass=ABCMeta):
|
||||
|
||||
"""
|
||||
Base Decorator class that all decorator classes inherit from.
|
||||
"""
|
||||
def __get__(self, instance, owner):
|
||||
"""
|
||||
Override __get__ in order to get the instance of a bound of method call.
|
||||
"""
|
||||
return partial(self.__call__, instance)
|
||||
|
||||
@abstractmethod
|
||||
def __call__(self, *args, **kwargs):
|
||||
"""
|
||||
All decorators must implement a __call__ method.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class DecoratorSimple(Decorator, metaclass=ABCMeta):
|
||||
|
||||
"""
|
||||
A Base Decorator class for decorators with no arguments.
|
||||
"""
|
||||
def __init__(self, func):
|
||||
"""
|
||||
Initialize a new DecoratorSimple instance.
|
||||
|
||||
@param func: The function being decorated.
|
||||
"""
|
||||
self.func = func
|
||||
|
||||
|
||||
class DecoratorArgs(Decorator, metaclass=ABCMeta):
|
||||
|
||||
class DecoratorComplex(Decorator, metaclass=ABCMeta):
|
||||
"""
|
||||
A Base Decorator class for decorators with arguments.
|
||||
"""
|
||||
@abstractmethod
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Initialize a new DecoratorComplex instance.
|
||||
|
||||
@param args: Args for the decorator.
|
||||
@param kwargs: Keyword args for the decorator.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def __call__(self, func, *args, **kwargs):
|
||||
"""
|
||||
Concrete DecoratorComplex instances must override the __call__ method.
|
||||
|
||||
@param func: The function being decorated.
|
||||
@param args: Arguments for the decorated function.
|
||||
@param kwargs: Keyword arguments for the decorated function.
|
||||
@return:
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Wrap(DecoratorSimple):
|
||||
|
||||
class CallWrapper(DecoratorSimple):
|
||||
"""
|
||||
A Decorator for wrapping DecoratorComplex __call__ methods.
|
||||
"""
|
||||
def __call__(self, instance, func):
|
||||
"""
|
||||
Wrap a concrete DecoratorComplex __call__ method.
|
||||
"""
|
||||
def wrapped(*args, **kwargs):
|
||||
return self.func(instance, func, *args, **kwargs)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import time
|
||||
from unittest import TestCase
|
||||
from pypatterns.structural.decorator import DecoratorSimple, DecoratorArgs, Wrap
|
||||
from pypatterns.structural.decorator import DecoratorSimple, DecoratorComplex, CallWrapper
|
||||
|
||||
|
||||
class DecoratorSimpleTestCase(TestCase):
|
||||
@@ -51,20 +51,20 @@ class DecoratorSimpleTestCase(TestCase):
|
||||
self.assertAlmostEqual(2.0, slow_function.end, delta=1.0)
|
||||
|
||||
|
||||
class DecoratorArgsTestCase(TestCase):
|
||||
class DecoratorComplexTestCase(TestCase):
|
||||
"""
|
||||
Unit testing class for the DecoratorArgs class.
|
||||
Unit testing class for the DecoratorComplex class.
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Initialize testing data.
|
||||
"""
|
||||
class Alert(DecoratorArgs):
|
||||
class Alert(DecoratorComplex):
|
||||
|
||||
def __init__(self, alert_time):
|
||||
self.alert_time = alert_time
|
||||
|
||||
@Wrap
|
||||
@CallWrapper
|
||||
def __call__(self, func, *args, **kwargs):
|
||||
start = time.time()
|
||||
return_val = func(*args, **kwargs)
|
||||
@@ -81,12 +81,20 @@ class DecoratorArgsTestCase(TestCase):
|
||||
|
||||
@raise AssertionError: If the test fails.
|
||||
"""
|
||||
@self.alert(1)
|
||||
def slow_function():
|
||||
time.sleep(2)
|
||||
return 'foo'
|
||||
class SlowClass(object):
|
||||
|
||||
self.assertEquals(('foo', True), slow_function())
|
||||
@self.alert(1)
|
||||
def slow_function_true(self):
|
||||
time.sleep(2)
|
||||
return 'foo'
|
||||
|
||||
@self.alert(1)
|
||||
def slow_function_false(self):
|
||||
return 'bar'
|
||||
|
||||
slow_class = SlowClass()
|
||||
self.assertEquals(('foo', True), slow_class.slow_function_true())
|
||||
self.assertEquals(('bar', False), slow_class.slow_function_false())
|
||||
|
||||
def test_decorate_args(self):
|
||||
"""
|
||||
@@ -95,9 +103,53 @@ class DecoratorArgsTestCase(TestCase):
|
||||
@raise AssertionError: If the test fails.
|
||||
"""
|
||||
|
||||
@self.alert(1)
|
||||
def slow_function(n):
|
||||
time.sleep(n)
|
||||
return 'foo'
|
||||
class SlowClass(object):
|
||||
|
||||
self.assertEquals(('foo', True), slow_function(2))
|
||||
@self.alert(1)
|
||||
def slow_function_true(self, n):
|
||||
time.sleep(n)
|
||||
return 'foo'
|
||||
|
||||
@self.alert(1)
|
||||
def slow_function_false(self, n):
|
||||
return n
|
||||
|
||||
slow_class = SlowClass()
|
||||
self.assertEquals(('foo', True), slow_class.slow_function_true(2))
|
||||
self.assertEquals((10, False), slow_class.slow_function_false(10))
|
||||
|
||||
|
||||
class WrapTestCase(TestCase):
|
||||
"""
|
||||
Unit testing class for the CallWrapper decorator class.
|
||||
"""
|
||||
def test_wrap(self):
|
||||
"""
|
||||
Test the wrap decorator
|
||||
|
||||
@raise AssertionError: If the test fails.
|
||||
"""
|
||||
class SlowClass(DecoratorComplex):
|
||||
|
||||
def __init__(self, sleep_time):
|
||||
self.sleep_time = sleep_time
|
||||
self.end_time = None
|
||||
|
||||
@CallWrapper
|
||||
def __call__(self, func, *args, **kwargs):
|
||||
start_time = time.time()
|
||||
return_val = func(*args, **kwargs)
|
||||
time.sleep(self.sleep_time)
|
||||
end_time = time.time() - start_time
|
||||
self.end_time = end_time
|
||||
return return_val, self.sleep_time, self.end_time
|
||||
|
||||
@SlowClass(1)
|
||||
def hello_world(n):
|
||||
return ['hello world' for _ in range(n)]
|
||||
|
||||
return_val, sleeptime, end_time = hello_world(5)
|
||||
|
||||
self.assertEquals(1, sleeptime)
|
||||
self.assertAlmostEquals(1, end_time, delta=1)
|
||||
self.assertListEqual(['hello world' for _ in range(5)], return_val)
|
||||
|
||||
Reference in New Issue
Block a user