[FIX] Report: get the wkhtmltopdf version in a cleaner way with a simple regex
[odoo/odoo.git] / openerp / tools / func.py
index d1797e3..89cdf9f 100644 (file)
@@ -3,7 +3,7 @@
 #
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-#    Copyright (C) 2010 OpenERP s.a. (<http://openerp.com>).
+#    Copyright (C) 2010, 2014 OpenERP s.a. (<http://openerp.com>).
 #
 #    This program is free software: you can redistribute it and/or modify
 #    it under the terms of the GNU Affero General Public License as
 #
 ##############################################################################
 
-__all__ = ['synchronized']
+__all__ = ['synchronized', 'lazy_property']
 
 from functools import wraps
 from inspect import getsourcefile
 
+
+class lazy_property(object):
+    """ Decorator for a lazy property of an object, i.e., an object attribute
+        that is determined by the result of a method call evaluated once. To
+        reevaluate the property, simply delete the attribute on the object, and
+        get it again.
+    """
+    def __init__(self, fget):
+        self.fget = fget
+        self.name = fget.__name__
+
+    def __get__(self, obj, cls):
+        if obj is None:
+            return self
+        value = self.fget(obj)
+        setattr(obj, self.name, value)
+        return value
+
+    @staticmethod
+    def reset_all(obj):
+        """ Reset all lazy properties on the instance `obj`. """
+        cls = type(obj)
+        obj_dict = obj.__dict__
+        for name in obj_dict.keys():
+            if isinstance(getattr(cls, name, None), lazy_property):
+                obj_dict.pop(name)
+
+
 def synchronized(lock_attr='_lock'):
     def decorator(func):
         @wraps(func)
@@ -45,7 +73,7 @@ def frame_codeinfo(fframe, back=0):
     
     try:
         if not fframe:
-            return ("<unknown>", '')
+            return "<unknown>", ''
         for i in range(back):
             fframe = fframe.f_back
         try:
@@ -53,8 +81,23 @@ def frame_codeinfo(fframe, back=0):
         except TypeError:
             fname = '<builtin>'
         lineno = fframe.f_lineno or ''
-        return (fname, lineno)
+        return fname, lineno
     except Exception:
-        return ("<unknown>", '')
+        return "<unknown>", ''
+
+def compose(a, b):
+    """ Composes the callables ``a`` and ``b``. ``compose(a, b)(*args)`` is
+    equivalent to ``a(b(*args))``.
+
+    Can be used as a decorator by partially applying ``a``::
+
+         @partial(compose, a)
+         def b():
+            ...
+    """
+    @wraps(b)
+    def wrapper(*args, **kwargs):
+        return a(b(*args, **kwargs))
+    return wrapper
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: