You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

70 lines
2.5 KiB

  1. from nilmdb.utils.printf import *
  2. import sys
  3. import inspect
  4. import decorator
  5. def must_close(errorfile = sys.stderr, wrap_verify = False):
  6. """Class decorator that warns on 'errorfile' at deletion time if
  7. the class's close() member wasn't called.
  8. If 'wrap_verify' is True, every class method is wrapped with a
  9. verifier that will raise AssertionError if the .close() method has
  10. already been called."""
  11. def class_decorator(cls):
  12. def is_method_or_function(x):
  13. return inspect.ismethod(x) or inspect.isfunction(x)
  14. def wrap_class_method(wrapper):
  15. try:
  16. orig = getattr(cls, wrapper.__name__)
  17. except AttributeError:
  18. orig = lambda x: None
  19. if is_method_or_function(orig):
  20. setattr(cls, wrapper.__name__,
  21. decorator.decorator(wrapper, orig))
  22. @wrap_class_method
  23. def __init__(orig, self, *args, **kwargs):
  24. ret = orig(self, *args, **kwargs)
  25. self.__dict__["_must_close"] = True
  26. self.__dict__["_must_close_initialized"] = True
  27. return ret
  28. @wrap_class_method
  29. def __del__(orig, self, *args, **kwargs):
  30. try:
  31. if "_must_close" in self.__dict__:
  32. fprintf(errorfile, "error: %s.close() wasn't called!\n",
  33. self.__class__.__name__)
  34. return orig(self, *args, **kwargs)
  35. except:
  36. pass
  37. @wrap_class_method
  38. def close(orig, self, *args, **kwargs):
  39. if "_must_close" in self.__dict__:
  40. del self._must_close
  41. return orig(self, *args, **kwargs)
  42. # Optionally wrap all other functions
  43. def verifier(orig, self, *args, **kwargs):
  44. if ("_must_close" not in self.__dict__ and
  45. "_must_close_initialized" in self.__dict__):
  46. raise AssertionError("called " + str(orig) + " after close")
  47. return orig(self, *args, **kwargs)
  48. if wrap_verify:
  49. for (name, method) in inspect.getmembers(cls, is_method_or_function):
  50. # Skip some methods
  51. if name in [ "__del__", "__init__" ]:
  52. continue
  53. # Set up wrapper
  54. if inspect.ismethod(method):
  55. func = method.__func__
  56. else:
  57. func = method
  58. setattr(cls, name, decorator.decorator(verifier, func))
  59. return cls
  60. return class_decorator