Hello community,

here is the log from the commit of package python-pytools for openSUSE:Factory 
checked in at 2018-04-19 15:27:15
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pytools (Old)
 and      /work/SRC/openSUSE:Factory/.python-pytools.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pytools"

Thu Apr 19 15:27:15 2018 rev:4 rq:593929 version:2018.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pytools/python-pytools.changes    
2017-10-18 10:54:17.878131936 +0200
+++ /work/SRC/openSUSE:Factory/.python-pytools.new/python-pytools.changes       
2018-04-19 15:27:16.608477039 +0200
@@ -1,0 +2,6 @@
+Fri Apr  6 08:49:05 UTC 2018 - [email protected]
+
+- Update to version 2018.2
+  * No changelog available
+
+-------------------------------------------------------------------
@@ -4 +10 @@
-- Update to version 17.6
+- Update to version 2017.6

Old:
----
  pytools-2017.6.tar.gz

New:
----
  pytools-2018.3.tar.gz

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

Other differences:
------------------
++++++ python-pytools.spec ++++++
--- /var/tmp/diff_new_pack.BVQTox/_old  2018-04-19 15:27:17.208452582 +0200
+++ /var/tmp/diff_new_pack.BVQTox/_new  2018-04-19 15:27:17.208452582 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-pytools
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,20 +18,20 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-pytools
-Version:        2017.6
+Version:        2018.3
 Release:        0
 Summary:        A collection of tools for Python
 License:        MIT
 Group:          Development/Languages/Python
-Url:            https://pypi.python.org/pypi/pytools
+URL:            https://pypi.python.org/pypi/pytools
 Source0:        
https://files.pythonhosted.org/packages/source/p/pytools/pytools-%{version}.tar.gz
-BuildRequires:  %{python_module appdirs}
+BuildRequires:  %{python_module appdirs} >= 1.4.0
 BuildRequires:  %{python_module base}
-BuildRequires:  %{python_module decorator}
+BuildRequires:  %{python_module decorator} >= 3.2.0
 BuildRequires:  %{python_module devel}
-BuildRequires:  %{python_module numpy}
+BuildRequires:  %{python_module numpy} >= 1.6.0
 BuildRequires:  %{python_module setuptools}
-BuildRequires:  %{python_module six}
+BuildRequires:  %{python_module six} >= 1.8.0
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 BuildArch:      noarch
@@ -64,8 +64,8 @@
 python2 setup.py test
 
 %files %{python_files}
