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.
 
 
 

62 lines
2.3 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 wrap_class_method(wrapper):
  13. try:
  14. orig = getattr(cls, wrapper.__name__).im_func
  15. except:
  16. orig = lambda x: None
  17. setattr(cls, wrapper.__name__, decorator.decorator(wrapper, orig))
  18. @wrap_class_method
  19. def __init__(orig, self, *args, **kwargs):
  20. ret = orig(self, *args, **kwargs)
  21. self.__dict__["_must_close"] = True
  22. self.__dict__["_must_close_initialized"] = True
  23. return ret
  24. @wrap_class_method
  25. def __del__(orig, self, *args, **kwargs):
  26. if "_must_close" in self.__dict__:
  27. fprintf(errorfile, "error: %s.close() wasn't called!\n",
  28. self.__class__.__name__)
  29. return orig(self, *args, **kwargs)
  30. @wrap_class_method
  31. def close(orig, self, *args, **kwargs):
  32. if "_must_close" in self.__dict__:
  33. del self._must_close
  34. return orig(self, *args, **kwargs)
  35. # Optionally wrap all other functions
  36. def verifier(orig, self, *args, **kwargs):
  37. if ("_must_close" not in self.__dict__ and
  38. "_must_close_initialized" in self.__dict__):
  39. raise AssertionError("called " + str(orig) + " after close")
  40. return orig(self, *args, **kwargs)
  41. if wrap_verify:
  42. for (name, method) in inspect.getmembers(cls, inspect.ismethod):
  43. # Skip class methods
  44. if method.__self__ is not None:
  45. continue
  46. # Skip some methods
  47. if name in [ "__del__", "__init__" ]:
  48. continue
  49. # Set up wrapper
  50. setattr(cls, name, decorator.decorator(verifier,
  51. method.im_func))
  52. return cls
  53. return class_decorator