1. Joao Bueno
  2. lelo

Commits

Joao Bueno  committed 41a1a9d

Completed lazy object implementation

  • Participants
  • Parent commits ff87460
  • Branches master

Comments (0)

Files changed (2)

File lelo/_lelo.py

View file
     queue.put(func(*args, **kwargs))
 
 
-class Wrapper(object):
-    def __init__(self, func):
-        self.func = func
-        self.__name__ = func.__name__
 
-    def __call__(self, *args, **kw):
-        self.queue = Queue(1)
+class CallWrapper(object):
+    def __init__(self, func, args, kw):
+        object.__setattr__(self, "_computed", False)
+        queue = Queue(1)
+        object.__setattr__(self, "_queue", queue)
         process = Process(target=_xecuter,
-            args=(self.queue, self.func,
+            args=(queue, func,
                   args, kw)
             )
         process.start()
 
     @property
     def _value(self):
-        if not hasattr(self, "_real_value"):
-            self._real_value = self.queue.get()
-        return self._real_value
+        if not object.__getattribute__(self, "_computed"):
+            queue = object.__getattribute__(self, "_queue")
+            object.__setattr__(self, "_real_value", queue.get())
+            object.__setattr__(self, "_computed", True)
+        return object.__getattribute__(self, "_real_value")
+
+
+def value_retriever(name):
+    def operator(self, *args, **kw):
+        try:
+            real_op = getattr(self._value, name)
+        except AttributeError:
+            return NotImplemented
+        return real_op(*args, **kw)
+    operator.__name__ = name
+    return operator
 
-        
+def attr_getter(self, attr):
+    if attr.startswith("__") or attr == "_value":
+        return object.__getattribute__(self, attr)
+    return getattr(self._value, attr)
+attr_getter.__name__ = "__getattr__"
 
-def paralell(func):
-    """
-    Make so that the function is called in a separate process, 
+def __subclasscheck__(cls, other):
+    return True
+
+
+class MetaParalell(type):
+    def __new__(metacls, name, bases, dct):
+        # FIXME: check the data_model
+        # and other Python documentation -
+        #  there are mssing dunder methods still
+        special_methods = """
+        __abs__ __add__ __and__ __cmp__ __coerce__
+        __delattr__ __div__ __divmod__ __doc__ __float__
+        __floordiv__ __format__  __getnewargs__
+        __hash__ __hex__ __index__ __int__ __invert__
+        __long__ __lshift__ __mod__ __mul__ __neg__ 
+        __nonzero__ __oct__ __or__ __pos__ __pow__ __radd__
+        __rand__ __rdiv__ __rdivmod__ __reduce__ __reduce_ex__
+        __repr__ __rfloordiv__ __rlshift__ __rmod__ __rmul__
+        __ror__ __rpow__ __rrshift__ __rshift__ __rsub__
+        __rtruediv__ __rxor__ __setattr__ __sizeof__
+        __str__ __sub__ __subclasshook__ __truediv_
+        __trunc__ __xor__ _contains__ __delitem__ __delslice__
+        __eq__ __ge__ __getitem__ __getslice__ __gt__ __iadd__
+        __imul__ __iter__ __le__ __len__ __lt__ __ne__ __reversed__
+        __setitem__ __setslice__  __enter__ __exit__
+
+        """
+        for func_name in special_methods.split():
+            dct[func_name] = value_retriever(func_name)
+        dct["__getattr__"] = attr_getter
+        return type.__new__(metacls, name, bases, dct)
+
+doc = """
+    Make so that the function is called in a separate process,
     using Python multiprocessing, and gets started imediatelly -
     in a non blocking way.
     The return value is a proxy object that will bridge to the real
     return value whenever it is used - it will block at time
     of use if it is not complete
-    """
-    pass
+"""
+
+LazyCallWrapper = MetaParalell("paralell", (CallWrapper,), {})
+
+
+class Wrapper(object):
+    def __init__(self, func):
+        self.func = func
+        self.__name__ = self.func.__name__
+
+    def __call__(self, *args, **kw):
+        return LazyCallWrapper(self.func, args, kw)
+
+
+
+paralell = Wrapper

File tests/test.py

View file
 
         def sum_(a, b):
             return a + b
-        
+
         proc  = Process(target=_xecuter, 
             args=(queue, sum_, (2, 3), {}))
         proc.start()
-        
-        
+
         self.assertEqual(queue.get(), 5)
 
     def test_proc_wrapper_works(self):
 
-        from lelo._lelo import Wrapper
+        from lelo._lelo import Wrapper, LazyCallWrapper
         def sum_(a,b):
             return a + b
 
         wrapped = Wrapper(sum_)
-        self.assertEqual(wrapped(2,3), None)
-        self.assertEqual(wrapped._value, 5)
-        
+        result = wrapped(2,3)
+        self.assertEqual(type(result), LazyCallWrapper)
+        self.assertEqual(result._value, 5)
         
+    def test_lazy_class_factory(self):
+        from lelo._lelo import MetaParalell
+        X = MetaParalell("X", (object,), {})
+        x = X()
+        object.__setattr__(x, "_value", 10)
+        self.assertEqual(x + 0, 10)
+        object.__setattr__(x, "_value", {"y": 10})
+        self.assertEqual(list(x.keys()), ["y"])
+
+    def test_paralell_function_creation(self):
+        from types import MethodType
+        @paralell
+        def soma(a, b):
+            return a + b
+        x = getattr(soma, "__call__")
+        self.assert_(x.__class__, MethodType)
+
+    def test_paralell_execution(self):
+        @paralell
+        def soma(a, b):
+            return a + b
+        result = soma(2,3)
+        #print result.__repr__
+        self.assertEqual(result, 5)
 
 if __name__ == "__main__":