ACL uses enums, some more tests, other stuff.
[python_utils.git] / decorator_utils.py
index 03e7c880433fad5d359a2bb3acc29a4266204e65..2817239c88c2396b0e5dcc56e7c535b8afdd99d9 100644 (file)
@@ -5,6 +5,7 @@
 import datetime
 import enum
 import functools
+import inspect
 import logging
 import math
 import multiprocessing
@@ -17,8 +18,10 @@ import traceback
 from typing import Callable, Optional
 import warnings
 
+# This module is commonly used by others in here and should avoid
+# taking any unnecessary dependencies back on them.
 import exceptions
-import thread_utils
+
 
 logger = logging.getLogger(__name__)
 
@@ -426,6 +429,7 @@ def timeout(
     parameter.  The function is wrapped and returned to the caller.
     """
     if use_signals is None:
+        import thread_utils
         use_signals = thread_utils.is_current_thread_main_thread()
 
     def decorate(function):
@@ -517,3 +521,19 @@ def call_with_sample_rate(sample_rate: float) -> Callable:
                 )
         return _call_with_sample_rate
     return decorator
+
+
+def decorate_matching_methods_with(decorator, acl=None):
+    """Apply decorator to all methods in a class whose names begin with
+    prefix.  If prefix is None (default), decorate all methods in the
+    class.
+    """
+    def decorate_the_class(cls):
+        for name, m in inspect.getmembers(cls, inspect.isfunction):
+            if acl is None:
+                setattr(cls, name, decorator(m))
+            else:
+                if acl(name):
+                    setattr(cls, name, decorator(m))
+        return cls
+    return decorate_the_class