From b9407de5dce682baeceb9b56204bb441ef18a532 Mon Sep 17 00:00:00 2001
From: Julien Muchembled <jm@nexedi.com>
Date: Mon, 12 Jul 2010 16:07:13 +0000
Subject: [PATCH] Fix __name__ and __doc__ of some decorated functions

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@37064 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ERP5Type/Cache.py              |  5 +++--
 product/ERP5Type/UnrestrictedMethod.py |  7 +++----
 product/ERP5Type/Utils.py              | 22 ++++++++++++++++++++++
 3 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/product/ERP5Type/Cache.py b/product/ERP5Type/Cache.py
index b1471012af..2b9f571712 100644
--- a/product/ERP5Type/Cache.py
+++ b/product/ERP5Type/Cache.py
@@ -33,6 +33,7 @@ from AccessControl.SecurityInfo import allow_class
 from CachePlugins.BaseCache import CachedMethodError
 from zLOG import LOG, WARNING
 from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
+from Products.ERP5Type.Utils import simple_decorator
 from warnings import warn
 
 DEFAULT_CACHE_SCOPE = 'GLOBAL'
@@ -281,6 +282,7 @@ def generateCacheIdWithoutFirstArg(method_id, *args, **kwd):
 
 def caching_instance_method(*args, **kw):
   kw.setdefault('cache_id_generator', generateCacheIdWithoutFirstArg)
+  @simple_decorator
   def wrapped(method):
     # The speed of returned function must be fast
     # so we instanciate CachingMethod now.
@@ -293,6 +295,7 @@ def caching_instance_method(*args, **kw):
   return wrapped
 
 def transactional_cached(key_method=lambda *args: args):
+  @simple_decorator
   def decorator(function):
     key = repr(function)
     def wrapper(*args, **kw):
@@ -303,7 +306,5 @@ def transactional_cached(key_method=lambda *args: args):
       except KeyError:
         cache[subkey] = result = function(*args, **kw)
         return result
-    wrapper.__doc__ = function.__doc__
-    wrapper.__name__ = function.__name__
     return wrapper
   return decorator
diff --git a/product/ERP5Type/UnrestrictedMethod.py b/product/ERP5Type/UnrestrictedMethod.py
index 85ff8a88f5..733458c596 100644
--- a/product/ERP5Type/UnrestrictedMethod.py
+++ b/product/ERP5Type/UnrestrictedMethod.py
@@ -34,6 +34,7 @@ try:
   from Zope2 import app
 except ImportError:
   from Zope import app
+from Products.ERP5Type.Utils import simple_decorator
 
 class PrivilegedUser(UnrestrictedUser):
   """User that bypasses all security checks, but retains an original
@@ -48,6 +49,7 @@ class PrivilegedUser(UnrestrictedUser):
     """Get the ID of the user. This is disabled in UnrestrictedUser."""
     return self.getUserName()
 
+@simple_decorator
 def UnrestrictedMethod(function):
   """Decorator to bypass all security checks.
 
@@ -66,10 +68,7 @@ def UnrestrictedMethod(function):
 
   This method is dangerous. Enough said. Be careful.
   """
-  wrapper = lambda *args, **kw: unrestricted_apply(function, args, kw)
-  wrapper.__doc__ = function.__doc__
-  wrapper.__name__ = function.__name__
-  return wrapper
+  return lambda *args, **kw: unrestricted_apply(function, args, kw)
 
 def unrestricted_apply(function, args=(), kw={}):
     """Function to bypass all security checks
diff --git a/product/ERP5Type/Utils.py b/product/ERP5Type/Utils.py
index db55b57acf..91ada44ab1 100644
--- a/product/ERP5Type/Utils.py
+++ b/product/ERP5Type/Utils.py
@@ -65,6 +65,27 @@ from Products.PageTemplates.Expressions import getEngine
 from Products.PageTemplates.Expressions import SecureModuleImporter
 from Products.ZCatalog.Lazy import LazyMap
 
+def simple_decorator(decorator):
+  """Decorator to turn simple function into well-behaved decorator
+
+  See also http://wiki.python.org/moin/PythonDecoratorLibrary
+
+  XXX We should use http://pypi.python.org/pypi/decorator/ instead,
+      to make decorators ZPublisher-friendly.
+  """
+  def new_decorator(f):
+    g = decorator(f)
+    g.__name__ = f.__name__
+    g.__doc__ = f.__doc__
+    g.__dict__.update(f.__dict__)
+    return g
+  # Now a few lines needed to make simple_decorator itself
+  # be a well-behaved decorator.
+  new_decorator.__name__ = decorator.__name__
+  new_decorator.__doc__ = decorator.__doc__
+  new_decorator.__dict__.update(decorator.__dict__)
+  return new_decorator
+
 from Products.ERP5Type import Permissions
 
 from Products.ERP5Type.Accessor.Constant import PropertyGetter as \
@@ -194,6 +215,7 @@ def _showwarning(message, category, filename, lineno, file=None, line=None):
     file.write(warnings.formatwarning(message, category, filename, lineno))
 warnings.showwarning = _showwarning
 
+@simple_decorator
 def deprecated(wrapped):
   message = "Use of '%s' function (%s, line %s) is deprecated." % (
     wrapped.__name__, wrapped.__module__, wrapped.func_code.co_firstlineno)
-- 
2.30.9