Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-lmdb for openSUSE:Factory 
checked in at 2021-04-21 20:59:35
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-lmdb (Old)
 and      /work/SRC/openSUSE:Factory/.python-lmdb.new.12324 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-lmdb"

Wed Apr 21 20:59:35 2021 rev:8 rq:886821 version:1.2.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-lmdb/python-lmdb.changes  2021-02-07 
15:23:44.334179978 +0100
+++ /work/SRC/openSUSE:Factory/.python-lmdb.new.12324/python-lmdb.changes       
2021-04-21 20:59:50.042242417 +0200
@@ -1,0 +2,21 @@
+Tue Apr 20 02:10:56 UTC 2021 - Mia Herkt <m...@0x0.st>
+
+- Update to v1.2.1 (no changes)
+
+-------------------------------------------------------------------
+Sun Apr 18 21:58:00 UTC 2021 - Mia Herkt <m...@0x0.st>
+
+- Update to v1.2.0
+  * Remove wheel generation for 2.7 because the manylinux images
+    no longer support it.
+  * Allow passing None as a value to transaction.del in CFFI
+    implementation for parity with cpython implementation.
+  * Fix Cursor.put behavior on a dupsort DB with append=True.
+  * Add warning to docs about use of Environment.set_mapsize.
+    This is currently an unresolved issue with upstream LMDB.
+  * CFFI implementation:
+    fix a seg fault when open_db returns map full.
+  * CFFI implementation:
+    fix a bug in open_db in a read-only environment.
+
+-------------------------------------------------------------------

Old:
----
  lmdb-1.1.0.tar.gz

New:
----
  lmdb-1.2.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-lmdb.spec ++++++
--- /var/tmp/diff_new_pack.5YHXiQ/_old  2021-04-21 20:59:50.558243229 +0200
+++ /var/tmp/diff_new_pack.5YHXiQ/_new  2021-04-21 20:59:50.562243235 +0200
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-lmdb
-Version:        1.1.0
+Version:        1.2.1
 Release:        0
 Summary:        Universal Python binding for the LMDB 'Lightning' Database
 License:        OLDAP-2.8

