Hello community, here is the log from the commit of package python-lmdb for openSUSE:Factory checked in at 2020-08-18 12:00:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-lmdb (Old) and /work/SRC/openSUSE:Factory/.python-lmdb.new.3399 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-lmdb" Tue Aug 18 12:00:30 2020 rev:6 rq:827393 version:0.99 Changes: -------- --- /work/SRC/openSUSE:Factory/python-lmdb/python-lmdb.changes 2019-11-26 17:04:23.340006565 +0100 +++ /work/SRC/openSUSE:Factory/.python-lmdb.new.3399/python-lmdb.changes 2020-08-18 12:02:52.731422124 +0200 @@ -1,0 +2,13 @@ +Mon Aug 17 16:04:47 UTC 2020 - Michael Ströder <[email protected]> + +- Update to v0.99 + * Fix lmdb.tool encoding issues. + * Fix -l lmdb invocation issue. + * Minor documentation improvements. + * Update LMDB to version 0.9.24. + * Update for Python 3.9 (current release candidate) support. + * Resolve a bug when using cursor.putmulti and append=True on dupsort DBs. + * Allow _Database.flags method to take no arguments since the one argument + wasn't being used. + +------------------------------------------------------------------- Old: ---- lmdb-0.98.tar.gz New: ---- lmdb-0.99.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-lmdb.spec ++++++ --- /var/tmp/diff_new_pack.m5h7WL/_old 2020-08-18 12:02:53.739422262 +0200 +++ /var/tmp/diff_new_pack.m5h7WL/_new 2020-08-18 12:02:53.739422262 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-lmdb # -# Copyright (c) 2019 SUSE LLC +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-lmdb -Version: 0.98 +Version: 0.99 Release: 0 Summary: Universal Python binding for the LMDB 'Lightning' Database License: OLDAP-2.8 ++++++ lmdb-0.98.tar.gz -> lmdb-0.99.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/ChangeLog new/lmdb-0.99/ChangeLog --- old/lmdb-0.98/ChangeLog 2019-11-06 18:52:32.000000000 +0100 +++ new/lmdb-0.99/ChangeLog 2020-08-13 14:05:07.000000000 +0200 @@ -1,3 +1,20 @@ +2020-08-13 v0.99 +* Fix lmdb.tool encoding issues. + +* Fix -l lmdb invocation issue. + +* Minor documentation improvements. + +* Update LMDB to version 0.9.24. + +* Update for Python 3.9 (current release candidate) support. + +* Resolve a bug when using cursor.putmulti and append=True on dupsort DBs. + +* Allow _Database.flags method to take no arguments since the one argument + wasn't being used. + + 2019-11-06 v0.98 * Fix that a duplicate argument to a lmdb method would cause an assert. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/PKG-INFO new/lmdb-0.99/PKG-INFO --- old/lmdb-0.98/PKG-INFO 2019-11-06 22:40:10.000000000 +0100 +++ new/lmdb-0.99/PKG-INFO 2020-08-13 14:37:31.504410500 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: lmdb -Version: 0.98 +Version: 0.99 Summary: Universal Python binding for the LMDB 'Lightning' Database Home-page: http://github.com/jnwatson/py-lmdb/ Author: David Wilson diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/README.md new/lmdb-0.99/README.md --- old/lmdb-0.98/README.md 2019-11-06 18:52:32.000000000 +0100 +++ new/lmdb-0.99/README.md 2020-08-13 14:05:07.000000000 +0200 @@ -15,6 +15,18 @@ the tests under your desired target Python release, as the Travis CI build has a bad habit of breaking due to external factors approximately every 3 months. +# Python Version Support Statement + +This project has been around for a while. Previously, it supported all the way back to before 2.5. Currently py-lmdb +supports Python 2.7, Python >= 3.4, and pypy. + +Python 2.7 is now end-of-life. If you are still using Python 2.7, you should strongly considering porting to Python +3. + +That said, this project will continue to support running on Python 2.7 until Travis CI or Appveyor remove support for +it. + # Sponsored by The Vertex Project -My current employer, [The Vertex Project](https://vertex.link/) is generously sponsoring my time to maintain py-lmdb. If you like open source and systems programming in Python, check us out. We could definitely use some more hands. +My current employer, [The Vertex Project](https://vertex.link/) is generously sponsoring my time to maintain py-lmdb. +If you like open source and systems programming in Python, check us out. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/docs/conf.py new/lmdb-0.99/docs/conf.py --- old/lmdb-0.98/docs/conf.py 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/docs/conf.py 2020-08-13 14:05:07.000000000 +0200 @@ -43,7 +43,7 @@ # General information about the project. project = u'lmdb' -copyright = u'2013, David Wilson' +copyright = u'2013-2019 David Wilson, 2019-2020 Nic Watson' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -107,7 +107,7 @@ # further. For a list of options available for each theme, see the # documentation. html_theme_options = { - 'github_repo': 'https://github.com/dw/py-lmdb/' + 'github_repo': 'https://github.com/jnwatson/py-lmdb/' } # Add any paths that contain custom themes here, relative to this directory. @@ -196,7 +196,7 @@ # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'lmdb.tex', u'lmdb Documentation', - u'David Wilson', 'manual'), + u'David Wilson and Nic Watson', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/docs/index.rst new/lmdb-0.99/docs/index.rst --- old/lmdb-0.98/docs/index.rst 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/docs/index.rst 2020-08-13 14:05:07.000000000 +0200 @@ -284,10 +284,9 @@ .. caution:: - This option may cause filesystems that don't support sparse files, such as - OSX, to immediately preallocate `map_size=` bytes of underlying storage - when the environment is opened or closed for the first time. - + A filesystem failure (such as running out of space), will crash the Python + process if this option is enabled. (This is a general OS limitation, and + not limited to LMDB). Resource Management +++++++++++++++++++ @@ -407,6 +406,11 @@ .. autoclass:: lmdb.Environment :members: +Database class +############## + +.. autoclass:: lmdb._Database + :members: Transaction class ################# @@ -414,14 +418,12 @@ .. autoclass:: lmdb.Transaction :members: - Cursor class ############ .. autoclass:: lmdb.Cursor :members: - Exceptions ########## diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/lib/lmdb.h new/lmdb-0.99/lib/lmdb.h --- old/lmdb-0.98/lib/lmdb.h 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/lib/lmdb.h 2020-08-13 14:05:07.000000000 +0200 @@ -135,7 +135,7 @@ * * @author Howard Chu, Symas Corporation. * - * @copyright Copyright 2011-2018 Howard Chu, Symas Corp. All rights reserved. + * @copyright Copyright 2011-2019 Howard Chu, Symas Corp. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP @@ -200,7 +200,7 @@ /** Library minor version */ #define MDB_VERSION_MINOR 9 /** Library patch version */ -#define MDB_VERSION_PATCH 22 +#define MDB_VERSION_PATCH 24 /** Combine args a,b,c into a single integer for easy version comparisons */ #define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c)) @@ -210,7 +210,7 @@ MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH) /** The release date of this library version */ -#define MDB_VERSION_DATE "March 21, 2018" +#define MDB_VERSION_DATE "July 24, 2019" /** A stringifier for the version info */ #define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")" @@ -370,7 +370,7 @@ MDB_GET_BOTH, /**< Position at key/data pair. Only for #MDB_DUPSORT */ MDB_GET_BOTH_RANGE, /**< position at key, nearest data. Only for #MDB_DUPSORT */ MDB_GET_CURRENT, /**< Return key/data at current cursor position */ - MDB_GET_MULTIPLE, /**< Return key and up to a page of duplicate data items + MDB_GET_MULTIPLE, /**< Return up to a page of duplicate data items from current cursor position. Move cursor to prepare for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */ MDB_LAST, /**< Position at last key/data item */ @@ -379,7 +379,7 @@ MDB_NEXT, /**< Position at next data item */ MDB_NEXT_DUP, /**< Position at next data item of current key. Only for #MDB_DUPSORT */ - MDB_NEXT_MULTIPLE, /**< Return key and up to a page of duplicate data items + MDB_NEXT_MULTIPLE, /**< Return up to a page of duplicate data items from next cursor position. Move cursor to prepare for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */ MDB_NEXT_NODUP, /**< Position at first data item of next key */ @@ -390,7 +390,7 @@ MDB_SET, /**< Position at specified key */ MDB_SET_KEY, /**< Position at specified key, return key + data */ MDB_SET_RANGE, /**< Position at first key greater than or equal to specified key. */ - MDB_PREV_MULTIPLE /**< Position at previous page and return key and up to + MDB_PREV_MULTIPLE /**< Position at previous page and return up to a page of duplicate data items. Only for #MDB_DUPFIXED */ } MDB_cursor_op; @@ -1510,6 +1510,10 @@ /** @brief Delete current key/data pair * * This function deletes the key/data pair to which the cursor refers. + * This does not invalidate the cursor, so operations such as MDB_NEXT + * can still be used on it. + * Both MDB_NEXT and MDB_GET_CURRENT will return the same record after + * this operation. * @param[in] cursor A cursor handle returned by #mdb_cursor_open() * @param[in] flags Options for this operation. This parameter * must be set to 0 or one of the values described here. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/lib/mdb.c new/lmdb-0.99/lib/mdb.c --- old/lmdb-0.98/lib/mdb.c 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/lib/mdb.c 2020-08-13 14:05:07.000000000 +0200 @@ -5,7 +5,7 @@ * BerkeleyDB API, but much simplified. */ /* - * Copyright 2011-2018 Howard Chu, Symas Corp. + * Copyright 2011-2019 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -3094,10 +3094,41 @@ * we may be unable to return them to me_pghead. */ MDB_page *mp = txn->mt_loose_pgs; + MDB_ID2 *dl = txn->mt_u.dirty_list; + unsigned x; if ((rc = mdb_midl_need(&txn->mt_free_pgs, txn->mt_loose_count)) != 0) return rc; - for (; mp; mp = NEXT_LOOSE_PAGE(mp)) + for (; mp; mp = NEXT_LOOSE_PAGE(mp)) { mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno); + /* must also remove from dirty list */ + if (txn->mt_flags & MDB_TXN_WRITEMAP) { + for (x=1; x<=dl[0].mid; x++) + if (dl[x].mid == mp->mp_pgno) + break; + mdb_tassert(txn, x <= dl[0].mid); + } else { + x = mdb_mid2l_search(dl, mp->mp_pgno); + mdb_tassert(txn, dl[x].mid == mp->mp_pgno); + mdb_dpage_free(env, mp); + } + dl[x].mptr = NULL; + } + { + /* squash freed slots out of the dirty list */ + unsigned y; + for (y=1; dl[y].mptr && y <= dl[0].mid; y++); + if (y <= dl[0].mid) { + for(x=y, y++;;) { + while (!dl[y].mptr && y <= dl[0].mid) y++; + if (y > dl[0].mid) break; + dl[x++] = dl[y++]; + } + dl[0].mid = x-1; + } else { + /* all slots freed */ + dl[0].mid = 0; + } + } txn->mt_loose_pgs = NULL; txn->mt_loose_count = 0; } @@ -3960,9 +3991,9 @@ * and won't map more than the file size. * Just set the maxsize right now. */ - if (SetFilePointer(env->me_fd, sizelo, &sizehi, 0) != (DWORD)sizelo + if (!(flags & MDB_WRITEMAP) && (SetFilePointer(env->me_fd, sizelo, &sizehi, 0) != (DWORD)sizelo || !SetEndOfFile(env->me_fd) - || SetFilePointer(env->me_fd, 0, NULL, 0) != 0) + || SetFilePointer(env->me_fd, 0, NULL, 0) != 0)) return ErrCode(); } @@ -5063,7 +5094,7 @@ if (env->me_fd != INVALID_HANDLE_VALUE) (void) close(env->me_fd); if (env->me_txns) { - MDB_PID_T pid = env->me_pid; + MDB_PID_T pid = getpid(); /* Clearing readers is done in this function because * me_txkey with its destructor must be disabled first. * @@ -8718,7 +8749,7 @@ * the split so the new page is emptier than the old page. * This yields better packing during sequential inserts. */ - if (nkeys < 20 || nsize > pmax/16 || newindx >= nkeys) { + if (nkeys < 32 || nsize > pmax/16 || newindx >= nkeys) { /* Find split point */ psize = 0; if (newindx <= split_indx || newindx >= nkeys) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/lib/midl.c new/lmdb-0.99/lib/midl.c --- old/lmdb-0.98/lib/midl.c 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/lib/midl.c 2020-08-13 14:05:07.000000000 +0200 @@ -3,7 +3,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software <http://www.openldap.org/>. * - * Copyright 2000-2018 The OpenLDAP Foundation. + * Copyright 2000-2019 The OpenLDAP Foundation. * Portions Copyright 2001-2018 Howard Chu, Symas Corp. * All rights reserved. * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/lib/midl.h new/lmdb-0.99/lib/midl.h --- old/lmdb-0.98/lib/midl.h 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/lib/midl.h 2020-08-13 14:05:07.000000000 +0200 @@ -11,7 +11,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software <http://www.openldap.org/>. * - * Copyright 2000-2018 The OpenLDAP Foundation. + * Copyright 2000-2019 The OpenLDAP Foundation. * Portions Copyright 2001-2018 Howard Chu, Symas Corp. * All rights reserved. * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/lib/py-lmdb/preload.h new/lmdb-0.99/lib/py-lmdb/preload.h --- old/lmdb-0.98/lib/py-lmdb/preload.h 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/lib/py-lmdb/preload.h 2020-08-13 14:05:07.000000000 +0200 @@ -23,6 +23,8 @@ #ifndef LMDB_PRELOAD_H #define LMDB_PRELOAD_H +#include <stdlib.h> + /** * Touch a byte from every page in `x`, causing any read faults necessary for * copying the value to occur. This should be called with the GIL released, in @@ -37,7 +39,7 @@ static void preload(int rc, void *x, size_t size) { if(rc == 0) { volatile char j; - int i; + size_t i; for(i = 0; i < size; i += 4096) { j = ((volatile char *)x)[i]; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/lmdb/__init__.py new/lmdb-0.99/lmdb/__init__.py --- old/lmdb-0.98/lmdb/__init__.py 2019-11-06 18:52:32.000000000 +0100 +++ new/lmdb-0.99/lmdb/__init__.py 2020-08-13 14:05:07.000000000 +0200 @@ -19,7 +19,7 @@ # <http://www.openldap.org/>. """ -cffi wrapper for OpenLDAP's "Lightning" MDB database. +Python wrapper for OpenLDAP's "Lightning" MDB database. Please see https://lmdb.readthedocs.io/ """ @@ -50,5 +50,4 @@ from lmdb.cffi import __all__ from lmdb.cffi import __doc__ -__version__ = '0.98' - +__version__ = '0.99' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/lmdb/cffi.py new/lmdb-0.99/lmdb/cffi.py --- old/lmdb-0.98/lmdb/cffi.py 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/lmdb/cffi.py 2020-08-13 14:05:07.000000000 +0200 @@ -55,6 +55,7 @@ 'Cursor', 'Environment', 'Transaction', + '_Database', 'enable_drop_gil', 'version', ] @@ -98,7 +99,7 @@ EMPTY_BYTES = UnicodeType().encode() -# Used to track context across CFFI callbcks. +# Used to track context across CFFI callbacks. _callbacks = threading.local() _CFFI_CDEF = ''' @@ -236,6 +237,7 @@ #define MDB_VERSION_MISMATCH ... #define MDB_APPEND ... + #define MDB_APPENDDUP ... #define MDB_CP_COMPACT ... #define MDB_CREATE ... #define MDB_DUPFIXED ... @@ -1031,7 +1033,7 @@ create=True, integerkey=False, integerdup=False, dupfixed=False): """ - Open a database, returning an opaque handle. Repeat + Open a database, returning an instance of :py:class:`_Database`. Repeat :py:meth:`Environment.open_db` calls for the same name will return the same handle. As a special case, the main database is always open. @@ -1062,6 +1064,13 @@ process. Only one thread should call this function; it is not mutex-protected in a read-only transaction. + The `dupsort`, `integerkey`, `integerdup`, and `dupfixed` parameters are + ignored if the database already exists. The state of those settings are + persistent and immutable per database. See :py:meth:`_Database.flags` + to view the state of those options for an opened database. A consequence + of the immutability of these flags is that the default non-named database + will never have these flags set. + Preexisting transactions, other than the current transaction and any parents, must not use the new handle, nor must their children. @@ -1135,7 +1144,12 @@ class _Database(object): - """Internal database handle.""" + """ + Internal database handle. This class is opaque, save a single method. + + Should not be constructed directly. Use :py:meth:`Environment.open_db` + instead. + """ def __init__(self, env, txn, name, reverse_key, dupsort, create, integerkey, integerdup, dupfixed): env._deps.add(self) @@ -1171,9 +1185,12 @@ raise _error("mdb_dbi_flags", rc) self._flags = flags_[0] - def flags(self, txn): + def flags(self, *args): """Return the database's associated flags as a dict of _Database constructor kwargs.""" + if len(args) > 1: + raise TypeError('flags takes 0 or 1 arguments') + return { 'reverse_key': bool(self._flags & _lib.MDB_REVERSEKEY), 'dupsort': bool(self._flags & _lib.MDB_DUPSORT), @@ -1526,7 +1543,7 @@ <http://symas.com/mdb/doc/group__mdb.html#ga9ff5d7bd42557fd5ee235dc1d62613aa>`_ `db`: - :py:class:`Database` to navigate. + :py:class:`_Database` to navigate. `txn`: :py:class:`Transaction` to navigate. @@ -2007,8 +2024,8 @@ def set_range_dup(self, key, value): """Seek to the first key/value pair greater than or equal to `key`, - returning ``True`` on success, or ``False`` to indicate `(key, value)` - was past end of database. + returning ``True`` on success, or ``False`` to indicate that `value` was past the + last value of `key` or that `(key, value)` was past the end end of database. Only meaningful for databases opened with `dupsort=True`. @@ -2144,7 +2161,10 @@ if not overwrite: flags |= _lib.MDB_NOOVERWRITE if append: - flags |= _lib.MDB_APPEND + if self.txn._db._flags & _lib.MDB_DUPSORT: + flags |= _lib.MDB_APPENDDUP + else: + flags |= _lib.MDB_APPEND added = 0 skipped = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/lmdb/cpython.c new/lmdb-0.99/lmdb/cpython.c --- old/lmdb-0.98/lmdb/cpython.c 2019-11-06 18:52:32.000000000 +0100 +++ new/lmdb-0.99/lmdb/cpython.c 2020-08-13 14:05:07.000000000 +0200 @@ -861,33 +861,35 @@ self = env->spare_txns; DEBUG("found freelist txn; self=%p self->txn=%p", self, self->txn) env->spare_txns = self->spare_next; - env->max_spare_txns++; - self->flags &= ~TRANS_SPARE; - _Py_NewReference((PyObject *)self); - UNLOCKED(rc, mdb_txn_renew(self->txn)); + UNLOCKED(rc, mdb_txn_renew(self->txn)); if(rc) { mdb_txn_abort(self->txn); - self->txn = NULL; + PyObject_Del(self); + return err_set("mdb_txn_begin", rc); } + + env->max_spare_txns++; + self->flags &= ~TRANS_SPARE; + } else { + MDB_txn *txn; if(write && env->readonly) { const char *msg = "Cannot start write transaction with read-only env"; return err_set(msg, EACCES); } + flags = write ? 0 : MDB_RDONLY; + UNLOCKED(rc, mdb_txn_begin(env->env, parent_txn, flags, &txn)); + if(rc) { + return err_set("mdb_txn_begin", rc); + } + if(! ((self = PyObject_New(TransObject, &PyTransaction_Type)))) { + mdb_txn_abort(txn); return NULL; } - - flags = write ? 0 : MDB_RDONLY; - UNLOCKED(rc, mdb_txn_begin(env->env, parent_txn, flags, &self->txn)); - } - - if(rc) { - _Py_ForgetReference((PyObject *)self); - PyObject_Del(self); - return err_set("mdb_txn_begin", rc); + self->txn = txn; } OBJECT_INIT(self) @@ -917,6 +919,7 @@ make_cursor(DbObject *db, TransObject *trans) { CursorObject *self; + MDB_cursor *curs; int rc; if(! trans->valid) { @@ -928,20 +931,26 @@ return NULL; } - self = PyObject_New(CursorObject, &PyCursor_Type); - UNLOCKED(rc, mdb_cursor_open(trans->txn, db->dbi, &self->curs)); + UNLOCKED(rc, mdb_cursor_open(trans->txn, db->dbi, &curs)); if(rc) { - _Py_ForgetReference((PyObject *)self); - PyObject_Del(self); return err_set("mdb_cursor_open", rc); } + self = PyObject_New(CursorObject, &PyCursor_Type); + if (!self) { + mdb_cursor_close(curs); + return NULL; + } + DEBUG("sizeof cursor = %d", (int) sizeof *self) OBJECT_INIT(self) LINK_CHILD(trans, self) + self->curs = curs; self->positioned = 0; self->key.mv_size = 0; + self->key.mv_data = NULL; self->val.mv_size = 0; + self->val.mv_data = NULL; self->trans = trans; self->last_mutation = trans->mutations; self->dbi_flags = db->flags; @@ -1041,23 +1050,11 @@ PyObject *dct; unsigned int f; - struct db_flags { - TransObject *txn; - } arg = {NULL}; - - static const struct argspec argspec[] = { - {"txn", ARG_TRANS, OFFSET(db_flags, txn)} - }; - - static PyObject *cache = NULL; - if(parse_args(self->valid, SPECSIZE(), argspec, &cache, args, kwds, &arg)) { - return NULL; - } - if(! arg.txn) { - return type_error("'txn' argument required"); - } - if(! arg.txn->valid) { - return err_invalid(); + if (args) { + Py_ssize_t size = PyTuple_GET_SIZE(args); + if(size > 1) { + return type_error("too many positional arguments."); + } } dct = PyDict_New(); @@ -2244,7 +2241,7 @@ flags |= MDB_NOOVERWRITE; } if(arg.append) { - flags |= MDB_APPEND; + flags |= (self->trans->db->flags & MDB_DUPSORT) ? MDB_APPENDDUP : MDB_APPEND; } if(! ((iter = PyObject_GetIter(arg.items)))) { @@ -2581,14 +2578,17 @@ new_iterator(CursorObject *cursor, IterValFunc val_func, MDB_cursor_op op) { IterObject *iter = PyObject_New(IterObject, &PyIterator_Type); - if(iter) { - iter->val_func = val_func; - iter->curs = cursor; - Py_INCREF(cursor); - iter->started = 0; - iter->op = op; + if (!iter) { + return NULL; } - DEBUG("new_iterator: %#p", (void *)iter) + + iter->val_func = val_func; + iter->curs = cursor; + Py_INCREF(cursor); + iter->started = 0; + iter->op = op; + + DEBUG("new_iterator: %p", (void *)iter) return (PyObject *) iter; } @@ -2992,15 +2992,17 @@ self->spare_next = self->env->spare_txns; self->env->spare_txns = self; self->env->max_spare_txns--; + Py_INCREF(self); Py_CLEAR(self->db); UNLINK_CHILD(self->env, self) Py_CLEAR(self->env); - } else { - MDEBUG("deleting trans") - trans_clear(self); - PyObject_Del(self); + return; } + + MDEBUG("deleting trans") + trans_clear(self); + PyObject_Del(self); } /** @@ -3618,15 +3620,18 @@ int i; for(i = 0; types[i]; i++) { PyTypeObject *type = types[i]; + char const * name = type->tp_name; if(PyType_Ready(type)) { return -1; } - if(PyObject_SetAttrString(mod, type->tp_name, (PyObject *)type)) { + if(PyObject_SetAttrString(mod, name, (PyObject *)type)) { return -1; } - if(type->tp_name[0] != '_' && append_string(__all__, type->tp_name)) { + /* As a special case, export _Database */ + if((name[0] != '_' || 0 == strcmp(name, "_Database")) && + append_string(__all__, name)) { return -1; } } Binary files old/lmdb-0.98/lmdb/cpython.cpython-39d-x86_64-linux-gnu.so and new/lmdb-0.99/lmdb/cpython.cpython-39d-x86_64-linux-gnu.so differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/lmdb/tool.py new/lmdb-0.99/lmdb/tool.py --- old/lmdb-0.98/lmdb/tool.py 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/lmdb/tool.py 2020-08-13 14:05:07.000000000 +0200 @@ -251,7 +251,7 @@ die('"copyfd" command takes no arguments (see --help)') try: - fp = os.fdopen(opts.out_fd, 'w', 0) + os.fdopen(opts.out_fd, 'w', 0) except OSError: e = sys.exc_info()[1] die('Bad --out-fd %d: %s', opts.out_fd, e) @@ -509,8 +509,8 @@ dbs = [] for arg in args: name = None if arg == ':main:' else arg - src_db = ENV.open_db(name) - dst_db = target_env.open_db(name) + src_db = ENV.open_db(_to_bytes(name)) + dst_db = target_env.open_db(_to_bytes(name)) dbs.append((arg, src_db, dst_db)) if not dbs: @@ -590,7 +590,7 @@ s = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234') height, width = struct.unpack('hh', s) return width, height - except: + except Exception: return default @@ -599,9 +599,9 @@ _TERM_WIDTH, _TERM_HEIGHT = _get_term_width() -def main(): +def main(argv=None): parser = make_parser() - opts, args = parser.parse_args() + opts, args = parser.parse_args(argv) if not args: die('Please specify a command (see --help)') @@ -614,7 +614,7 @@ if opts.db: global DB - DB = ENV.open_db(opts.db) + DB = ENV.open_db(_to_bytes(opts.db)) if hasattr(signal, 'SIGWINCH'): # Disable on win32. signal.signal(signal.SIGWINCH, _on_sigwinch) @@ -628,4 +628,4 @@ if __name__ == '__main__': - main() + main(sys.argv[1:]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/lmdb.egg-info/PKG-INFO new/lmdb-0.99/lmdb.egg-info/PKG-INFO --- old/lmdb-0.98/lmdb.egg-info/PKG-INFO 2019-11-06 22:40:10.000000000 +0100 +++ new/lmdb-0.99/lmdb.egg-info/PKG-INFO 2020-08-13 14:37:31.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: lmdb -Version: 0.98 +Version: 0.99 Summary: Universal Python binding for the LMDB 'Lightning' Database Home-page: http://github.com/jnwatson/py-lmdb/ Author: David Wilson diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/lmdb.egg-info/SOURCES.txt new/lmdb-0.99/lmdb.egg-info/SOURCES.txt --- old/lmdb-0.98/lmdb.egg-info/SOURCES.txt 2019-11-06 22:40:10.000000000 +0100 +++ new/lmdb-0.99/lmdb.egg-info/SOURCES.txt 2020-08-13 14:37:31.000000000 +0200 @@ -38,6 +38,7 @@ lmdb/_config.py lmdb/cffi.py lmdb/cpython.c +lmdb/cpython.cpython-39d-x86_64-linux-gnu.so lmdb/tool.py lmdb.egg-info/PKG-INFO lmdb.egg-info/SOURCES.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/setup.py new/lmdb-0.99/setup.py --- old/lmdb-0.98/setup.py 2019-11-06 18:52:32.000000000 +0100 +++ new/lmdb-0.99/setup.py 2020-08-13 14:05:07.000000000 +0200 @@ -44,14 +44,10 @@ if os.getenv('LMDB_FORCE_CFFI') is not None: use_cpython = False -if sys.version[:3] < '2.5': - sys.stderr.write('Error: py-lmdb requires at least CPython 2.5\n') +if sys.version[:3] < '2.7' or (sys.version_info[0] == 3 and sys.version[:3] < '3.4'): + sys.stderr.write('Error: py-lmdb requires at least CPython 2.7 or 3.4\n') raise SystemExit(1) -if sys.version[:3] in ('3.0', '3.1', '3.2'): - use_cpython = False - - # # Figure out which LMDB implementation to use. # diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/tests/cursor_test.py new/lmdb-0.99/tests/cursor_test.py --- old/lmdb-0.98/tests/cursor_test.py 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/tests/cursor_test.py 2020-08-13 14:05:07.000000000 +0200 @@ -31,7 +31,6 @@ from testlib import B from testlib import BT - class ContextManagerTest(unittest.TestCase): def tearDown(self): testlib.cleanup() @@ -50,7 +49,7 @@ try: with txn.cursor() as curs: curs.put(123, 123) - except: + except Exception: pass self.assertRaises(Exception, lambda: curs.get(B('foo'))) @@ -174,6 +173,21 @@ self.assertRaises(Exception, lambda: self.c.putmulti(range(2))) + def test_dupsort(self): + _, env = testlib.temp_env() + db1 = env.open_db(B('db1'), dupsort=True) + txn = env.begin(write=True, db=db1) + with txn.cursor() as c: + tups = [BT('a', 'value1'), BT('b', 'value1'), BT('b', 'value2')] + assert (3, 3) == c.putmulti(tups) + + def test_dupsort_append(self): + _, env = testlib.temp_env() + db1 = env.open_db(B('db1'), dupsort=True) + txn = env.begin(write=True, db=db1) + with txn.cursor() as c: + tups = [BT('a', 'value1'), BT('b', 'value1'), BT('b', 'value2')] + assert (3, 3) == c.putmulti(tups, append=True) class ReplaceTest(CursorTestBase): def test_replace(self): @@ -258,7 +272,7 @@ self.c.value() minflts_after_value = resource.getrusage(resource.RUSAGE_THREAD)[6] - epsilon = 5 + epsilon = 20 # Setting the position doesn't prefault the data assert minflts_after_key - minflts_before < epsilon diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/tests/env_test.py new/lmdb-0.99/tests/env_test.py --- old/lmdb-0.98/tests/env_test.py 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/tests/env_test.py 2020-08-13 14:05:07.000000000 +0200 @@ -23,14 +23,12 @@ from __future__ import absolute_import from __future__ import with_statement import os -import signal import sys import unittest import weakref import testlib from testlib import B -from testlib import BT from testlib import OCT from testlib import INT_TYPES from testlib import UnicodeType @@ -704,6 +702,9 @@ key = B('%s-%s' % (flag, val)) db = env.open_db(key, txn=txn, **{flag: val}) assert db.flags(txn)[flag] == val + assert db.flags(None)[flag] == val + assert db.flags()[flag] == val + self.assertRaises(TypeError, lambda: db.flags(1, 2, 3)) txn.commit() # Test flag persistence. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/tests/package_test.py new/lmdb-0.99/tests/package_test.py --- old/lmdb-0.98/tests/package_test.py 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/tests/package_test.py 2020-08-13 14:05:07.000000000 +0200 @@ -63,6 +63,7 @@ 'Transaction', 'TxnFullError', 'VersionMismatchError', + '_Database', 'enable_drop_gil', 'version', ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/tests/testlib.py new/lmdb-0.99/tests/testlib.py --- old/lmdb-0.98/tests/testlib.py 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/tests/testlib.py 2020-08-13 14:05:07.000000000 +0200 @@ -29,6 +29,7 @@ import sys import tempfile import traceback +import unittest try: import __builtin__ @@ -37,7 +38,6 @@ import lmdb - _cleanups = [] def cleanup(): @@ -50,6 +50,10 @@ atexit.register(cleanup) +class LmdbTest(unittest.TestCase): + def tearDown(self): + cleanup() + def temp_dir(create=True): path = tempfile.mkdtemp(prefix='lmdb_test') @@ -99,12 +103,9 @@ # PyPy doesn't collect objects with __del__ on first attempt. gc.collect() - -# Handle moronic Python >=3.0 <3.3. UnicodeType = getattr(__builtin__, 'unicode', str) BytesType = getattr(__builtin__, 'bytes', str) - try: INT_TYPES = (int, long) except NameError: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/tests/tool_test.py new/lmdb-0.99/tests/tool_test.py --- old/lmdb-0.98/tests/tool_test.py 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/tests/tool_test.py 2020-08-13 14:05:07.000000000 +0200 @@ -21,17 +21,37 @@ # from __future__ import absolute_import + +import sys +import shlex import unittest import lmdb import lmdb.tool +import testlib - -class ToolTest(unittest.TestCase): - def test_ok(self): - # For now, simply ensure the module can be compiled (3.x compat). - pass - +def call_tool(cmdline): + if sys.platform == 'win32': + args = cmdline.split() + else: + args = shlex.split(cmdline) + return lmdb.tool.main(args) + +class ToolTest(testlib.LmdbTest): + def test_cmd_get(self): + frompath, env = testlib.temp_env() + db = env.open_db(b'subdb') + with env.begin(write=True, db=db) as txn: + txn.put(b'foo', b'bar', db=db) + env.close() + call_tool('-d subdb get --env %s' % (frompath,)) + + def test_cmd_rewrite(self): + frompath, env = testlib.temp_env() + env.open_db(b'subdb') + env.close() + topath = testlib.temp_dir() + call_tool('rewrite -e %s -E %s subdb' % (frompath, topath)) if __name__ == '__main__': unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lmdb-0.98/tests/txn_test.py new/lmdb-0.99/tests/txn_test.py --- old/lmdb-0.98/tests/txn_test.py 2019-11-06 18:52:11.000000000 +0100 +++ new/lmdb-0.99/tests/txn_test.py 2020-08-13 14:05:07.000000000 +0200 @@ -28,11 +28,8 @@ import testlib from testlib import B -from testlib import BT -from testlib import OCT from testlib import INT_TYPES from testlib import BytesType -from testlib import UnicodeType import lmdb
