nilmdb/nilmdb/utils/mustclose.py
Jim Paris 3d24092cd2 Replace bare 'except:' with 'except: Exception'
Otherwise we might inadvertently catch SystemExit or KeyboardExit or
something we don't want to catch.
2013-03-24 21:28:01 -04:00

62 lines
2.3 KiB
Python

from nilmdb.utils.printf import *
import sys
import inspect
import decorator
def must_close(errorfile = sys.stderr, wrap_verify = False):
"""Class decorator that warns on 'errorfile' at deletion time if
the class's close() member wasn't called.
If 'wrap_verify' is True, every class method is wrapped with a
verifier that will raise AssertionError if the .close() method has
already been called."""
def class_decorator(cls):
def wrap_class_method(wrapper):
try:
orig = getattr(cls, wrapper.__name__).im_func
except Exception:
orig = lambda x: None
setattr(cls, wrapper.__name__, decorator.decorator(wrapper, orig))
@wrap_class_method
def __init__(orig, self, *args, **kwargs):
ret = orig(self, *args, **kwargs)
self.__dict__["_must_close"] = True
self.__dict__["_must_close_initialized"] = True
return ret
@wrap_class_method
def __del__(orig, self, *args, **kwargs):
if "_must_close" in self.__dict__:
fprintf(errorfile, "error: %s.close() wasn't called!\n",
self.__class__.__name__)
return orig(self, *args, **kwargs)
@wrap_class_method
def close(orig, self, *args, **kwargs):
if "_must_close" in self.__dict__:
del self._must_close
return orig(self, *args, **kwargs)
# Optionally wrap all other functions
def verifier(orig, self, *args, **kwargs):
if ("_must_close" not in self.__dict__ and
"_must_close_initialized" in self.__dict__):
raise AssertionError("called " + str(orig) + " after close")
return orig(self, *args, **kwargs)
if wrap_verify:
for (name, method) in inspect.getmembers(cls, inspect.ismethod):
# Skip class methods
if method.__self__ is not None:
continue
# Skip some methods
if name in [ "__del__", "__init__" ]:
continue
# Set up wrapper
setattr(cls, name, decorator.decorator(verifier,
method.im_func))
return cls
return class_decorator