++++++ lmdb-1.1.0.tar.gz -> lmdb-1.2.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.1.0/ChangeLog new/lmdb-1.2.1/ChangeLog
--- old/lmdb-1.1.0/ChangeLog    2021-02-04 23:00:08.000000000 +0100
+++ new/lmdb-1.2.1/ChangeLog    2021-04-19 21:10:32.000000000 +0200
@@ -1,3 +1,32 @@
+2021-04-19 v1.2.1
+* Resolve CI bug where non-Linux wheels were not being published to PyPI.
+
+2021-04-15 v1.2.0
+* Update bundled LMDB to 0.9.29.
+
+* Add non-bundled testing to CI.
+
+* Remove wheel generation for 2.7 because the manylinux images no longer
+  support it.
+
+* Allow passing None as a value to transaction.del in CFFI implementation
+  for parity with cpython implementation.
+
+* Fix Cursor.put behavior on a dupsort DB with append=True.
+
+* Add warning to docs about use of Environment.set_mapsize.  This is currently
+an unresolved issue with upstream LMDB.
+
+* CFFI implementation:  fix a seg fault when open_db returns map full.
+
+* CFFI implementation:  fix a bug in open_db in a read-only environment.
+
+
+2021-02-05 v1.1.1
+* Dowgrade underlying LMDB to 0.9.26.  0.9.27 has a minor defect that will
+  need to get resolved.
+
+
 2021-02-04 v1.1.0
 * Migrate CI pipeline from Travis and AppVeyor to Github Actions.  Now
   includes comprehensive testing across 4 dimensions (OS, Python version,
@@ -10,6 +39,7 @@
 
 * Upgrade underlying LMDB to 0.9.27.
 
+
 2020-08-28 v1.0.0
 * Start of new semantic versioning scheme.  This would be a minor version
   bump from the 0.99 release if it were semantically versioned.
@@ -19,6 +49,7 @@
   underlying C library.  By default, the patch will be applied unless
   this module is built with LMDB_PURE environment variable set.
 
+
 2020-08-13 v0.99
 * Fix lmdb.tool encoding issues.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.1.0/PKG-INFO new/lmdb-1.2.1/PKG-INFO
--- old/lmdb-1.1.0/PKG-INFO     2021-02-04 23:00:18.689847200 +0100
+++ new/lmdb-1.2.1/PKG-INFO     2021-04-19 21:10:55.101324800 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: lmdb
-Version: 1.1.0
+Version: 1.2.1
 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-1.1.0/docs/index.rst 
new/lmdb-1.2.1/docs/index.rst
--- old/lmdb-1.1.0/docs/index.rst       2021-02-04 23:00:08.000000000 +0100
+++ new/lmdb-1.2.1/docs/index.rst       2021-04-19 21:10:32.000000000 +0200
@@ -9,7 +9,7 @@
     :maxdepth: 2
 
 This is a universal Python binding for the `LMDB 'Lightning' Database
-<http://symas.com/mdb/>`_. Two variants are provided and automatically selected
+<http://lmdb.tech/>`_. Two variants are provided and automatically selected
 during install: a `CFFI <https://cffi.readthedocs.io/en/release-0.5/>`_ variant
 that supports `PyPy <http://www.pypy.org/>`_ and all versions of CPython >=2.7,
 and a C extension that supports CPython >=2.7 and >=3.4. Both variants
@@ -105,7 +105,7 @@
 
 Before getting in contact, please ensure you have thoroughly reviewed this
 documentation, and if applicable, the associated
-`official Doxygen documentation <http://symas.com/mdb/doc/>`_.
+`official Doxygen documentation <http://lmdb.tech/doc/>`_.
 
 If you have found a bug, please report it on the `GitHub issue tracker
 <https://github.com/dw/py-lmdb/issues>`_, or mail it to the list below if
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.1.0/lib/lmdb.h new/lmdb-1.2.1/lib/lmdb.h
--- old/lmdb-1.1.0/lib/lmdb.h   2021-02-04 23:00:08.000000000 +0100
+++ new/lmdb-1.2.1/lib/lmdb.h   2021-04-19 21:10:32.000000000 +0200
@@ -135,7 +135,7 @@
  *
  *     @author Howard Chu, Symas Corporation.
  *
- *     @copyright Copyright 2011-2020 Howard Chu, Symas Corp. All rights 
reserved.
+ *     @copyright Copyright 2011-2021 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      27
+#define MDB_VERSION_PATCH      29
 
 /** 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       "October 26, 2020"
+#define MDB_VERSION_DATE       "March 16, 2021"
 
 /** A stringifier for the version info */
 #define MDB_VERSTR(a,b,c,d)    "LMDB " #a "." #b "." #c ": (" d ")"
@@ -576,7 +576,7 @@
         *      <li>#MDB_NOTLS
         *              Don't use Thread-Local Storage. Tie reader locktable 
slots to
         *              #MDB_txn objects instead of to threads. I.e. 
#mdb_txn_reset() keeps
-        *              the slot reseved for the #MDB_txn object. A thread may 
use parallel
+        *              the slot reserved for the #MDB_txn object. A thread may 
use parallel
         *              read-only transactions. A read-only transaction may 
span threads if
         *              the user synchronizes its use. Applications that 
multiplex many
         *              user threads over individual OS threads need this 
option. Such an
@@ -928,7 +928,7 @@
 typedef void MDB_assert_func(MDB_env *env, const char *msg);
 
        /** Set or reset the assert() callback of the environment.
-        * Disabled if liblmdb is buillt with NDEBUG.
+        * Disabled if liblmdb is built with NDEBUG.
         * @note This hack should become obsolete as lmdb's error handling 
matures.
         * @param[in] env An environment handle returned by #mdb_env_create().
         * @param[in] func An #MDB_assert_func function, or 0.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.1.0/lib/mdb.c new/lmdb-1.2.1/lib/mdb.c
--- old/lmdb-1.1.0/lib/mdb.c    2021-02-04 23:00:08.000000000 +0100
+++ new/lmdb-1.2.1/lib/mdb.c    2021-04-19 21:10:32.000000000 +0200
@@ -5,7 +5,7 @@
  *     BerkeleyDB API, but much simplified.
  */
 /*
- * Copyright 2011-2020 Howard Chu, Symas Corp.
+ * Copyright 2011-2021 Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -493,7 +493,7 @@
         *      The string is printed literally, with no format processing.
         */
 #define DPUTS(arg)     DPRINTF(("%s", arg))
-       /** Debuging output value of a cursor DBI: Negative in a sub-cursor. */
+       /** Debugging output value of a cursor DBI: Negative in a sub-cursor. */
 #define DDBI(mc) \
        (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi)
 /** @} */
@@ -6597,7 +6597,7 @@
 
        dkey.mv_size = 0;
 
-       if (flags == MDB_CURRENT) {
+       if (flags & MDB_CURRENT) {
                if (!(mc->mc_flags & C_INITIALIZED))
                        return EINVAL;
                rc = MDB_SUCCESS;
@@ -6992,7 +6992,7 @@
                        xdata.mv_size = 0;
                        xdata.mv_data = "";
                        leaf = NODEPTR(mc->mc_pg[mc->mc_top], 
mc->mc_ki[mc->mc_top]);
-                       if (flags & MDB_CURRENT) {
+                       if ((flags & (MDB_CURRENT|MDB_APPENDDUP)) == 
MDB_CURRENT) {
                                xflags = MDB_CURRENT|MDB_NOSPILL;
                        } else {
                                mdb_xcursor_init1(mc, leaf);
@@ -8481,7 +8481,6 @@
                return rc;
        }
 
-       ki = mc->mc_ki[mc->mc_top];
        mp = mc->mc_pg[mc->mc_top];
        nkeys = NUMKEYS(mp);
 
@@ -8493,19 +8492,18 @@
                if (m3->mc_snum < mc->mc_snum)
                        continue;
                if (m3->mc_pg[mc->mc_top] == mp) {
+                       if (m3->mc_ki[mc->mc_top] >= mc->mc_ki[mc->mc_top]) {
                        /* if m3 points past last node in page, find next 
sibling */
-                       if (m3->mc_ki[mc->mc_top] >= nkeys) {
-                               rc = mdb_cursor_sibling(m3, 1);
-                               if (rc == MDB_NOTFOUND) {
-                                       m3->mc_flags |= C_EOF;
-                                       rc = MDB_SUCCESS;
-                                       continue;
+                               if (m3->mc_ki[mc->mc_top] >= nkeys) {
+                                       rc = mdb_cursor_sibling(m3, 1);
+                                       if (rc == MDB_NOTFOUND) {
+                                               m3->mc_flags |= C_EOF;
+                                               rc = MDB_SUCCESS;
+                                               continue;
+                                       }
+                                       if (rc)
+                                               goto fail;
                                }
-                               if (rc)
-                                       goto fail;
-                       }
-                       if (m3->mc_ki[mc->mc_top] >= ki ||
-                               /* moved to right sibling */ 
m3->mc_pg[mc->mc_top] != mp) {
                                if (m3->mc_xcursor && !(m3->mc_flags & C_EOF)) {
                                        MDB_node *node = 
NODEPTR(m3->mc_pg[m3->mc_top], m3->mc_ki[m3->mc_top]);
                                        /* If this node has dupdata, it may 
need to be reinited
@@ -8527,10 +8525,10 @@
                                        }
                                        m3->mc_xcursor->mx_cursor.mc_flags |= 
C_DEL;
                                }
-                               m3->mc_flags |= C_DEL;
                        }
                }
        }
+       mc->mc_flags |= C_DEL;
 
 fail:
        if (rc)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.1.0/lib/py-lmdb/env-copy-txn.patch 
new/lmdb-1.2.1/lib/py-lmdb/env-copy-txn.patch
--- old/lmdb-1.1.0/lib/py-lmdb/env-copy-txn.patch       2021-02-04 
23:00:08.000000000 +0100
+++ new/lmdb-1.2.1/lib/py-lmdb/env-copy-txn.patch       2021-04-19 
21:10:32.000000000 +0200
@@ -1,5 +1,5 @@
 diff --git a/libraries/liblmdb/lmdb.h b/libraries/liblmdb/lmdb.h
-index 361c93010..da6254819 100644
+index 69aa2751a2..ff7f77a10d 100644
 --- a/libraries/liblmdb/lmdb.h
 +++ b/libraries/liblmdb/lmdb.h
 @@ -682,9 +682,14 @@ int  mdb_env_copyfd(MDB_env *env, mdb_filehandle_t fd);
@@ -32,10 +32,10 @@
        /** @brief Return statistics about the LMDB environment.
         *
 diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c
-index b70a6a54d..0b382a721 100644
+index 8cecdb2e69..9ede4183dd 100644
 --- a/libraries/liblmdb/mdb.c
 +++ b/libraries/liblmdb/mdb.c
-@@ -9334,12 +9334,12 @@ done:
+@@ -9332,12 +9332,12 @@ done:
  
        /** Copy environment with compaction. */
  static int ESECT
@@ -50,7 +50,7 @@
        pthread_t thr;
        pgno_t root, new_root;
        int rc = MDB_SUCCESS;
-@@ -9385,9 +9385,11 @@ mdb_env_copyfd1(MDB_env *env, HANDLE fd)
+@@ -9383,9 +9383,11 @@ mdb_env_copyfd1(MDB_env *env, HANDLE fd)
        if (rc)
                goto done;
  
@@ -65,7 +65,7 @@
  
        mp = (MDB_page *)my.mc_wbuf[0];
        memset(mp, 0, NUM_METAS * env->me_psize);
-@@ -9447,7 +9449,8 @@ finish:
+@@ -9445,7 +9447,8 @@ finish:
                my.mc_error = rc;
        mdb_env_cthr_toggle(&my, 1 | MDB_EOF);
        rc = THREAD_FINISH(thr);
@@ -75,7 +75,7 @@
  
  done:
  #ifdef _WIN32
-@@ -9564,12 +9567,22 @@ leave:
+@@ -9562,12 +9565,22 @@ leave:
  }
  
  int ESECT
@@ -100,7 +100,7 @@
  }
  
  int ESECT
-@@ -9580,6 +9593,12 @@ mdb_env_copyfd(MDB_env *env, HANDLE fd)
+@@ -9578,6 +9591,12 @@ mdb_env_copyfd(MDB_env *env, HANDLE fd)
  
  int ESECT
  mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags)
@@ -113,7 +113,7 @@
  {
        int rc;
        MDB_name fname;
-@@ -9591,7 +9610,7 @@ mdb_env_copy2(MDB_env *env, const char *path, unsigned 
int flags)
+@@ -9589,7 +9608,7 @@ mdb_env_copy2(MDB_env *env, const char *path, unsigned 
int flags)
                mdb_fname_destroy(fname);
        }
        if (rc == MDB_SUCCESS) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.1.0/lmdb/__init__.py 
new/lmdb-1.2.1/lmdb/__init__.py
--- old/lmdb-1.1.0/lmdb/__init__.py     2021-02-04 23:00:08.000000000 +0100
+++ new/lmdb-1.2.1/lmdb/__init__.py     2021-04-19 21:10:32.000000000 +0200
@@ -50,4 +50,4 @@
     from lmdb.cffi import __all__
     from lmdb.cffi import __doc__
 
-__version__ = '1.1.0'
+__version__ = '1.2.1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.1.0/lmdb/cffi.py new/lmdb-1.2.1/lmdb/cffi.py
--- old/lmdb-1.1.0/lmdb/cffi.py 2021-02-04 23:00:08.000000000 +0100
+++ new/lmdb-1.2.1/lmdb/cffi.py 2021-04-19 21:10:32.000000000 +0200
@@ -42,13 +42,13 @@
 try:
     import __builtin__
 except ImportError:
-    import builtins as __builtin__
+    import builtins as __builtin__  # type: ignore
 
 import lmdb
 try:
     from lmdb import _config
 except ImportError:
-    _config = None
+    _config = None  # type: ignore
 
 
 __all__ = [
@@ -362,7 +362,7 @@
         'libraries': []
     }
 
-    _have_patched_lmdb = '-DHAVE_PATCHED_LMDB=1' in 
_config.CONFIG['extra_compile_args']
+    _have_patched_lmdb = '-DHAVE_PATCHED_LMDB=1' in 
_config.CONFIG['extra_compile_args']  # type: ignore
 
     if _have_patched_lmdb:
         _CFFI_CDEF += _CFFI_CDEF_PATCHED
@@ -370,13 +370,13 @@
     _ffi = cffi.FFI()
     _ffi.cdef(_CFFI_CDEF)
     _lib = _ffi.verify(_CFFI_VERIFY,
-        modulename='lmdb_cffi',
-        ext_package='lmdb',
-        sources=_config_vars['extra_sources'],
-        extra_compile_args=_config_vars['extra_compile_args'],
-        include_dirs=_config_vars['extra_include_dirs'],
-        libraries=_config_vars['libraries'],
-        library_dirs=_config_vars['extra_library_dirs'])
+                       modulename='lmdb_cffi',
+                       ext_package='lmdb',
+                       sources=_config_vars['extra_sources'],
+                       extra_compile_args=_config_vars['extra_compile_args'],
+                       include_dirs=_config_vars['extra_include_dirs'],
+                       libraries=_config_vars['libraries'],
+                       library_dirs=_config_vars['extra_library_dirs'])
 
     @_ffi.callback("int(char *, void *)")
     def _msg_func(s, _):
@@ -535,8 +535,10 @@
     """
     def __nonzero__(self):
         return 0
+
     def __bool__(self):
         return False
+
     def __repr__(self):
         return "<This used to be a LMDB resource but it was deleted or closed>"
 _invalid = Some_LMDB_Resource_That_Was_Deleted_Or_Closed()
@@ -595,7 +597,7 @@
     interpreter crash.
 
     Equivalent to `mdb_env_open()
-    
<http://symas.com/mdb/doc/group__mdb.html#ga1fe2740e25b1689dc412e7b9faadba1b>`_
+    <http://lmdb.tech/doc/group__mdb.html#ga1fe2740e25b1689dc412e7b9faadba1b>`_
 
         `path`:
             Location of directory (if `subdir=True`) or file prefix to store
@@ -712,10 +714,10 @@
             so that no readers may be active at all when a writer begins.
     """
     def __init__(self, path, map_size=10485760, subdir=True,
-            readonly=False, metasync=True, sync=True, map_async=False,
-            mode=O_0755, create=True, readahead=True, writemap=False,
-            meminit=True, max_readers=126, max_dbs=0, max_spare_txns=1,
-            lock=True):
+                 readonly=False, metasync=True, sync=True, map_async=False,
+                 mode=O_0755, create=True, readahead=True, writemap=False,
+                 meminit=True, max_readers=126, max_dbs=0, max_spare_txns=1,
+                 lock=True):
         self._max_spare_txns = max_spare_txns
         self._spare_txns = []
 
@@ -726,6 +728,7 @@
             raise _error("mdb_env_create", rc)
         self._env = envpp[0]
         self._deps = set()
+        self._creating_db_in_readonly = False
 
         self.set_mapsize(map_size)
 
@@ -809,7 +812,18 @@
             The new size in bytes.
 
         Equivalent to `mdb_env_set_mapsize()
-        
<http://symas.com/mdb/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5>`_
+        
<http://lmdb.tech/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5>`_
+
+        Warning:
+        There's a data race in the underlying library that may cause
+        catastrophic loss of data if you use this method.
+
+        You are safe if one of the following are true:
+            * Only one process accessing a particular LMDB file ever calls
+              this method.
+
+            * You use locking external to this library to ensure that only one
+              process accessing the current LMDB file can be inside this 
function.
         """
         rc = _lib.mdb_env_set_mapsize(self._env, map_size)
         if rc:
@@ -820,7 +834,7 @@
         transactions. Repeat calls to :py:meth:`close` have no effect.
 
         Equivalent to `mdb_env_close()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga4366c43ada8874588b6a62fbda2d1e95>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga4366c43ada8874588b6a62fbda2d1e95>`_
         """
         if self._env:
             if self._deps:
@@ -846,7 +860,7 @@
         stored.
 
         Equivalent to `mdb_env_get_path()
-        
<http://symas.com/mdb/doc/group__mdb.html#gac699fdd8c4f8013577cb933fb6a757fe>`_
+        
<http://lmdb.tech/doc/group__mdb.html#gac699fdd8c4f8013577cb933fb6a757fe>`_
         """
         path = _ffi.new('char **')
         rc = _lib.mdb_env_get_path(self._env, path)
@@ -872,7 +886,7 @@
             this parameter may be set only if compact=True.
 
         Equivalent to `mdb_env_copy2() or mdb_env_copy3()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga5d51d6130325f7353db0955dbedbc378>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga5d51d6130325f7353db0955dbedbc378>`_
         """
         flags = _lib.MDB_CP_COMPACT if compact else 0
         if txn and not _have_patched_lmdb:
@@ -908,7 +922,7 @@
             is not available if the module was built with LMDB_PURE.
 
         Equivalent to `mdb_env_copyfd2() or mdb_env_copyfd3
-        
<http://symas.com/mdb/doc/group__mdb.html#ga5d51d6130325f7353db0955dbedbc378>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga5d51d6130325f7353db0955dbedbc378>`_
         """
         if txn and not _have_patched_lmdb:
             raise TypeError("Non-patched LMDB doesn't support transaction with 
env.copy")
@@ -933,7 +947,7 @@
         """Flush the data buffers to disk.
 
         Equivalent to `mdb_env_sync()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga85e61f05aa68b520cc6c3b981dba5037>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga85e61f05aa68b520cc6c3b981dba5037>`_
 
         Data is always written to disk when :py:meth:`Transaction.commit` is
         called, but the operating system may keep it buffered. MDB always
@@ -981,7 +995,7 @@
         +--------------------+---------------------------------------+
 
         Equivalent to `mdb_env_stat()
-        
<http://symas.com/mdb/doc/group__mdb.html#gaf881dca452050efbd434cd16e4bae255>`_
+        
<http://lmdb.tech/doc/group__mdb.html#gaf881dca452050efbd434cd16e4bae255>`_
         """
         st = _ffi.new('MDB_stat *')
         rc = _lib.mdb_env_stat(self._env, st)
@@ -1012,7 +1026,7 @@
         +--------------------+---------------------------------------------+
 
         Equivalent to `mdb_env_info()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga18769362c7e7d6cf91889a028a5c5947>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga18769362c7e7d6cf91889a028a5c5947>`_
         """
         info = _ffi.new('MDB_envinfo *')
         rc = _lib.mdb_env_info(self._env, info)
@@ -1044,7 +1058,7 @@
             'readahead': not (flags & _lib.MDB_NORDAHEAD),
             'writemap': bool(flags & _lib.MDB_WRITEMAP),
             'meminit': not (flags & _lib.MDB_NOMEMINIT),
-            'lock':  not (flags & _lib.MDB_NOLOCK),
+            'lock': not (flags & _lib.MDB_NOLOCK),
         }
 
     def max_key_size(self):
@@ -1094,7 +1108,7 @@
         same handle. As a special case, the main database is always open.
 
         Equivalent to `mdb_dbi_open()
-        
<http://symas.com/mdb/doc/group__mdb.html#gac08cad5b096925642ca359a6d6f0562a>`_
+        
<http://lmdb.tech/doc/group__mdb.html#gac08cad5b096925642ca359a6d6f0562a>`_
 
         Named databases are implemented by *storing a special descriptor in the
         main database*. All databases in an environment *share the same file*.
@@ -1199,9 +1213,13 @@
             db = _Database(self, txn, key, reverse_key, dupsort, create,
                            integerkey, integerdup, dupfixed)
         else:
-            with self.begin(write=not self.readonly) as txn:
-                db = _Database(self, txn, key, reverse_key, dupsort, create,
-                               integerkey, integerdup, dupfixed)
+            try:
+                self._creating_db_in_readonly = True
+                with self.begin(write=not self.readonly) as txn:
+                    db = _Database(self, txn, key, reverse_key, dupsort, 
create,
+                                   integerkey, integerdup, dupfixed)
+            finally:
+                self._creating_db_in_readonly = False
         self._dbs[key] = db
         return db
 
@@ -1291,7 +1309,7 @@
                 txn.put('a', 'b')
 
     Equivalent to `mdb_txn_begin()
-    
<http://symas.com/mdb/doc/group__mdb.html#gad7ea55da06b77513609efebd44b26920>`_
+    <http://lmdb.tech/doc/group__mdb.html#gad7ea55da06b77513609efebd44b26920>`_
 
         `env`:
             Environment the transaction should be on.
@@ -1362,11 +1380,17 @@
             self._write = True
         else:
             try:  # Exception catch in order to avoid racy 'if txns:' test
+                if env._creating_db_in_readonly:  # Don't use spare txns for 
creating a DB when read-only
+                    raise IndexError
                 self._txn = env._spare_txns.pop()
                 env._max_spare_txns += 1
                 rc = _lib.mdb_txn_renew(self._txn)
                 if rc:
+                    while self._deps:
+                        self._deps.pop()._invalidate()
                     _lib.mdb_txn_abort(self._txn)
+                    self._txn = _invalid
+                    self._invalidate()
                     raise _error("mdb_txn_renew", rc)
             except IndexError:
                 txnpp = _ffi.new('MDB_txn **')
@@ -1424,7 +1448,7 @@
         unavailable, and invalidates existing cursors.
 
         Equivalent to `mdb_drop()
-        
<http://symas.com/mdb/doc/group__mdb.html#gab966fab3840fc54a6571dfb32b00f2db>`_
+        
<http://lmdb.tech/doc/group__mdb.html#gab966fab3840fc54a6571dfb32b00f2db>`_
         """
         while db._deps:
             db._deps.pop()._invalidate()
@@ -1449,11 +1473,13 @@
             self._invalidate()
             return True
 
+        return False
+
     def commit(self):
         """Commit the pending transaction.
 
         Equivalent to `mdb_txn_commit()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga846fbd6f46105617ac9f4d76476f6597>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga846fbd6f46105617ac9f4d76476f6597>`_
         """
         while self._deps:
             self._deps.pop()._invalidate()
@@ -1471,7 +1497,7 @@
         been closed.
 
         Equivalent to `mdb_txn_abort()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga73a5938ae4c3239ee11efa07eb22b882>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga73a5938ae4c3239ee11efa07eb22b882>`_
         """
         if self._txn:
             while self._deps:
@@ -1489,7 +1515,7 @@
         a `dupsort=True` database.
 
         Equivalent to `mdb_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga8bf10cd91d3f3a83a34d04ce6b07992d>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga8bf10cd91d3f3a83a34d04ce6b07992d>`_
         """
         rc = _lib.pymdb_get(self._txn, (db or self._db)._dbi,
                             key, len(key), self._val)
@@ -1508,7 +1534,7 @@
         On success, the cursor is positioned on the new record.
 
         Equivalent to `mdb_put()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga4fa8573d9236d54687c61827ebf8cac0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga4fa8573d9236d54687c61827ebf8cac0>`_
 
             `key`:
                 Bytestring key to store.
@@ -1576,7 +1602,7 @@
         """Delete a key from the database.
 
         Equivalent to `mdb_del()
-        
<http://symas.com/mdb/doc/group__mdb.html#gab8182f9360ea69ac0afd4a4eaab1ddb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#gab8182f9360ea69ac0afd4a4eaab1ddb0>`_
 
             `key`:
                 The key to delete.
@@ -1588,6 +1614,9 @@
 
         Returns True if at least one key was deleted.
         """
+        if value is None:  # for bug-compatibility with cpython impl
+            value = EMPTY_BYTES
+
         rc = _lib.pymdb_del(self._txn, (db or self._db)._dbi,
                             key, len(key), value, len(value))
         self._mutations += 1
@@ -1607,7 +1636,7 @@
     Structure for navigating a database.
 
     Equivalent to `mdb_cursor_open()
-    
<http://symas.com/mdb/doc/group__mdb.html#ga9ff5d7bd42557fd5ee235dc1d62613aa>`_
+    <http://lmdb.tech/doc/group__mdb.html#ga9ff5d7bd42557fd5ee235dc1d62613aa>`_
 
         `db`:
             :py:class:`_Database` to navigate.
@@ -1905,9 +1934,9 @@
         duplicates, the cursor is positioned on the first value ("duplicate").
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_FIRST
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get(_lib.MDB_FIRST)
 
@@ -1918,9 +1947,9 @@
         Only meaningful for databases opened with `dupsort=True`.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_FIRST_DUP
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get(_lib.MDB_FIRST_DUP)
 
@@ -1932,9 +1961,9 @@
         duplicates, the cursor is positioned on the last value ("duplicate").
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_LAST
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get(_lib.MDB_LAST)
 
@@ -1945,9 +1974,9 @@
         Only meaningful for databases opened with `dupsort=True`.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_LAST_DUP
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get(_lib.MDB_LAST_DUP)
 
@@ -1960,9 +1989,9 @@
         to the previous key.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_PREV
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get(_lib.MDB_PREV)
 
@@ -1974,9 +2003,9 @@
         Only meaningful for databases opened with `dupsort=True`.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_PREV_DUP
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get(_lib.MDB_PREV_DUP)
 
@@ -1987,9 +2016,9 @@
         Only meaningful for databases opened with `dupsort=True`.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_PREV_NODUP
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get(_lib.MDB_PREV_NODUP)
 
@@ -2002,9 +2031,9 @@
         first value of the next key.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_NEXT
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get(_lib.MDB_NEXT)
 
@@ -2015,9 +2044,9 @@
         Only meaningful for databases opened with `dupsort=True`.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_NEXT_DUP
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get(_lib.MDB_NEXT_DUP)
 
@@ -2028,9 +2057,9 @@
         Only meaningful for databases opened with `dupsort=True`.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_NEXT_NODUP
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get(_lib.MDB_NEXT_NODUP)
 
@@ -2043,9 +2072,9 @@
         ("duplicate") for the key.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_SET_KEY
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get_kv(_lib.MDB_SET_KEY, key, EMPTY_BYTES)
 
@@ -2057,9 +2086,9 @@
         Only meaningful for databases opened with `dupsort=True`.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_GET_BOTH
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         return self._cursor_get_kv(_lib.MDB_GET_BOTH, key, value)
 
@@ -2118,7 +2147,7 @@
             next_op = _lib.MDB_NEXT_DUP
 
         a = bytearray()
-        l = list()
+        lst = list()
         for key in keys:
             if self.set_key(key):
                 while self._valid:
@@ -2129,16 +2158,16 @@
 
                     if dupfixed_bytes:
                         gen = (
-                            (key, val[i:i+dupfixed_bytes])
+                            (key, val[i:i + dupfixed_bytes])
                             for i in range(0, len(val), dupfixed_bytes))
                         if keyfixed:
                             for k, v in gen:
                                 a.extend(k + v)
                         else:
                             for k, v in gen:
-                                l.append((k, v))
+                                lst.append((k, v))
                     else:
-                        l.append((key, val))
+                        lst.append((key, val))
 
                     if dupdata:
                         self._cursor_get(next_op)
@@ -2148,7 +2177,7 @@
         if keyfixed:
             return memoryview(a)
         else:
-            return l
+            return lst
 
     def set_range(self, key):
         """Seek to the first key greater than or equal to `key`, returning
@@ -2160,9 +2189,9 @@
         ("duplicate") for the key.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_SET_RANGE
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         if not key:
             return self.first()
@@ -2176,9 +2205,9 @@
         Only meaningful for databases opened with `dupsort=True`.
 
         Equivalent to `mdb_cursor_get()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0>`_
         with `MDB_GET_BOTH_RANGE
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1206b2af8b95e7f6b0ef6b28708c9127>`_
         """
         rc = self._cursor_get_kv(_lib.MDB_GET_BOTH_RANGE, key, value)
         # issue #126: MDB_GET_BOTH_RANGE does not satisfy its documentation,
@@ -2196,7 +2225,7 @@
         meaningful for databases opened with `dupsort=True`.
 
         Equivalent to `mdb_cursor_del()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga26a52d3efcfd72e5bf6bd6960bf75f95>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga26a52d3efcfd72e5bf6bd6960bf75f95>`_
         """
         v = self._valid
         if v:
@@ -2215,7 +2244,7 @@
         Only meaningful for databases opened with `dupsort=True`.
 
         Equivalent to `mdb_cursor_count()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga4041fd1e1862c6b7d5f10590b86ffbe2>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga4041fd1e1862c6b7d5f10590b86ffbe2>`_
         """
         countp = _ffi.new('size_t *')
         rc = _lib.mdb_cursor_count(self._cur, countp)
@@ -2229,7 +2258,7 @@
         success, the cursor is positioned on the key.
 
         Equivalent to `mdb_cursor_put()
-        
<http://symas.com/mdb/doc/group__mdb.html#ga1f83ccb40011837ff37cc32be01ad91e>`_
+        
<http://lmdb.tech/doc/group__mdb.html#ga1f83ccb40011837ff37cc32be01ad91e>`_
 
             `key`:
                 Bytestring key to store.
@@ -2260,7 +2289,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
 
         rc = _lib.pymdb_cursor_put(self._cur, key, len(key), val, len(val), 
flags)
         self.txn._mutations += 1
@@ -2325,7 +2357,7 @@
                 else:
                     raise _error("mdb_cursor_put", rc)
         self._cursor_get(_lib.MDB_GET_CURRENT)
-        return added, added-skipped
+        return added, added - skipped
 
     def replace(self, key, val):
         """Store a record, returning its previous value if one existed. Returns
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.1.0/lmdb/cpython.c 
new/lmdb-1.2.1/lmdb/cpython.c
--- old/lmdb-1.1.0/lmdb/cpython.c       2021-02-04 23:00:08.000000000 +0100
+++ new/lmdb-1.2.1/lmdb/cpython.c       2021-04-19 21:10:32.000000000 +0200
@@ -2586,7 +2586,7 @@
         flags |= MDB_NOOVERWRITE;
     }
     if(arg.append) {
-        flags |= MDB_APPEND;
+        flags |= (self->trans->db->flags & MDB_DUPSORT) ? MDB_APPENDDUP : 
MDB_APPEND;
     }
 
     UNLOCKED(rc, mdb_cursor_put(self->curs, &arg.key, &arg.val, flags));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.1.0/lmdb.egg-info/PKG-INFO 
new/lmdb-1.2.1/lmdb.egg-info/PKG-INFO
--- old/lmdb-1.1.0/lmdb.egg-info/PKG-INFO       2021-02-04 23:00:14.000000000 
+0100
+++ new/lmdb-1.2.1/lmdb.egg-info/PKG-INFO       2021-04-19 21:10:48.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: lmdb
-Version: 1.1.0
+Version: 1.2.1
 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-1.1.0/tests/crash_test.py 
new/lmdb-1.2.1/tests/crash_test.py
--- old/lmdb-1.1.0/tests/crash_test.py  2021-02-04 23:00:08.000000000 +0100
+++ new/lmdb-1.2.1/tests/crash_test.py  2021-04-19 21:10:32.000000000 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright 2013 The py-lmdb authors, all rights reserved.
+# Copyright 2013-2021 The py-lmdb authors, all rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted only as authorized by the OpenLDAP
@@ -32,9 +32,11 @@
 from __future__ import absolute_import
 from __future__ import with_statement
 
+import sys
 import itertools
 import random
 import unittest
+import multiprocessing
 
 import lmdb
 import testlib
@@ -278,5 +280,40 @@
         txn2 = env.begin(write=False)
         self.assertRaises(lmdb.InvalidParameterError, txn2.cursor, db=db)
 
+if sys.version_info[:2] >= (3, 4):
+    class MapResizeTest(unittest.TestCase):
+        def tearDown(self):
+            testlib.cleanup()
+
+        @staticmethod
+        def do_resize(path):
+            '''
+            Increase map size and fill up database, making sure that the root 
page is no longer
+            accessible in the main process.
+            '''
+            data = [i.to_bytes(4, 'little') for i in range(400)]
+            with lmdb.open(path, max_dbs=10, create=False, map_size=32000) as 
env:
+                env.open_db(b'foo')
+                env.set_mapsize(64000)
+                with env.begin(write=True) as txn:
+                    for datum in data:
+                        txn.put(datum, b'0')
+
+        def test_opendb_resize(self):
+            '''
+            Test that we correctly handle a MDB_MAP_RESIZED in env.open_db.
+
+            Would seg fault in cffi implementation
+            '''
+            mpctx = multiprocessing.get_context('spawn')
+            path, env = testlib.temp_env(max_dbs=10, map_size=32000)
+            env.close()
+            env = lmdb.open(path, max_dbs=10, map_size=32000, readonly=True)
+            proc = mpctx.Process(target=self.do_resize, args=(path,))
+            proc.start()
+            proc.join(5)
+            assert proc.exitcode is not None
+            self.assertRaises(lmdb.MapResizedError, env.open_db, b'foo')
+
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.1.0/tests/cursor_test.py 
new/lmdb-1.2.1/tests/cursor_test.py
--- old/lmdb-1.1.0/tests/cursor_test.py 2021-02-04 23:00:08.000000000 +0100
+++ new/lmdb-1.2.1/tests/cursor_test.py 2021-04-19 21:10:32.000000000 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright 2013 The py-lmdb authors, all rights reserved.
+# Copyright 2013-2021 The py-lmdb authors, all rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted only as authorized by the OpenLDAP
@@ -27,6 +27,8 @@
 import sys
 import unittest
 
+import lmdb
+
 import testlib
 from testlib import B
 from testlib import BT
@@ -140,6 +142,25 @@
     def testPut(self):
         pass
 
+class CursorTest2(unittest.TestCase):
+    def tearDown(self):
+        testlib.cleanup()
+
+    def setUp(self):
+        self.path, self.env = testlib.temp_env()
+        self.db = self.env.open_db(b'foo', dupsort=True)
+        self.txn = self.env.begin(write=True, db=self.db)
+        self.c = self.txn.cursor()
+
+    def testIterWithDeletes(self):
+        ''' A problem identified in LMDB 0.9.27 '''
+        self.c.put(b'\x00\x01', b'hehe', dupdata=True)
+        self.c.put(b'\x00\x02', b'haha', dupdata=True)
+        self.c.set_key(b'\x00\x02')
+        it = self.c.iternext()
+        self.assertEqual((b'\x00\x02', b'haha'), next(it))
+        self.txn.delete(b'\x00\x01', b'hehe', db=self.db)
+        self.assertRaises(StopIteration, next, it)
 
 class PutmultiTest(CursorTestBase):
     def test_empty_seq(self):
@@ -171,7 +192,7 @@
 
     def test_bad_seq1(self):
         self.assertRaises(Exception,
-             lambda: self.c.putmulti(range(2)))
+                          lambda: self.c.putmulti(range(2)))
 
     def test_dupsort(self):
         _, env = testlib.temp_env()
@@ -181,7 +202,7 @@
             tups = [BT('a', 'value1'), BT('b', 'value1'), BT('b', 'value2')]
             assert (3, 3) == c.putmulti(tups)
 
-    def test_dupsort_append(self):
+    def test_dupsort_putmulti_append(self):
         _, env = testlib.temp_env()
         db1 = env.open_db(B('db1'), dupsort=True)
         txn = env.begin(write=True, db=db1)
@@ -189,6 +210,15 @@
             tups = [BT('a', 'value1'), BT('b', 'value1'), BT('b', 'value2')]
             assert (3, 3) == c.putmulti(tups, append=True)
 
+    def test_dupsort_put_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:
+            assert c.put(B('a'), B('value1'), append=True)
+            assert c.put(B('b'), B('value1'), append=True)
+            assert c.put(B('b'), B('value2'), append=True)
+
 class ReplaceTest(CursorTestBase):
     def test_replace(self):
         assert None is self.c.replace(B('a'), B(''))
@@ -280,5 +310,22 @@
         # Getting the value does prefault the data, even if we only get it by 
pointer
         assert minflts_after_value - minflts_after_key > 1000
 
+class CursorReadOnlyTest(unittest.TestCase):
+    def tearDown(self):
+        testlib.cleanup()
+
+    def test_cursor_readonly(self):
+        '''
+        Tests whether you can open a cursor on a sub-db at all in a read-only 
environment.
+        '''
+        path, env = testlib.temp_env(max_dbs=10)
+        env.open_db(b'foo')
+        env.close()
+        with lmdb.open(path, max_dbs=10, readonly=True) as env:
+            db2 = env.open_db(b'foo')
+            with env.begin(db=db2) as txn:
+                with txn.cursor(db=db2):
+                    pass
+
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.1.0/tests/txn_test.py 
new/lmdb-1.2.1/tests/txn_test.py
--- old/lmdb-1.1.0/tests/txn_test.py    2021-02-04 23:00:08.000000000 +0100
+++ new/lmdb-1.2.1/tests/txn_test.py    2021-04-19 21:10:32.000000000 +0200
@@ -520,13 +520,24 @@
         _, env = testlib.temp_env()
         db = env.open_db(B('db1'), dupsort=True)
         txn = env.begin(write=True, db=db)
-        assert None == txn.replace(B('a'), B('x'))
+        assert None is txn.replace(B('a'), B('x'))
         assert B('x') == txn.replace(B('a'), B('y'))
         assert B('y') == txn.replace(B('a'), B('z'))
         cur = txn.cursor()
         assert cur.set_key(B('a'))
         assert [B('z')] == list(cur.iternext_dup())
 
+    def test_dupsort_del_none(self):
+        _, env = testlib.temp_env()
+        db = env.open_db(B('db1'), dupsort=True)
+        with env.begin(write=True, db=db) as txn:
+            assert txn.put(B('a'), B('a'))
+            assert txn.put(B('a'), B('b'))
+            cur = txn.cursor()
+            assert cur.set_key(B('a'))
+            assert [B('a'), B('b')] == list(cur.iternext_dup())
+            assert txn.delete(B('a'), None)
+
     def test_dupdata_no_dupsort(self):
         _, env = testlib.temp_env()
         txn = env.begin(write=True)

Reply via email to