[Python-bugs-list] [ python-Bugs-715063 ] bsddb.first()/next() raise undocumented exception

SourceForge.net noreply@sourceforge.net
Mon, 07 Jul 2003 12:39:28 -0700


Bugs item #715063, was opened at 2003-04-03 23:03
Message generated for change (Comment added) made by bwarsaw
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=715063&group_id=5470

Category: Python Library
Group: Python 2.3
Status: Closed
Resolution: Works For Me
Priority: 5
Submitted By: Christian Stork (cst)
Assigned to: Gregory P. Smith (greg)
Summary: bsddb.first()/next() raise undocumented exception

Initial Comment:
bsddb object's first() & next() methods raise an undocumented 
exception.  Wouldn't returning None make much more sense?  
And shouldn't this be documented? 

Python 2.3a2+ (#2, Mar 21 2003, 22:13:05) 
[GCC 3.2.3 20030316 (Debian prerelease)] on linux2
>>> import bsddb
>>> h.bsddb.hashopen("testdb")
>>> h.first()
------------------------------------------------------------
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "/usr/lib/python2.3/bsddb/__init__.py", line 134, in first
    rv = self.dbc.first()
DBNotFoundError: (-30991, 'DB_NOTFOUND: No matching key/
data pair found')

Note: The same exception appeared for the equivalent dbhash 
methods.  But I assume this should be fixed if this bug is fixed.

----------------------------------------------------------------------

>Comment By: Barry A. Warsaw (bwarsaw)
Date: 2003-07-07 15:39

Message:
Logged In: YES 
user_id=12800

Greg, correct me if I'm wrong but cursor.next() already has
the return value issue you point out, i.e. it can return
None or a tuple.  My pattern has been to do stuff like this:

rec = c.first()
while rec:
   key, val = rec
   rec = c.next()

so it doesn't bother me too much if the cursor.set() method
works the same way <wink>.  I think the documentation of
set_get_returns_none is correct and cursor.set() should be
changed to follow those rules.  I'm not too concerned with
backward compatibility either because this is the common
.set() idiom I use:

try:
  rec = c.set('somekey')
except db.DBNotFoundError:
  rec = None
while rec:
  ...

This code would not break by changing .set(), but I would be
able to remove the try/except.


----------------------------------------------------------------------

Comment By: Gregory P. Smith (greg)
Date: 2003-07-07 14:56

Message:
Logged In: YES 
user_id=413

Looking in the code, no, none of the DBCursor set* methods
follow set_get_returns_none() to not raise an exception. 
The documentation for set_get_returns_none implies that they
should as they're all cursor "get" methods.

All of the set methods normally return tuples of (key, data)
rather than a single value.  If we modify them to return
None rather than raise a DBNotFoundError it makes for an
annoying interface because it wouldn't always return a tuple.

I'm inclined to leave the set methods as they are and fix
the set_get_returns_none() documentation unless someone can
come up with good examples why it should be different.

----------------------------------------------------------------------

Comment By: Barry A. Warsaw (bwarsaw)
Date: 2003-07-07 13:49

Message:
Logged In: YES 
user_id=12800

Greg, what about cursor.set() -- I don't think this follows
set_get_returns_none() does it?  I wonder if it should.


----------------------------------------------------------------------

Comment By: Gregory P. Smith (greg)
Date: 2003-07-06 20:01

Message:
Logged In: YES 
user_id=413

DBNotFoundError derives from KeyError.  The old bsddb library also raised KeyError on first/last/next calls when there was no more data rather than returning None so that
interface cannot be changed.  (I agree, returning None would make more sense; but I
can't break the old interface).

The new pybsddb interface's DB and DBEnv set_get_returns_none method does allow you to control this behaviour.

If you are using the old style bsddb interface then you do not have access to the DBEnv before the DB object is created (DB objects inherit the flag setting from the DBEnv when they are created) so you'll need to call set_get_returns_none on the DB object itself:

import bsddb   # python 2.3 bsddb (aka bsddb3 or pybsddb)

hdb = bsddb.hashopen("myhash", 'c')
hdb.db.set_get_returns_none(1)   # will only work on python 2.3 / pybsddb
spam = hdb.first()
while spam:
  spam = hdb.next()

# notice there were no errors.


I've looked at the code for first/last/prev/get and they all use the same internal DBCursor_get wrapper that obeys the set_get_returns_none flag so that you can
write simple "foo = hdb.first();  while not foo:  foo = hdb.next()"  code.


----------------------------------------------------------------------

Comment By: Gregory P. Smith (greg)
Date: 2003-07-06 19:24

Message:
Logged In: YES 
user_id=413

i'm taking a look.

----------------------------------------------------------------------

Comment By: Barry A. Warsaw (bwarsaw)
Date: 2003-04-07 18:46

Message:
Logged In: YES 
user_id=12800

pybsddb has this option to return None from cursor.get()
methods instead of raising DBNotFoundError.  The DBEnv
method set_get_returns_none() can be used to change the
behavior, although the default is to return None.  I agree
that this is very handy!

I suppose .first() and .last() should perhaps honor this
config as well?


----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=715063&group_id=5470