-%defattr(-,root,root,-)
-%doc README.rst LICENSE
+%license LICENSE
+%doc README.rst
 %{python_sitelib}/*
 
 %changelog

++++++ pytools-2017.6.tar.gz -> pytools-2018.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/PKG-INFO new/pytools-2018.3/PKG-INFO
--- old/pytools-2017.6/PKG-INFO 2017-09-26 02:09:29.000000000 +0200
+++ new/pytools-2018.3/PKG-INFO 2018-03-16 21:26:58.000000000 +0100
@@ -1,11 +1,12 @@
 Metadata-Version: 1.1
 Name: pytools
-Version: 2017.6
+Version: 2018.3
 Summary: A collection of tools for Python
 Home-page: http://pypi.python.org/pypi/pytools
 Author: Andreas Kloeckner
 Author-email: [email protected]
 License: MIT
+Description-Content-Type: UNKNOWN
 Description: Pytools is a big bag of things that are "missing" from the Python 
standard
         library. This is mainly a dependency of my other software packages, 
and is
         probably of little interest to you unless you use those. If you're 
curious
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/pytools/__init__.py 
new/pytools-2018.3/pytools/__init__.py
--- old/pytools-2017.6/pytools/__init__.py      2017-09-25 05:04:33.000000000 
+0200
+++ new/pytools-2018.3/pytools/__init__.py      2018-03-11 08:49:36.000000000 
+0100
@@ -1466,7 +1466,7 @@
             bin_nr = bisect(bin_starts, value)-1
             try:
                 bins[bin_nr] += 1
-            except:
+            except Exception:
                 print(value, bin_nr, bin_starts)
                 raise
 
@@ -1855,10 +1855,9 @@
 
 
 def generate_numbered_unique_names(prefix, num=None):
-    orig_num = num
-    num = 0
-    if orig_num is None:
-        yield (num, prefix)
+    if num is None:
+        yield (0, prefix)
+        num = 0
 
     while True:
         name = "%s_%d" % (prefix, num)
@@ -1940,7 +1939,17 @@
         sys.setrecursionlimit(new_limit)
 
     def __exit__(self, exc_type, exc_val, exc_tb):
-        sys.setrecursionlimit(self.prev_recursion_limit)
+        # Deep recursion can produce deeply nested data structures
+        # (or long chains of to-be gc'd generators) that cannot be
+        # undergo garbage collection with a lower recursion limit.
+        #
+        # As a result, it doesn't seem possible to lower the recursion limit
+        # again after it has been raised without causing reliability issues.
+        #
+        # See https://gitlab.tiker.net/inducer/sumpy/issues/31 for
+        # context.
+
+        pass
 
 # }}}
 
@@ -1966,6 +1975,63 @@
 
 # }}}
 
+
+# {{{ find git revisions
+
+def find_git_revision(tree_root):
+    # Keep this routine self-contained so that it can be copy-pasted into
+    # setup.py.
+
+    from os.path import join, exists, abspath
+    tree_root = abspath(tree_root)
+
+    if not exists(join(tree_root, ".git")):
+        return None
+
+    # construct minimal environment
+    # stolen from
+    # 
https://github.com/numpy/numpy/blob/055ce3e90b50b5f9ef8cf1b8641c42e391f10735/setup.py#L70-L92
+    import os
+    env = {}
+    for k in ['SYSTEMROOT', 'PATH', 'HOME']:
+        v = os.environ.get(k)
+        if v is not None:
+            env[k] = v
+    # LANGUAGE is used on win32
+    env['LANGUAGE'] = 'C'
+    env['LANG'] = 'C'
+    env['LC_ALL'] = 'C'
+
+    from subprocess import Popen, PIPE, STDOUT
+    p = Popen(["git", "rev-parse", "HEAD"], shell=False,
+              stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True,
+              cwd=tree_root, env=env)
+    (git_rev, _) = p.communicate()
+
+    import sys
+    if sys.version_info >= (3,):
+        git_rev = git_rev.decode()
+
+    git_rev = git_rev.rstrip()
+
+    retcode = p.returncode
+    assert retcode is not None
+    if retcode != 0:
+        from warnings import warn
+        warn("unable to find git revision")
+        return None
+
+    return git_rev
+
+
+def find_module_git_revision(module_file, n_levels_up):
+    from os.path import dirname, join
+    tree_root = join(*([dirname(module_file)] + [".." * n_levels_up]))
+
+    return find_git_revision(tree_root)
+
+# }}}
+
 
 def _test():
     import doctest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/pytools/debug.py 
new/pytools-2018.3/pytools/debug.py
--- old/pytools-2017.6/pytools/debug.py 2016-12-06 02:09:53.000000000 +0100
+++ new/pytools-2018.3/pytools/debug.py 2017-10-29 13:17:25.000000000 +0100
@@ -122,7 +122,7 @@
                     expr_str = input()
                     try:
                         res = eval(expr_str, {"obj": r})
-                    except:
+                    except Exception:
                         from traceback import print_exc
                         print_exc()
                     print(res)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/pytools/importlib_backport.py 
new/pytools-2018.3/pytools/importlib_backport.py
--- old/pytools-2017.6/pytools/importlib_backport.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/pytools-2018.3/pytools/importlib_backport.py    2018-03-16 
21:25:30.000000000 +0100
@@ -0,0 +1,94 @@
+"""Backport of importlib.import_module from 3.x.
+
+Downloaded from: https://github.com/sprintly/importlib
+
+This code is based in the implementation of importlib.import_module()
+in Python 2.7. The license is below.
+
+========================================================================
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+("PSF"), and the Individual or Organization ("Licensee") accessing and
+otherwise using this software ("Python") in source or binary form and
+its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python
+alone or in any derivative version, provided, however, that PSF's
+License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
+2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation; All Rights
+Reserved" are retained in Python alone or in any derivative version
+prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python.
+
+4. PSF is making Python available to Licensee on an "AS IS"
+basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee. This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+"""
+
+# While not critical (and in no way guaranteed!), it would be nice to keep this
+# code compatible with Python 2.3.
+import sys
+import six
+
+
+def _resolve_name(name, package, level):
+    """Return the absolute name of the module to be imported."""
+    if not hasattr(package, 'rindex'):
+        raise ValueError("'package' not set to a string")
+    dot = len(package)
+    for x in six.moves.xrange(level, 1, -1):
+        try:
+            dot = package.rindex('.', 0, dot)
+        except ValueError:
+            raise ValueError("attempted relative import beyond top-level "
+                              "package")
+    return "%s.%s" % (package[:dot], name)
+
+
+def import_module(name, package=None):
+    """Import a module.
+    The 'package' argument is required when performing a relative import. It
+    specifies the package to use as the anchor point from which to resolve the
+    relative import to an absolute import.
+    """
+    if name.startswith('.'):
+        if not package:
+            raise TypeError("relative imports require the 'package' argument")
+        level = 0
+        for character in name:
+            if character != '.':
+                break
+            level += 1
+        name = _resolve_name(name[level:], package, level)
+    __import__(name)
+    return sys.modules[name]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/pytools/log.py 
new/pytools-2018.3/pytools/log.py
--- old/pytools-2017.6/pytools/log.py   2016-12-06 02:09:53.000000000 +0100
+++ new/pytools-2018.3/pytools/log.py   2017-10-29 13:16:10.000000000 +0100
@@ -558,7 +558,7 @@
         try:
             self.db_conn.execute("insert into %s values (?,?,?)" % name,
                     (self.tick_count, self.rank, float(value)))
-        except:
+        except Exception:
             print("while adding datapoint for '%s':" % name)
             raise
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/pytools/persistent_dict.py 
new/pytools-2018.3/pytools/persistent_dict.py
--- old/pytools-2017.6/pytools/persistent_dict.py       2017-09-26 
02:09:20.000000000 +0200
+++ new/pytools-2018.3/pytools/persistent_dict.py       2017-11-22 
04:13:02.000000000 +0100
@@ -32,6 +32,7 @@
 
 
 import collections
+import functools
 import six
 import sys
 import os
@@ -39,15 +40,19 @@
 import errno
 
 __doc__ = """
-Persistent Hashing
-==================
+Persistent Hashing and Persistent Dictionaries
+==============================================
 
 This module contains functionality that allows hashing with keys that remain
 valid across interpreter invocations, unlike Python's built-in hashes.
 
+This module also provides a disk-backed dictionary that uses persistent 
hashing.
+
 .. autoexception:: NoSuchEntryError
 .. autoexception:: ReadOnlyEntryError
 
+.. autoexception:: CollisionWarning
+
 .. autoclass:: KeyBuilder
 .. autoclass:: PersistentDict
 .. autoclass:: WriteOncePersistentDict
@@ -78,6 +83,37 @@
         checksum.update(obj)
 
 
+def _tracks_stacklevel(cls, exclude=frozenset(["__init__"])):
+    """Changes all the methods of `cls` to track the call stack level in a 
member
+    called `_stacklevel`.
+    """
+    def make_wrapper(f):
+        @functools.wraps(f)
+        def wrapper(obj, *args, **kwargs):
+            assert obj._stacklevel >= 0, obj._stacklevel
+            # Increment by 2 because the method is wrapped.
+            obj._stacklevel += 2
+            try:
+                return f(obj, *args, **kwargs)
+            finally:
+                obj._stacklevel -= 2
+
+        return wrapper
+
+    for member in cls.__dict__:
+        f = getattr(cls, member)
+
+        if member in exclude:
+            continue
+
+        if not six.callable(f):
+            continue
+
+        setattr(cls, member, make_wrapper(f))
+
+    return cls
+
+
 # {{{ cleanup managers
 
 class CleanupBase(object):
@@ -101,7 +137,7 @@
 
 
 class LockManager(CleanupBase):
-    def __init__(self, cleanup_m, lock_file):
+    def __init__(self, cleanup_m, lock_file, _stacklevel=1):
         self.lock_file = lock_file
 
         attempts = 0
@@ -121,7 +157,8 @@
             if attempts > 10:
                 from warnings import warn
                 warn("could not obtain lock--delete '%s' if necessary"
-                        % self.lock_file)
+                        % self.lock_file,
+                     stacklevel=1 + _stacklevel)
             if attempts > 3 * 60:
                 raise RuntimeError("waited more than three minutes "
                         "on the lock file '%s'"
@@ -395,8 +432,16 @@
     pass
 
 
+class CollisionWarning(UserWarning):
+    pass
+
+
+@_tracks_stacklevel
 class _PersistentDictBase(object):
     def __init__(self, identifier, key_builder=None, container_dir=None):
+        # for issuing warnings
+        self._stacklevel = 0
+
         self.identifier = identifier
 
         if key_builder is None:
@@ -417,6 +462,10 @@
 
         self._make_container_dir()
 
+    def _warn(self, msg, category=UserWarning):
+        from warnings import warn
+        warn(msg, category, stacklevel=1 + self._stacklevel)
+
     def store_if_not_present(self, key, value):
         self.store(key, value, _skip_if_present=True)
 
@@ -458,13 +507,16 @@
     def _collision_check(self, key, stored_key):
         if stored_key != key:
             # Key collision, oh well.
-            from warnings import warn
-            warn("%s: key collision in cache at '%s' -- these are "
+            self._warn("%s: key collision in cache at '%s' -- these are "
                     "sufficiently unlikely that they're often "
-                    "indicative of a broken implementation "
-                    "of equality comparison"
-                    % (self.identifier, self.container_dir))
-            # This is here so we can debug the equality comparison
+                    "indicative of a broken hash key implementation "
+                    "(that is not considering some elements relevant "
+                    "for equality comparison)"
+                    % (self.identifier, self.container_dir),
+                    CollisionWarning)
+
+            # This is here so we can step through equality comparison to
+            # see what is actually non-equal.
             stored_key == key
             raise NoSuchEntryError(key)
 
@@ -487,7 +539,21 @@
         self._make_container_dir()
 
 
+@_tracks_stacklevel
 class WriteOncePersistentDict(_PersistentDictBase):
+    """A concurrent disk-backed dictionary that disallows overwriting/deletion.
+
+    Compared with :class:`PersistentDict`, this class has faster
+    retrieval times.
+
+    .. automethod:: __init__
+    .. automethod:: __getitem__
+    .. automethod:: __setitem__
+    .. automethod:: clear
+    .. automethod:: store
+    .. automethod:: store_if_not_present
+    .. automethod:: fetch
+    """
     def __init__(self, identifier, key_builder=None, container_dir=None,
              in_mem_cache_size=256):
         """
@@ -496,11 +562,6 @@
         :arg key_builder: a subclass of :class:`KeyBuilder`
         :arg in_mem_cache_size: retain an in-memory cache of up to
             *in_mem_cache_size* items
-
-        .. automethod:: __getitem__
-        .. automethod:: __setitem__
-        .. automethod:: clear
-        .. automethod:: store_if_not_present
         """
         _PersistentDictBase.__init__(self, identifier, key_builder, 
container_dir)
         self._cache = _LRUCache(in_mem_cache_size)
@@ -516,8 +577,7 @@
             attempts += 1
 
             if attempts > 10:
-                from warnings import warn
-                warn("waiting until unlocked--delete '%s' if necessary"
+                self._warn("waiting until unlocked--delete '%s' if necessary"
                         % lock_file)
 
             if attempts > 3 * 60:
@@ -551,7 +611,7 @@
 
                 logger.debug("%s: disk cache store [key=%s]" % (
                         self.identifier, hexdigest_key))
-            except:
+            except Exception:
                 cleanup_m.error_clean_up()
                 raise
         finally:
@@ -599,13 +659,12 @@
 
         try:
             read_key = self._read(key_file)
-        except:
-            from warnings import warn
-            warn("pytools.persistent_dict.WriteOncePersistentDict(%s) "
+        except Exception as e:
+            self._warn("pytools.persistent_dict.WriteOncePersistentDict(%s) "
                     "encountered an invalid "
                     "key file for key %s. Remove the directory "
-                    "'%s' if necessary."
-                    % (self.identifier, hexdigest_key, item_dir))
+                    "'%s' if necessary. (caught: %s)"
+                    % (self.identifier, hexdigest_key, item_dir, str(e)))
             raise NoSuchEntryError(key)
 
         self._collision_check(key, read_key)
@@ -619,8 +678,8 @@
 
         try:
             read_contents = self._read(contents_file)
-        except:
-            warn("pytools.persistent_dict.WriteOncePersistentDict(%s) "
+        except Exception:
+            self._warn("pytools.persistent_dict.WriteOncePersistentDict(%s) "
                     "encountered an invalid "
                     "key file for key %s. Remove the directory "
                     "'%s' if necessary."
@@ -637,18 +696,23 @@
         self._cache.clear()
 
 
+@_tracks_stacklevel
 class PersistentDict(_PersistentDictBase):
+    """A concurrent disk-backed dictionary.
+
+    .. automethod:: __init__
+    .. automethod:: __getitem__
+    .. automethod:: __setitem__
+    .. automethod:: clear
+    .. automethod:: store
+    .. automethod:: store_if_not_present
+    .. automethod:: fetch
+    """
     def __init__(self, identifier, key_builder=None, container_dir=None):
         """
         :arg identifier: a file-name-compatible string identifying this
             dictionary
         :arg key_builder: a subclass of :class:`KeyBuilder`
-
-        .. automethod:: __getitem__
-        .. automethod:: __setitem__
-        .. automethod:: __delitem__
-        .. automethod:: clear
-        .. automethod:: store_if_not_present
         """
         _PersistentDictBase.__init__(self, identifier, key_builder, 
container_dir)
 
@@ -658,7 +722,8 @@
         cleanup_m = CleanupManager()
         try:
             try:
-                LockManager(cleanup_m, self._lock_file(hexdigest_key))
+                LockManager(cleanup_m, self._lock_file(hexdigest_key),
+                        1 + self._stacklevel)
                 item_dir_m = ItemDirManager(
                         cleanup_m, self._item_dir(hexdigest_key),
                         delete_on_error=True)
@@ -678,7 +743,7 @@
 
                 logger.debug("%s: cache store [key=%s]" % (
                         self.identifier, hexdigest_key))
-            except:
+            except Exception:
                 cleanup_m.error_clean_up()
                 raise
         finally:
@@ -697,7 +762,8 @@
         cleanup_m = CleanupManager()
         try:
             try:
-                LockManager(cleanup_m, self._lock_file(hexdigest_key))
+                LockManager(cleanup_m, self._lock_file(hexdigest_key),
+                        1 + self._stacklevel)
                 item_dir_m = ItemDirManager(
                         cleanup_m, item_dir, delete_on_error=False)
 
@@ -708,10 +774,9 @@
 
                 try:
                     read_key = self._read(key_path)
-                except:
+                except Exception:
                     item_dir_m.reset()
-                    from warnings import warn
-                    warn("pytools.persistent_dict.PersistentDict(%s) "
+                    self._warn("pytools.persistent_dict.PersistentDict(%s) "
                             "encountered an invalid "
                             "key file for key %s. Entry deleted."
                             % (self.identifier, hexdigest_key))
@@ -728,10 +793,9 @@
 
                 try:
                     read_contents = self._read(value_path)
-                except:
+                except Exception:
                     item_dir_m.reset()
-                    from warnings import warn
-                    warn("pytools.persistent_dict.PersistentDict(%s) "
+                    self._warn("pytools.persistent_dict.PersistentDict(%s) "
                             "encountered an invalid "
                             "key file for key %s. Entry deleted."
                             % (self.identifier, hexdigest_key))
@@ -741,7 +805,7 @@
 
                 # }}}
 
-            except:
+            except Exception:
                 cleanup_m.error_clean_up()
                 raise
         finally:
@@ -758,7 +822,8 @@
         cleanup_m = CleanupManager()
         try:
             try:
-                LockManager(cleanup_m, self._lock_file(hexdigest_key))
+                LockManager(cleanup_m, self._lock_file(hexdigest_key),
+                        1 + self._stacklevel)
                 item_dir_m = ItemDirManager(
                         cleanup_m, item_dir, delete_on_error=False)
                 key_file = self._key_file(hexdigest_key)
@@ -767,10 +832,9 @@
 
                 try:
                     read_key = self._read(key_file)
-                except:
+                except Exception:
                     item_dir_m.reset()
-                    from warnings import warn
-                    warn("pytools.persistent_dict.PersistentDict(%s) "
+                    self._warn("pytools.persistent_dict.PersistentDict(%s) "
                             "encountered an invalid "
                             "key file for key %s. Entry deleted."
                             % (self.identifier, hexdigest_key))
@@ -782,7 +846,7 @@
 
                 item_dir_m.reset()
 
-            except:
+            except Exception:
                 cleanup_m.error_clean_up()
                 raise
         finally:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/pytools/py_codegen.py 
new/pytools-2018.3/pytools/py_codegen.py
--- old/pytools-2017.6/pytools/py_codegen.py    2017-06-03 00:36:37.000000000 
+0200
+++ new/pytools-2018.3/pytools/py_codegen.py    2018-03-16 21:25:30.000000000 
+0100
@@ -100,6 +100,10 @@
     def get_function(self):
         return self.get_module()[self.name]
 
+    def get_picklable_function(self):
+        module = self.get_picklable_module()
+        return PicklableFunction(module, self.name)
+
 
 # {{{ pickling of binaries for generated code
 
@@ -121,27 +125,32 @@
 
         nondefault_globals = {}
         functions = {}
+        modules = {}
 
-        from types import FunctionType
+        from types import FunctionType, ModuleType
         for k, v in six.iteritems(self.mod_globals):
             if isinstance(v, FunctionType):
                 functions[k] = (
                         v.__name__,
                         marshal.dumps(v.__code__),
                         v.__defaults__)
-
+            elif isinstance(v, ModuleType):
+                modules[k] = v.__name__
             elif k not in _empty_module_dict:
                 nondefault_globals[k] = v
 
         import imp
-        return (0, imp.get_magic(), functions, nondefault_globals)
+        return (1, imp.get_magic(), functions, modules, nondefault_globals)
 
     def __setstate__(self, obj):
         v = obj[0]
         if v == 0:
             magic, functions, nondefault_globals = obj[1:]
+            modules = {}
+        elif v == 1:
+            magic, functions, modules, nondefault_globals = obj[1:]
         else:
-            raise ValueError("unknown version of PicklableGeneratedFunction")
+            raise ValueError("unknown version of PicklableModule")
 
         import imp
         if magic != imp.get_magic():
@@ -155,6 +164,11 @@
         mod_globals.update(nondefault_globals)
         self.mod_globals = mod_globals
 
+        from pytools.importlib_backport import import_module
+
+        for k, mod_name in six.iteritems(modules):
+            mod_globals[k] = import_module(mod_name)
+
         from types import FunctionType
         for k, v in six.iteritems(functions):
             name, code_bytes, argdefs = v
@@ -164,6 +178,32 @@
 
 # }}}
 
+
+# {{{ picklable function
+
+class PicklableFunction(object):
+    """Convience class wrapping a function in a :class:`PicklableModule`.
+    """
+
+    def __init__(self, module, name):
+        self._initialize(module, name)
+
+    def _initialize(self, module, name):
+        self.module = module
+        self.name = name
+        self.func = module.mod_globals[name]
+
+    def __call__(self, *args, **kwargs):
+        return self.func(*args, **kwargs)
+
+    def __getstate__(self):
+        return {"module": self.module, "name": self.name}
+
+    def __setstate__(self, obj):
+        self._initialize(obj["module"], obj["name"])
+
+# }}}
+
 
 # {{{ remove common indentation
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/pytools/version.py 
new/pytools-2018.3/pytools/version.py
--- old/pytools-2017.6/pytools/version.py       2017-09-26 02:09:20.000000000 
+0200
+++ new/pytools-2018.3/pytools/version.py       2018-03-16 21:25:30.000000000 
+0100
@@ -1,3 +1,3 @@
-VERSION = (2017, 6)
+VERSION = (2018, 3)
 VERSION_STATUS = ""
 VERSION_TEXT = ".".join(str(x) for x in VERSION) + VERSION_STATUS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/pytools.egg-info/PKG-INFO 
new/pytools-2018.3/pytools.egg-info/PKG-INFO
--- old/pytools-2017.6/pytools.egg-info/PKG-INFO        2017-09-26 
02:09:29.000000000 +0200
+++ new/pytools-2018.3/pytools.egg-info/PKG-INFO        2018-03-16 
21:26:58.000000000 +0100
@@ -1,11 +1,12 @@
 Metadata-Version: 1.1
 Name: pytools
-Version: 2017.6
+Version: 2018.3
 Summary: A collection of tools for Python
 Home-page: http://pypi.python.org/pypi/pytools
 Author: Andreas Kloeckner
 Author-email: [email protected]
 License: MIT
+Description-Content-Type: UNKNOWN
 Description: Pytools is a big bag of things that are "missing" from the Python 
standard
         library. This is mainly a dependency of my other software packages, 
and is
         probably of little interest to you unless you use those. If you're 
curious
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/pytools.egg-info/SOURCES.txt 
new/pytools-2018.3/pytools.egg-info/SOURCES.txt
--- old/pytools-2017.6/pytools.egg-info/SOURCES.txt     2017-09-26 
02:09:29.000000000 +0200
+++ new/pytools-2018.3/pytools.egg-info/SOURCES.txt     2018-03-16 
21:26:58.000000000 +0100
@@ -11,6 +11,7 @@
 pytools/debug.py
 pytools/decorator.py
 pytools/diskdict.py
+pytools/importlib_backport.py
 pytools/lex.py
 pytools/log.py
 pytools/mpi.py
@@ -31,4 +32,5 @@
 test/test_data_table.py
 test/test_math_stuff.py
 test/test_persistent_dict.py
+test/test_py_codegen.py
 test/test_pytools.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/test/test_persistent_dict.py 
new/pytools-2018.3/test/test_persistent_dict.py
--- old/pytools-2017.6/test/test_persistent_dict.py     2017-09-26 
02:09:20.000000000 +0200
+++ new/pytools-2018.3/test/test_persistent_dict.py     2018-02-27 
07:06:00.000000000 +0100
@@ -10,7 +10,7 @@
 
 from pytools.persistent_dict import (
         PersistentDict, WriteOncePersistentDict, NoSuchEntryError,
-        ReadOnlyEntryError)
+        ReadOnlyEntryError, CollisionWarning)
 
 
 # {{{ type for testing
@@ -155,12 +155,12 @@
         pdict[key1] = 1
 
         # check lookup
-        with pytest.warns(UserWarning):
+        with pytest.warns(CollisionWarning):
             with pytest.raises(NoSuchEntryError):
                 pdict[key2]
 
         # check deletion
-        with pytest.warns(UserWarning):
+        with pytest.warns(CollisionWarning):
             with pytest.raises(NoSuchEntryError):
                 del pdict[key2]
 
@@ -283,7 +283,7 @@
         pdict[key1] = 1
 
         # check lookup
-        with pytest.warns(UserWarning):
+        with pytest.warns(CollisionWarning):
             with pytest.raises(NoSuchEntryError):
                 pdict[key2]
 
@@ -292,7 +292,7 @@
             pdict[key2] = 1
 
         # check store_if_not_present
-        pdict.store_if_not_present(key2, 1)
+        pdict.store_if_not_present(key2, 2)
         assert pdict[key1] == 1
 
     finally:
@@ -318,5 +318,5 @@
     if len(sys.argv) > 1:
         exec(sys.argv[1])
     else:
-        from py.test.cmdline import main
+        from pytest import main
         main([__file__])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/test/test_py_codegen.py 
new/pytools-2018.3/test/test_py_codegen.py
--- old/pytools-2017.6/test/test_py_codegen.py  1970-01-01 01:00:00.000000000 
+0100
+++ new/pytools-2018.3/test/test_py_codegen.py  2018-03-16 21:25:30.000000000 
+0100
@@ -0,0 +1,38 @@
+from __future__ import division, with_statement, absolute_import
+
+import pytest  # noqa
+import pytools
+import pytools.py_codegen as codegen
+import sys
+
+
+def test_pickling_with_module_import():
+    cg = codegen.PythonCodeGenerator()
+    cg("import pytools")
+    cg("import math as m")
+
+    import pickle
+    mod = pickle.loads(pickle.dumps(cg.get_picklable_module()))
+
+    assert mod.mod_globals["pytools"] is pytools
+
+    import math
+    assert mod.mod_globals["m"] is math
+
+
+def test_picklable_function():
+    cg = codegen.PythonFunctionGenerator("f", args=())
+    cg("return 1")
+
+    import pickle
+    f = pickle.loads(pickle.dumps(cg.get_picklable_function()))
+
+    assert f() == 1
+
+
+if __name__ == "__main__":
+    if len(sys.argv) > 1:
+        exec(sys.argv[1])
+    else:
+        from py.test import main
+        main([__file__])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytools-2017.6/test/test_pytools.py 
new/pytools-2018.3/test/test_pytools.py
--- old/pytools-2017.6/test/test_pytools.py     2017-03-29 22:05:55.000000000 
+0200
+++ new/pytools-2018.3/test/test_pytools.py     2018-03-11 07:19:15.000000000 
+0100
@@ -195,9 +195,25 @@
         del d
 
 
+def test_generate_numbered_unique_names():
+    from pytools import generate_numbered_unique_names
+
+    gen = generate_numbered_unique_names("a")
+    assert next(gen) == (0, "a")
+    assert next(gen) == (1, "a_0")
+
+    gen = generate_numbered_unique_names("b", 6)
+    assert next(gen) == (7, "b_6")
+
+
+def test_find_module_git_revision():
+    import pytools
+    print(pytools.find_module_git_revision(pytools.__file__, n_levels_up=1))
+
+
 if __name__ == "__main__":
     if len(sys.argv) > 1:
         exec(sys.argv[1])
     else:
-        from py.test.cmdline import main
+        from pytest import main
         main([__file__])


Reply via email to