Add must_close() decorator, use it in nilmdb
Warns at runtime if a class's close() method wasn't called before the object was destroyed.
This commit is contained in:
parent
19c846c71c
commit
b0d76312d1
|
@ -94,6 +94,7 @@ class BisectableTable(object):
|
|||
def __getitem__(self, index):
|
||||
return self.table[index][0]
|
||||
|
||||
@nilmdb.utils.must_close()
|
||||
class NilmDB(object):
|
||||
verbose = 0
|
||||
|
||||
|
@ -135,14 +136,6 @@ class NilmDB(object):
|
|||
else:
|
||||
self.max_results = 16384
|
||||
|
||||
self.opened = True
|
||||
|
||||
def __del__(self):
|
||||
if "opened" in self.__dict__: # pragma: no cover
|
||||
fprintf(sys.stderr,
|
||||
"error: NilmDB.close() wasn't called, path %s",
|
||||
self.basepath)
|
||||
|
||||
def get_basepath(self):
|
||||
return self.basepath
|
||||
|
||||
|
@ -151,7 +144,6 @@ class NilmDB(object):
|
|||
self.con.commit()
|
||||
self.con.close()
|
||||
self.h5file.close()
|
||||
del self.opened
|
||||
|
||||
def _sql_schema_update(self):
|
||||
cur = self.con.cursor()
|
||||
|
|
|
@ -5,3 +5,4 @@ from .iteratorizer import Iteratorizer
|
|||
from .serializer import Serializer
|
||||
from .lrucache import lru_cache
|
||||
from .diskusage import du
|
||||
from .mustclose import must_close
|
||||
|
|
42
nilmdb/utils/mustclose.py
Normal file
42
nilmdb/utils/mustclose.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Class decorator that warns on stderr at deletion time if the class's
|
||||
# close() member wasn't called.
|
||||
|
||||
from nilmdb.utils.printf import *
|
||||
import sys
|
||||
|
||||
def must_close(errorfile = sys.stderr):
|
||||
def decorator(cls):
|
||||
def dummy(*args, **kwargs):
|
||||
pass
|
||||
if "__init__" not in cls.__dict__:
|
||||
cls.__init__ = dummy
|
||||
if "__del__" not in cls.__dict__:
|
||||
cls.__del__ = dummy
|
||||
if "close" not in cls.__dict__:
|
||||
cls.close = dummy
|
||||
|
||||
orig_init = cls.__init__
|
||||
orig_del = cls.__del__
|
||||
orig_close = cls.close
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
ret = orig_init(self, *args, **kwargs)
|
||||
self.__dict__["_must_close"] = True
|
||||
return ret
|
||||
|
||||
def __del__(self):
|
||||
if "_must_close" in self.__dict__:
|
||||
fprintf(errorfile, "error: %s.close() wasn't called!\n",
|
||||
self.__class__.__name__)
|
||||
return orig_del(self)
|
||||
|
||||
def close(self, *args, **kwargs):
|
||||
del self._must_close
|
||||
return orig_close(self)
|
||||
|
||||
cls.__init__ = __init__
|
||||
cls.__del__ = __del__
|
||||
cls.close = close
|
||||
|
||||
return cls
|
||||
return decorator
|
|
@ -10,6 +10,7 @@ cover-erase=
|
|||
##cover-branches= # need nose 1.1.3 for this
|
||||
stop=
|
||||
verbosity=2
|
||||
#tests=tests/test_mustclose.py
|
||||
#tests=tests/test_lrucache.py
|
||||
#tests=tests/test_cmdline.py
|
||||
#tests=tests/test_layout.py
|
||||
|
|
48
tests/test_mustclose.py
Normal file
48
tests/test_mustclose.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
import nilmdb
|
||||
from nilmdb.utils.printf import *
|
||||
|
||||
import nose
|
||||
from nose.tools import *
|
||||
from nose.tools import assert_raises
|
||||
|
||||
from test_helpers import *
|
||||
|
||||
import sys
|
||||
import cStringIO
|
||||
|
||||
err = cStringIO.StringIO()
|
||||
|
||||
@nilmdb.utils.must_close(errorfile = err)
|
||||
class Foo:
|
||||
def __init__(self):
|
||||
fprintf(err, "Init\n")
|
||||
|
||||
def __del__(self):
|
||||
fprintf(err, "Deleting\n")
|
||||
|
||||
def close(self):
|
||||
fprintf(err, "Closing\n")
|
||||
|
||||
class TestMustClose(object):
|
||||
def test(self):
|
||||
|
||||
# Note: this test might fail if the Python interpreter doesn't
|
||||
# garbage collect the object (and call its __del__ function)
|
||||
# right after a "del x".
|
||||
|
||||
x = Foo()
|
||||
del x
|
||||
eq_(err.getvalue(),
|
||||
"Init\n"
|
||||
"error: Foo.close() wasn't called!\n"
|
||||
"Deleting\n")
|
||||
|
||||
err.truncate(0)
|
||||
|
||||
y = Foo()
|
||||
y.close()
|
||||
del y
|
||||
eq_(err.getvalue(),
|
||||
"Init\n"
|
||||
"Closing\n"
|
||||
"Deleting\n")
|
Loading…
Reference in New Issue
Block a user