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 Tue Apr 15 10:11:28 2014 -0500 @@ -93,5 +93,30 @@ 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.d = gdbm.open(filename, 'c') + # Empty, should be False + self.assertFalse(bool(self.d)) + + def test_bool_not_empty(self): + """Ensure bool(db with an entry) is True.""" + + self.d = gdbm.open(filename, 'c') + self.d['a'] = 'b' + # Has an entry, should be True + self.assertTrue(bool(self.d)) + + def test_bool_closed_is_false(self): + """Ensure closed db is False.""" + + with gdbm.open(filename, 'c') as db: + db['a'] = 'b' + + # After closing, should be False + self.assertFalse(bool(db)) + + 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 Tue Apr 15 10:11:28 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(self.d)) + + 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_closed_is_false(self): + """Ensure closed db is False.""" + + with dbm.ndbm.open(self.filename, 'c') as db: + db['a'] = 'b' + + # After closing, should be False + self.assertFalse(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 Tue Apr 15 10:11:28 2014 -0500 @@ -220,6 +220,27 @@ } static int +dbm_bool(dbmobject *dp) +{ + datum key; + + if (dp->di_dbm == NULL) { + // DMB object closed + return 0; + } + + 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 Tue Apr 15 10:11:28 2014 -0500 @@ -286,6 +286,26 @@ } static int +dbm_bool(dbmobject *dp) +{ + datum key; + + if (dp->di_dbm == NULL) { + // DMB object closed + return 0; + } + + 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*/