Skip to content

Commit

Permalink
Move base functor implemetation into lighty package from lighty.db. R…
Browse files Browse the repository at this point in the history
…ewrite monads implementation using functor.
  • Loading branch information
GrAndSE committed Apr 23, 2012
1 parent 8b00db2 commit 3cbd5f7
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 120 deletions.
49 changes: 2 additions & 47 deletions lighty/db/functor.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,14 @@
'''Make functor representation that helps to make queries and another lazy
evaluations
'''
import functools
import operator

from .. import functor

class BaseFunctor(object):
'''Base lazy object class
'''

def create_copy(self, operator, operand):
'''Create object's copy
'''
raise NotImplemented('"%s" does not overrides create_copy() method' %
self.__class__.__name__)


def create_operator(operator):
'''Create operator function
'''
@functools.wraps(operator)
def wrap(self, operand):
return self.create_copy(operator, operand)
return wrap


class FunctorBase(type):
'''Metaclass used to create a classes includes method to generate lazy
methods to access
'''

def __new__(mcls, name, bases, attrs):
'''Create new class includes lazy methods to override an operators
'''
super_new = super(FunctorBase, mcls).__new__
parents = [b for b in bases if isinstance(b, FunctorBase)]
if not parents:
# If this isn't a subclass of Model, don't do anything special.
return super_new(mcls, name, bases, attrs)
# Analyse an attributes
new_attrs = {'_lazy': set(attrs['_lazy']) if '_lazy' in attrs
else set()}
for parent in parents:
if hasattr(parent, '_lazy'):
new_attrs['_lazy'] |= set(parent._lazy)
for attr in new_attrs['_lazy']:
attrs[attr.__name__] = create_operator(attr)
new_attrs.update(attrs)
return super_new(mcls, name, bases, new_attrs)


class BaseField(object):
class BaseField(functor.BaseFunctor):
'''Base field class
'''
__metaclass__ = FunctorBase
# Declare lazy operations
_lazy = (operator.__lt__, operator.__gt__, operator.__le__,
operator.__ge__, operator.__eq__, operator.__ne__,
Expand Down
49 changes: 49 additions & 0 deletions lighty/functor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'''Class implements base functor operations
'''
import functools


def create_operator(operator):
'''Create operator function
'''
@functools.wraps(operator)
def wrap(self, operand):
return self.create_copy(operator, operand)
return wrap


class FunctorBase(type):
'''Metaclass used to create a classes includes method to generate lazy
methods to access
'''

def __new__(mcls, name, bases, attrs):
'''Create new class includes lazy methods to override an operators
'''
super_new = super(FunctorBase, mcls).__new__
parents = [b for b in bases if isinstance(b, FunctorBase)]
if not parents:
# If this isn't a subclass of Model, don't do anything special.
return super_new(mcls, name, bases, attrs)
# Analyse an attributes
new_attrs = {'_lazy': set(attrs['_lazy']) if '_lazy' in attrs
else set()}
for parent in parents:
if hasattr(parent, '_lazy'):
new_attrs['_lazy'] |= set(parent._lazy)
for attr in new_attrs['_lazy']:
attrs[attr.__name__] = create_operator(attr)
new_attrs.update(attrs)
return super_new(mcls, name, bases, new_attrs)


class BaseFunctor(object):
'''Base lazy object class
'''
__metaclass__ = FunctorBase

def create_copy(self, operator, operand):
'''Create object's copy
'''
raise NotImplemented('"%s" does not overrides create_copy() method' %
self.__class__.__name__)
104 changes: 32 additions & 72 deletions lighty/monads.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import operator
import sys

from . import functor


def handle_exception(func):
'''Handle an exception and return ErrorMonad for this exception
Expand Down Expand Up @@ -86,90 +88,52 @@ def wrapper(self, *args, **kwargs):
return ValueMonad(func(self, *nargs, **nkwargs))
return wrapper

BOOLEAN_OPERATORS = set((operator.__lt__, operator.__le__, operator.__eq__,
operator.__ge__, operator.__gt__, ))


def __getattr__(self, name):
return getattr(self.value, name)

@functools.total_ordering
class ValueMonad(object):

class ValueMonad(functor.BaseFunctor):
'''Base monad class. All the operations except comparisions and few others
returns monads.
'''
__slots__ = ('__init__', '__lt__', '__gt__', '__le__', '__ge__', '__eq__',
'__ne__', '__add__', '__sub__', '__div__', '__mul__',
'__mod__', '__pow__', '__getitem__', '__delitem__',
'__setitem__', '__iter__', '__contains__', '__len__',
'__and__', '__or__', '__xor__', '__lshift__', '__rshift__',
'__call__', '__str__', '__getattr__', 'value', )
__slots__ = ('__init__', '__getitem__', '__delitem__', '__setitem__',
'__iter__', '__len__', '__call__', '__str__', 'value', )
_lazy = (operator.__lt__, operator.__le__, operator.__eq__,
operator.__ge__, operator.__gt__, operator.__add__,
operator.__sub__, operator.__div__, operator.__mod__,
operator.__pow__, operator.__mul__, operator.__contains__,
__getattr__, operator.__rshift__, operator.__lshift__,
operator.__and__, operator.__or__, operator.__xor__)

def __init__(self, value):
'''Create new monad including value
'''
super(ValueMonad, self).__init__()
self.value = value.value if isinstance(value, ValueMonad) else value

@monad_boolean
def __lt__(self, other):
return self.value < other

@monad_boolean
def __le__(self, other):
return self.value <= other

@monad_boolean
def __eq__(self, other):
return self.value == other

@monad_operator
def __add__(self, other):
return self.value + other

@monad_operator
def __sub__(self, other):
return self.value - other

@monad_operator
def __div__(self, other):
return self.value / other

@monad_operator
def __mul__(self, other):
return self.value * other

@monad_operator
def __mod__(self, other):
return self.value // other

@monad_operator
def __pow__(self, other):
return self.value ** other

@monad_operator
def __and__(self, other):
return self.value & other

@monad_operator
def __or__(self, other):
return self.value | other

@monad_operator
def __xor__(self, other):
return self.value % other

@monad_operator
def __lshift__(self, other):
return self.value << other

@monad_operator
def __rshift__(self, other):
return self.value >> other
def create_copy(self, operator, operand):
is_boolean = operator in BOOLEAN_OPERATORS
if isinstance(operand, NoneMonad):
return False if is_boolean else operand
value = operator.value if isinstance(operand, ValueMonad) else operand
try:
result = operator(self.value, value)
except Exception as e:
return False if is_boolean else ErrorMonad(e)
else:
return result if is_boolean else ValueMonad(result)

def __len__(self):
try:
return len(self.value)
length = len(self)
except:
return 1

@monad_boolean
def __contains__(self, item):
return item in self.value
else:
return length

@monad_function
def __iter__(self):
Expand All @@ -196,10 +160,6 @@ def __setitem__(self, *args):
def __call__(self, *args, **kwargs):
return self.value(*args, **kwargs)

@monad_operator
def __getattr__(self, name):
return getattr(self.value, name)

def __str__(self):
return str(self.value)

Expand Down
3 changes: 2 additions & 1 deletion tests/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

from lighty.conf import Settings

TEST_APPS = ['lighty.db', 'lighty.templates', 'lighty.wsgi', 'tests']
TEST_APPS = ['benchmark', 'lighty.db', 'lighty.templates', 'lighty.wsgi',
'tests']


class ConfTestCase(unittest.TestCase):
Expand Down

0 comments on commit 3cbd5f7

Please sign in to comment.