diff -r fe532dccf8f6 Lib/test/test_dbm_gnu.py --- a/Lib/test/test_dbm_gnu.py Mon Apr 14 10:30:43 2014 -0400 +++ b/Lib/test/test_dbm_gnu.py Wed Apr 16 12:38:27 2014 -0500 @@ -93,5 +93,31 @@ self.assertEqual(str(cm.exception), "GDBM object has already been closed") + def test_bool_empty(self): + """Ensure bool(db with no entry) is False.""" + + self.g = gdbm.open(filename, 'c') + # Empty, should be False + self.assertFalse(bool(self.g)) + + def test_bool_not_empty(self): + """Ensure bool(db with an entry) is True.""" + + self.g = gdbm.open(filename, 'c') + self.g['a'] = 'b' + # Has an entry, should be True + self.assertTrue(bool(self.g)) + + def test_bool_on_closed_db_raises(self): + """Ensure bool(db) on closed db raises an error.""" + + self.g = gdbm.open(filename, 'c') + self.g['a'] = 'b' + self.g.close() + + # After closing, bool(db) should raise + self.assertRaises(gdbm.error, bool, self.g) + + if __name__ == '__main__': unittest.main() diff -r fe532dccf8f6 Lib/test/test_dbm_ndbm.py --- a/Lib/test/test_dbm_ndbm.py Mon Apr 14 10:30:43 2014 -0400 +++ b/Lib/test/test_dbm_ndbm.py Wed Apr 16 12:38:27 2014 -0500 @@ -49,6 +49,31 @@ self.assertEqual(str(cm.exception), "DBM object has already been closed") + def test_bool_empty(self): + """Ensure bool(db with No entry) is False.""" + + with dbm.ndbm.open(self.filename, 'c') as db: + # Empty, should be False + self.assertFalse(bool(db)) + + def test_bool_not_empty(self): + """Ensure bool(db with an entry) is True.""" + + with dbm.ndbm.open(self.filename, 'c') as db: + db['a'] = 'b' + # Has an entry, should be True + self.assertTrue(bool(db)) + + def test_bool_on_closed_db_raises(self): + """Ensure bool(db) on closed db raises an error.""" + + with dbm.ndbm.open(self.filename, 'c') as db: + db['a'] = 'b' + + # After closing, bool(db) should raise + self.assertRaises(dbm.ndbm.error, bool, db) + + if __name__ == '__main__': unittest.main() diff -r fe532dccf8f6 Modules/_dbmmodule.c --- a/Modules/_dbmmodule.c Mon Apr 14 10:30:43 2014 -0400 +++ b/Modules/_dbmmodule.c Wed Apr 16 12:38:27 2014 -0500 @@ -220,6 +220,27 @@ } static int +dbm_bool(dbmobject *dp) +{ + datum key; + + if (dp->di_dbm == NULL) { + PyErr_SetString(DbmError, "DBM object has already been closed"); + return -1; + } + + if (dp->di_size > 0){ + /* Known non-zero size. */ + return 1; + } + + /* Unknown size. Ensure DBM object has an entry. */ + key = dbm_firstkey(dp->di_dbm); + return 0 != key.dptr; +} + + +static int dbm_contains(PyObject *self, PyObject *arg) { dbmobject *dp = (dbmobject *)self; @@ -396,6 +417,44 @@ {NULL, NULL} /* sentinel */ }; + +static PyNumberMethods dbm_as_number = { + 0, /*nb_add*/ + 0, /*nb_subtract*/ + 0, /*nb_multiply*/ + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + 0, /*nb_negative*/ + 0, /*nb_positive*/ + 0, /*nb_absolute*/ + (inquiry)dbm_bool, /*nb_bool*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + 0, /*nb_int*/ + 0, /*nb_reserved*/ + 0, /*nb_float*/ + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + 0, /* nb_floor_divide */ + 0, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ +}; + + static PyTypeObject Dbmtype = { PyVarObject_HEAD_INIT(NULL, 0) "_dbm.dbm", @@ -407,7 +466,7 @@ 0, /*tp_setattr*/ 0, /*tp_reserved*/ 0, /*tp_repr*/ - 0, /*tp_as_number*/ + &dbm_as_number, /*tp_as_number*/ &dbm_as_sequence, /*tp_as_sequence*/ &dbm_as_mapping, /*tp_as_mapping*/ 0, /*tp_hash*/ diff -r fe532dccf8f6 Modules/_gdbmmodule.c --- a/Modules/_gdbmmodule.c Mon Apr 14 10:30:43 2014 -0400 +++ b/Modules/_gdbmmodule.c Wed Apr 16 12:38:27 2014 -0500 @@ -286,6 +286,26 @@ } static int +dbm_bool(dbmobject *dp) +{ + datum key; + + if (dp->di_dbm == NULL) { + PyErr_SetString(DbmError, "GDBM object has already been closed"); + return -1; + } + + if (dp->di_size > 0){ + /* Known non-zero size. */ + return 1; + } + + /* Unknown size. Ensure DBM object has an entry. */ + key = gdbm_firstkey(dp->di_dbm); + return 0 != key.dptr; +} + +static int dbm_contains(PyObject *self, PyObject *arg) { dbmobject *dp = (dbmobject *)self; @@ -453,6 +473,42 @@ {NULL, NULL} /* sentinel */ }; +static PyNumberMethods dbm_as_number = { + 0, /*nb_add*/ + 0, /*nb_subtract*/ + 0, /*nb_multiply*/ + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + 0, /*nb_negative*/ + 0, /*nb_positive*/ + 0, /*nb_absolute*/ + (inquiry)dbm_bool, /*nb_bool*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + 0, /*nb_int*/ + 0, /*nb_reserved*/ + 0, /*nb_float*/ + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + 0, /* nb_floor_divide */ + 0, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ +}; + static PyTypeObject Dbmtype = { PyVarObject_HEAD_INIT(0, 0) "_gdbm.gdbm", @@ -464,7 +520,7 @@ 0, /*tp_setattr*/ 0, /*tp_reserved*/ 0, /*tp_repr*/ - 0, /*tp_as_number*/ + &dbm_as_number, /*tp_as_number*/ &dbm_as_sequence, /*tp_as_sequence*/ &dbm_as_mapping, /*tp_as_mapping*/ 0, /*tp_hash*/