dumbdbm module broken in Python2.3?
Changjune Kim
juneaftn at REMOVETHIShanmail.net
Thu Mar 13 10:35:01 EST 2003
"Jane Austine" <janeaustine50 at hotmail.com> wrote in message
news:ba1e306f.0303111337.72a696c7 at posting.google.com...
> I used shelve.py and it falls back on dumbdbm when no
> possible alternatives are found on the system.
>
> I found this error, which is recurrent and deterministic:
>
> Exception exceptions.AttributeError: "'NoneType' object has no
> attribute 'error'" in <bound method _Database.__del__ of
> <dumbdbm._Database instance at 0x820c71c>> ignored
>
> The problem seems to reside in the __del__ of dumbdbm._Database:
>
> class _Database:
> ...
> def __del__(self):
> if self._index is not None:
> self._commit()
> ...
> def _commit(self):
> try: _os.unlink(self._bakfile)
> except _os.error: pass
> try: _os.rename(self._dirfile, self._bakfile)
> except _os.error: pass
> f = _open(self._dirfile, 'w', self._mode)
> for key, (pos, siz) in self._index.items():
> f.write("%s, (%s, %s)\n" % (`key`, `pos`, `siz`))
> f.close()
>
> My investigation showed that the error was from _commit. When
> it was called, _os or _open was both None. And the exception
> catch didn't work quite safely cause its in the "except" clause.
>
> The reason I suspect is when the time that _Database.__del__ was
> called the os module(which is imported as _os) is already removed out.
>
> I changed the code as:
>
> def _commit(self):
> global _os
> if _os is None:
> import os as _os
> import __builtin__
> _open = __builtin__.open
> try: _os.unlink(self._bakfile)
> except _os.error: pass
> try: _os.rename(self._dirfile, self._bakfile)
> except _os.error: pass
> ......
>
> Now it works without any problems, AFAIK.
>
> Am I right on the track?
>
> Jane
You should be using shelve with auto-garbage-collection. A safer and proper
way is close shelve explicitly.
This is a minimal case code for the same kind of error:
<code>
import types
import types as _types
class A:
def __del__(self):
try:
_types.IntType
except:
print "error from A"
class B:
def __del__(self):
try:
types.IntType
except:
print "error from B"
foobar=(A(),B())
</code>
This results in "error from A" only. Why? See what happens with -v option:
...
# clear __builtin__._
# clear sys.path
# clear sys.argv
# clear sys.ps1
# clear sys.ps2
# clear sys.exitfunc
# clear sys.exc_type
# clear sys.exc_value
# clear sys.exc_traceback
# clear sys.last_type
# clear sys.last_value
# clear sys.last_traceback
# restore sys.stdin
# restore sys.stdout
# restore sys.stderr
# cleanup __main__
error from A
# cleanup[1] __future__
# cleanup[1] site
# cleanup[1] types
# cleanup[1] sitecustomize
# cleanup[1] nt
# cleanup[1] signal
...
# cleanup[2] os
# cleanup sys
# cleanup __builtin__
# cleanup ints: 2 unfreed ints in 1 out of 1 block
# cleanup floats
__main__ is cleared and _types is removed as __main__ is cleaned up.
However, types.IntType still exists since "types" is cleaned up much later.
One way around it is:
def __del__(self,_types=_types):
and you get no errors at all.
Still the best way is explicitly del-ing what you don't need anymore.
Explicit is better than implicit in Python world.
More information about the Python-list
mailing list