Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-pyrsistent for 
openSUSE:Factory checked in at 2024-01-06 17:29:15
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pyrsistent (Old)
 and      /work/SRC/openSUSE:Factory/.python-pyrsistent.new.28375 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pyrsistent"

Sat Jan  6 17:29:15 2024 rev:14 rq:1137122 version:0.20.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pyrsistent/python-pyrsistent.changes      
2023-04-22 21:58:31.556522512 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-pyrsistent.new.28375/python-pyrsistent.changes
   2024-01-06 17:29:18.499907530 +0100
@@ -1,0 +2,16 @@
+Fri Jan  5 17:29:47 UTC 2024 - Dirk Müller <dmuel...@suse.com>
+
+- update to 0.20.0:
+  * Fix #245, never introduce new nodes during discard.
+  * Fix #268, do not rely on well implemented __ne__ for keys in
+    pmaps, instead do explicit inversion of equality
+    comparison when checking for inequality.
+  * Officially support Python 3.12.
+  * Officially drop support for Python 3.7.
+  * Fix #273, build more types of wheels.
+  * Fix #282, add generic types to types
+  * Fix #281, defaultdict can now be frozen. NB! This is a
+    backwards incompatible fix since defaultdict was not
+    previously frozen.
+
+-------------------------------------------------------------------

Old:
----
  pyrsistent-0.19.3.tar.gz

New:
----
  pyrsistent-0.20.0.tar.gz

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

Other differences:
------------------
++++++ python-pyrsistent.spec ++++++
--- /var/tmp/diff_new_pack.rqmYo2/_old  2024-01-06 17:29:19.403940550 +0100
+++ /var/tmp/diff_new_pack.rqmYo2/_new  2024-01-06 17:29:19.407940696 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-pyrsistent
 #
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,11 +16,9 @@
 #
 
 
-%{?!python_module:%define python_module() python-%{**} python3-%{**}}
-%global skip_python2 1
 %{?sle15_python_module_pythons}
 Name:           python-pyrsistent
-Version:        0.19.3
+Version:        0.20.0
 Release:        0
 Summary:        Persistent, Functional, Immutable data structures
 License:        MIT
@@ -29,8 +27,10 @@
 Source:         
https://files.pythonhosted.org/packages/source/p/pyrsistent/pyrsistent-%{version}.tar.gz
 BuildRequires:  %{python_module devel}
 BuildRequires:  %{python_module hypothesis}
+BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module setuptools}
+BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 %python_subpackages
@@ -50,10 +50,10 @@
 
 %build
 export CFLAGS="%{optflags}"
-%python_build
+%pyproject_wheel
 
 %install
-%python_install
+%pyproject_install
 %python_expand %fdupes %{buildroot}%{$python_sitearch}
 
 %check
@@ -66,5 +66,5 @@
 %{python_sitearch}/_pyrsistent*
 %{python_sitearch}/pvectorc*
 %{python_sitearch}/pyrsistent
-%{python_sitearch}/pyrsistent-%{version}*-info
+%{python_sitearch}/pyrsistent-%{version}.dist-info
 

++++++ pyrsistent-0.19.3.tar.gz -> pyrsistent-0.20.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/CHANGES.txt 
new/pyrsistent-0.20.0/CHANGES.txt
--- old/pyrsistent-0.19.3/CHANGES.txt   2022-12-29 08:50:58.000000000 +0100
+++ new/pyrsistent-0.20.0/CHANGES.txt   2023-10-25 22:54:06.000000000 +0200
@@ -1,5 +1,16 @@
 Revision history
 ----------------
+0.20.0, 2023-10-25
+ * Fix #245, never introduce new nodes during discard.
+ * Fix #268, do not rely on well implemented __ne__ for keys in pmaps, instead 
do explicit inversion of equality
+   comparison when checking for inequality.
+ * Officially support Python 3.12.
+ * Officially drop support for Python 3.7.
+ * Fix #273, build more types of wheels. Thanks @jams2 for this!
+ * Fix #282, add generic types to types. Thanks @lukasK9999 for this!
+ * Fix #281, defaultdict can now be frozen. NB! This is a backwards 
incompatible fix since defaultdict was not
+   previously frozen.
+
 0.19.3, 2022-12-29
  * Fix #264, add wheels and official support for Python 3.11. Thanks @hugovk 
for this!
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/LICENSE.mit 
new/pyrsistent-0.20.0/LICENSE.mit
--- old/pyrsistent-0.19.3/LICENSE.mit   2022-12-29 08:50:58.000000000 +0100
+++ new/pyrsistent-0.20.0/LICENSE.mit   2023-10-25 22:54:06.000000000 +0200
@@ -1,4 +1,4 @@
-Copyright (c) 2022 Tobias Gustafsson
+Copyright (c) 2023 Tobias Gustafsson
 
 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/PKG-INFO 
new/pyrsistent-0.20.0/PKG-INFO
--- old/pyrsistent-0.19.3/PKG-INFO      2022-12-29 08:51:12.178382600 +0100
+++ new/pyrsistent-0.20.0/PKG-INFO      2023-10-25 22:54:20.757125600 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: pyrsistent
-Version: 0.19.3
+Version: 0.20.0
 Summary: Persistent/Functional/Immutable data structures
 Home-page: https://github.com/tobgu/pyrsistent/
 Author: Tobias Gustafsson
@@ -10,13 +10,13 @@
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: Implementation :: PyPy
-Requires-Python: >=3.7
+Requires-Python: >=3.8
 Description-Content-Type: text/x-rst
 License-File: LICENSE.mit
 
@@ -601,7 +601,7 @@
 Compatibility
 -------------
 
-Pyrsistent is developed and tested on Python 3.7+ and PyPy3.
+Pyrsistent is developed and tested on Python 3.8+ and PyPy3.
 
 Performance
 -----------
@@ -741,6 +741,12 @@
 
 Aaron Durant https://github.com/Aaron-Durant
 
+Joshua Munn https://github.com/jams2
+
+Lukas https://github.com/lukasK9999
+
+Arshad https://github.com/arshad-ml
+
 Contributing
 ------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/README new/pyrsistent-0.20.0/README
--- old/pyrsistent-0.19.3/README        2022-12-29 08:50:58.000000000 +0100
+++ new/pyrsistent-0.20.0/README        2023-10-25 22:54:06.000000000 +0200
@@ -579,7 +579,7 @@
 Compatibility
 -------------
 
-Pyrsistent is developed and tested on Python 3.7+ and PyPy3.
+Pyrsistent is developed and tested on Python 3.8+ and PyPy3.
 
 Performance
 -----------
@@ -719,6 +719,12 @@
 
 Aaron Durant https://github.com/Aaron-Durant
 
+Joshua Munn https://github.com/jams2
+
+Lukas https://github.com/lukasK9999
+
+Arshad https://github.com/arshad-ml
+
 Contributing
 ------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/README.rst 
new/pyrsistent-0.20.0/README.rst
--- old/pyrsistent-0.19.3/README.rst    2022-12-29 08:50:58.000000000 +0100
+++ new/pyrsistent-0.20.0/README.rst    2023-10-25 22:54:06.000000000 +0200
@@ -579,7 +579,7 @@
 Compatibility
 -------------
 
-Pyrsistent is developed and tested on Python 3.7+ and PyPy3.
+Pyrsistent is developed and tested on Python 3.8+ and PyPy3.
 
 Performance
 -----------
@@ -719,6 +719,12 @@
 
 Aaron Durant https://github.com/Aaron-Durant
 
+Joshua Munn https://github.com/jams2
+
+Lukas https://github.com/lukasK9999
+
+Arshad https://github.com/arshad-ml
+
 Contributing
 ------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/_pyrsistent_version.py 
new/pyrsistent-0.20.0/_pyrsistent_version.py
--- old/pyrsistent-0.19.3/_pyrsistent_version.py        2022-12-29 
08:50:58.000000000 +0100
+++ new/pyrsistent-0.20.0/_pyrsistent_version.py        2023-10-25 
22:54:06.000000000 +0200
@@ -1 +1 @@
-__version__ = '0.19.3'
+__version__ = '0.20.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pvectorcmodule.c 
new/pyrsistent-0.20.0/pvectorcmodule.c
--- old/pyrsistent-0.19.3/pvectorcmodule.c      2022-12-29 08:50:58.000000000 
+0100
+++ new/pyrsistent-0.20.0/pvectorcmodule.c      2023-10-25 22:54:06.000000000 
+0200
@@ -15,7 +15,7 @@
 ------------------
 initpyrsistentc - This is the method that initializes the whole module
 pyrsistent_* -    Methods part of the interface
-<typename>_* -    Instance methods of types. For examle PVector_append(...)
+<typename>_* -    Instance methods of types. For example PVector_append(...)
 
 All other methods are camel cased without prefix. All methods are static, none 
should
 require to be exposed outside of this module. 
@@ -232,13 +232,13 @@
   }
   
   PyObject_GC_UnTrack((PyObject*)self);
-  Py_TRASHCAN_SAFE_BEGIN(self);
+  Py_TRASHCAN_BEGIN(self, PVector_dealloc);
 
   releaseNode(0, self->tail);
   releaseNode(self->shift, self->root);
   
   PyObject_GC_Del(self);
-  Py_TRASHCAN_SAFE_END(self);
+  Py_TRASHCAN_END;
 }
 
 static PyObject *PVector_toList(PVector *self) {
@@ -1289,7 +1289,7 @@
 
 static void PVectorEvolver_dealloc(PVectorEvolver *self) {
   PyObject_GC_UnTrack(self);
-  Py_TRASHCAN_SAFE_BEGIN(self);
+  Py_TRASHCAN_BEGIN(self, PVectorEvolver_dealloc);
 
   if(self->originalVector != self->newVector) {
     cleanVector(self->newVector);
@@ -1300,7 +1300,7 @@
   Py_DECREF(self->appendList);
 
   PyObject_GC_Del(self);
-  Py_TRASHCAN_SAFE_END(self);
+  Py_TRASHCAN_END;
 }
 
 static PyObject *PVectorEvolver_append(PVectorEvolver *self, PyObject *args) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pyrsistent/_checked_types.py 
new/pyrsistent-0.20.0/pyrsistent/_checked_types.py
--- old/pyrsistent-0.19.3/pyrsistent/_checked_types.py  2022-12-29 
08:50:58.000000000 +0100
+++ new/pyrsistent-0.20.0/pyrsistent/_checked_types.py  2023-10-25 
22:54:06.000000000 +0200
@@ -2,11 +2,16 @@
 
 from abc import abstractmethod, ABCMeta
 from collections.abc import Iterable
+from typing import TypeVar, Generic
 
 from pyrsistent._pmap import PMap, pmap
 from pyrsistent._pset import PSet, pset
 from pyrsistent._pvector import PythonPVector, python_pvector
 
+T_co = TypeVar('T_co', covariant=True)
+KT = TypeVar('KT')
+VT_co = TypeVar('VT_co', covariant=True)
+
 
 class CheckedType(object):
     """
@@ -271,7 +276,7 @@
 
     return cls(source_data)
 
-class CheckedPVector(PythonPVector, CheckedType, metaclass=_CheckedTypeMeta):
+class CheckedPVector(Generic[T_co], PythonPVector, CheckedType, 
metaclass=_CheckedTypeMeta):
     """
     A CheckedPVector is a PVector which allows specifying type and invariant 
checks.
 
@@ -357,7 +362,7 @@
         return CheckedPVector.Evolver(self.__class__, self)
 
 
-class CheckedPSet(PSet, CheckedType, metaclass=_CheckedTypeMeta):
+class CheckedPSet(PSet[T_co], CheckedType, metaclass=_CheckedTypeMeta):
     """
     A CheckedPSet is a PSet which allows specifying type and invariant checks.
 
@@ -455,7 +460,7 @@
 _UNDEFINED_CHECKED_PMAP_SIZE = object()
 
 
-class CheckedPMap(PMap, CheckedType, metaclass=_CheckedMapTypeMeta):
+class CheckedPMap(PMap[KT, VT_co], CheckedType, metaclass=_CheckedMapTypeMeta):
     """
     A CheckedPMap is a PMap which allows specifying type and invariant checks.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pyrsistent/_helpers.py 
new/pyrsistent-0.20.0/pyrsistent/_helpers.py
--- old/pyrsistent-0.19.3/pyrsistent/_helpers.py        2022-12-29 
08:50:58.000000000 +0100
+++ new/pyrsistent-0.20.0/pyrsistent/_helpers.py        2023-10-25 
22:54:06.000000000 +0200
@@ -1,3 +1,4 @@
+import collections
 from functools import wraps
 from pyrsistent._pmap import PMap, pmap
 from pyrsistent._pset import PSet, pset
@@ -10,6 +11,7 @@
 
     - list is converted to pvector, recursively
     - dict is converted to pmap, recursively on values (but not keys)
+    - defaultdict is converted to pmap, recursively on values (but not keys)
     - set is converted to pset, but not recursively
     - tuple is converted to tuple, recursively.
 
@@ -33,6 +35,8 @@
     typ = type(o)
     if typ is dict or (strict and isinstance(o, PMap)):
         return pmap({k: freeze(v, strict) for k, v in o.items()})
+    if typ is collections.defaultdict or (strict and isinstance(o, PMap)):
+        return pmap({k: freeze(v, strict) for k, v in o.items()})
     if typ is list or (strict and isinstance(o, PVector)):
         curried_freeze = lambda x: freeze(x, strict)
         return pvector(map(curried_freeze, o))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pyrsistent/_pbag.py 
new/pyrsistent-0.20.0/pyrsistent/_pbag.py
--- old/pyrsistent-0.19.3/pyrsistent/_pbag.py   2022-12-29 08:50:58.000000000 
+0100
+++ new/pyrsistent-0.20.0/pyrsistent/_pbag.py   2023-10-25 22:54:06.000000000 
+0200
@@ -1,13 +1,16 @@
 from collections.abc import Container, Iterable, Sized, Hashable
 from functools import reduce
+from typing import Generic, TypeVar
 from pyrsistent._pmap import pmap
 
+T_co = TypeVar('T_co', covariant=True)
+
 
 def _add_to_counters(counters, element):
     return counters.set(element, counters.get(element, 0) + 1)
 
 
-class PBag(object):
+class PBag(Generic[T_co]):
     """
     A persistent bag/multiset type.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pyrsistent/_pdeque.py 
new/pyrsistent-0.20.0/pyrsistent/_pdeque.py
--- old/pyrsistent-0.19.3/pyrsistent/_pdeque.py 2022-12-29 08:50:58.000000000 
+0100
+++ new/pyrsistent-0.20.0/pyrsistent/_pdeque.py 2023-10-25 22:54:06.000000000 
+0200
@@ -1,10 +1,13 @@
 from collections.abc import Sequence, Hashable
 from itertools import islice, chain
 from numbers import Integral
+from typing import TypeVar, Generic
 from pyrsistent._plist import plist
 
+T_co = TypeVar('T_co', covariant=True)
 
-class PDeque(object):
+
+class PDeque(Generic[T_co]):
     """
     Persistent double ended queue (deque). Allows quick appends and pops in 
both ends. Implemented
     using two persistent lists.
@@ -175,7 +178,7 @@
         return False
 
     def __hash__(self):
-        return  hash(tuple(self))
+        return hash(tuple(self))
 
     def __len__(self):
         return self._length
@@ -275,7 +278,7 @@
             try:
                 # This is severely inefficient with a double reverse, should 
perhaps implement a remove_last()?
                 return PDeque(self._left_list,
-                               
self._right_list.reverse().remove(elem).reverse(), self._length - 1)
+                              
self._right_list.reverse().remove(elem).reverse(), self._length - 1)
             except ValueError as e:
                 raise ValueError('{0} not found in PDeque'.format(elem)) from e
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pyrsistent/_plist.py 
new/pyrsistent-0.20.0/pyrsistent/_plist.py
--- old/pyrsistent-0.19.3/pyrsistent/_plist.py  2022-12-29 08:50:58.000000000 
+0100
+++ new/pyrsistent-0.20.0/pyrsistent/_plist.py  2023-10-25 22:54:06.000000000 
+0200
@@ -1,6 +1,9 @@
 from collections.abc import Sequence, Hashable
 from numbers import Integral
 from functools import reduce
+from typing import Generic, TypeVar
+
+T_co = TypeVar('T_co', covariant=True)
 
 
 class _PListBuilder(object):
@@ -219,7 +222,7 @@
         raise ValueError('{0} not found in PList'.format(elem))
 
 
-class PList(_PListBase):
+class PList(Generic[T_co], _PListBase):
     """
     Classical Lisp style singly linked list. Adding elements to the head using 
cons is O(1).
     Element access is O(k) where k is the position of the element in the list. 
Taking the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pyrsistent/_pmap.py 
new/pyrsistent-0.20.0/pyrsistent/_pmap.py
--- old/pyrsistent-0.19.3/pyrsistent/_pmap.py   2022-12-29 08:50:58.000000000 
+0100
+++ new/pyrsistent-0.20.0/pyrsistent/_pmap.py   2023-10-25 22:54:06.000000000 
+0200
@@ -1,8 +1,12 @@
 from collections.abc import Mapping, Hashable
 from itertools import chain
+from typing import Generic, TypeVar
+
 from pyrsistent._pvector import pvector
 from pyrsistent._transformations import transform
 
+KT = TypeVar('KT')
+VT_co = TypeVar('VT_co', covariant=True)
 class PMapView:
     """View type for the persistent map/dict type `PMap`.
 
@@ -103,7 +107,7 @@
         elif not isinstance(x, type(self)): return False
         else: return self._map == x._map
 
-class PMap(object):
+class PMap(Generic[KT, VT_co]):
     """
     Persistent map/dict. Tries to follow the same naming conventions as the 
built in dict where feasible.
 
@@ -409,7 +413,8 @@
                 for k, v in bucket:
                     if k == key:
                         if v is not val:
-                            new_bucket = [(k2, v2) if k2 != k else (k2, val) 
for k2, v2 in bucket]
+                            # Use `not (k2 == k)` rather than `!=` to avoid 
relying on a well implemented `__ne__`, see #268.
+                            new_bucket = [(k2, v2) if not (k2 == k) else (k2, 
val) for k2, v2 in bucket]
                             self._buckets_evolver[index] = new_bucket
 
                         return self
@@ -472,10 +477,12 @@
             index, bucket = PMap._get_bucket(self._buckets_evolver, key)
 
             if bucket:
-                new_bucket = [(k, v) for (k, v) in bucket if k != key]
-                if len(bucket) > len(new_bucket):
+                # Use `not (k == key)` rather than `!=` to avoid relying on a 
well implemented `__ne__`, see #268.
+                new_bucket = [(k, v) for (k, v) in bucket if not (k == key)]
+                size_diff = len(bucket) - len(new_bucket)
+                if size_diff > 0:
                     self._buckets_evolver[index] = new_bucket if new_bucket 
else None
-                    self._size -= 1
+                    self._size -= size_diff
                     return self
 
             raise KeyError('{0}'.format(key))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pyrsistent/_pset.py 
new/pyrsistent-0.20.0/pyrsistent/_pset.py
--- old/pyrsistent-0.19.3/pyrsistent/_pset.py   2022-12-29 08:50:58.000000000 
+0100
+++ new/pyrsistent-0.20.0/pyrsistent/_pset.py   2023-10-25 22:54:06.000000000 
+0200
@@ -1,9 +1,12 @@
 from collections.abc import Set, Hashable
 import sys
+from typing import TypeVar, Generic
 from pyrsistent._pmap import pmap
 
+T_co = TypeVar('T_co', covariant=True)
 
-class PSet(object):
+
+class PSet(Generic[T_co]):
     """
     Persistent set implementation. Built on top of the persistent map. The set 
supports all operations
     in the Set protocol and is Hashable.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pyrsistent/_pvector.py 
new/pyrsistent-0.20.0/pyrsistent/_pvector.py
--- old/pyrsistent-0.19.3/pyrsistent/_pvector.py        2022-12-29 
08:50:58.000000000 +0100
+++ new/pyrsistent-0.20.0/pyrsistent/_pvector.py        2023-10-25 
22:54:06.000000000 +0200
@@ -2,8 +2,12 @@
 from collections.abc import Sequence, Hashable
 from numbers import Integral
 import operator
+from typing import TypeVar, Generic
+
 from pyrsistent._transformations import transform
 
+T_co = TypeVar('T_co', covariant=True)
+
 
 def _bitcount(val):
     return bin(val).count("1")
@@ -410,7 +414,7 @@
         l.remove(value)
         return _EMPTY_PVECTOR.extend(l)
 
-class PVector(metaclass=ABCMeta):
+class PVector(Generic[T_co],metaclass=ABCMeta):
     """
     Persistent vector implementation. Meant as a replacement for the cases 
where you would normally
     use a Python list.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pyrsistent/_transformations.py 
new/pyrsistent-0.20.0/pyrsistent/_transformations.py
--- old/pyrsistent-0.19.3/pyrsistent/_transformations.py        2022-12-29 
08:50:58.000000000 +0100
+++ new/pyrsistent-0.20.0/pyrsistent/_transformations.py        2023-10-25 
22:54:06.000000000 +0200
@@ -127,6 +127,10 @@
         for k, v in kvs:
             is_empty = False
             if v is _EMPTY_SENTINEL:
+                if command is discard:
+                    # If nothing there when discarding just move on, do not 
introduce new nodes
+                    continue
+
                 # Allow expansion of structure but make sure to cover the case
                 # when an empty pmap is added as leaf node. See #154.
                 is_empty = True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pyrsistent/typing.py 
new/pyrsistent-0.20.0/pyrsistent/typing.py
--- old/pyrsistent-0.19.3/pyrsistent/typing.py  2022-12-29 08:50:58.000000000 
+0100
+++ new/pyrsistent-0.20.0/pyrsistent/typing.py  2023-10-25 22:54:06.000000000 
+0200
@@ -36,36 +36,38 @@
     ]
 
     T = TypeVar('T')
+    T_co = TypeVar('T_co', covariant=True)
     KT = TypeVar('KT')
     VT = TypeVar('VT')
+    VT_co = TypeVar('VT_co', covariant=True)
 
-    class CheckedPMap(Mapping[KT, VT], Hashable):
+    class CheckedPMap(Mapping[KT, VT_co], Hashable):
         pass
 
     # PSet.add and PSet.discard have different type signatures than that of 
Set.
-    class CheckedPSet(Generic[T], Hashable):
+    class CheckedPSet(Generic[T_co], Hashable):
         pass
 
-    class CheckedPVector(Sequence[T], Hashable):
+    class CheckedPVector(Sequence[T_co], Hashable):
         pass
 
-    class PBag(Container[T], Iterable[T], Sized, Hashable):
+    class PBag(Container[T_co], Iterable[T_co], Sized, Hashable):
         pass
 
-    class PDeque(Sequence[T], Hashable):
+    class PDeque(Sequence[T_co], Hashable):
         pass
 
-    class PList(Sequence[T], Hashable):
+    class PList(Sequence[T_co], Hashable):
         pass
 
-    class PMap(Mapping[KT, VT], Hashable):
+    class PMap(Mapping[KT, VT_co], Hashable):
         pass
 
     # PSet.add and PSet.discard have different type signatures than that of 
Set.
-    class PSet(Generic[T], Hashable):
+    class PSet(Generic[T_co], Hashable):
         pass
 
-    class PVector(Sequence[T], Hashable):
+    class PVector(Sequence[T_co], Hashable):
         pass
 
     class PVectorEvolver(Generic[T]):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/pyrsistent.egg-info/PKG-INFO 
new/pyrsistent-0.20.0/pyrsistent.egg-info/PKG-INFO
--- old/pyrsistent-0.19.3/pyrsistent.egg-info/PKG-INFO  2022-12-29 
08:51:12.000000000 +0100
+++ new/pyrsistent-0.20.0/pyrsistent.egg-info/PKG-INFO  2023-10-25 
22:54:20.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: pyrsistent
-Version: 0.19.3
+Version: 0.20.0
 Summary: Persistent/Functional/Immutable data structures
 Home-page: https://github.com/tobgu/pyrsistent/
 Author: Tobias Gustafsson
@@ -10,13 +10,13 @@
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: Implementation :: PyPy
-Requires-Python: >=3.7
+Requires-Python: >=3.8
 Description-Content-Type: text/x-rst
 License-File: LICENSE.mit
 
@@ -601,7 +601,7 @@
 Compatibility
 -------------
 
-Pyrsistent is developed and tested on Python 3.7+ and PyPy3.
+Pyrsistent is developed and tested on Python 3.8+ and PyPy3.
 
 Performance
 -----------
@@ -741,6 +741,12 @@
 
 Aaron Durant https://github.com/Aaron-Durant
 
+Joshua Munn https://github.com/jams2
+
+Lukas https://github.com/lukasK9999
+
+Arshad https://github.com/arshad-ml
+
 Contributing
 ------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/setup.py 
new/pyrsistent-0.20.0/setup.py
--- old/pyrsistent-0.19.3/setup.py      2022-12-29 08:50:58.000000000 +0100
+++ new/pyrsistent-0.20.0/setup.py      2023-10-25 22:54:06.000000000 +0200
@@ -68,11 +68,11 @@
         'Intended Audience :: Developers',
         'License :: OSI Approved :: MIT License',
         'Operating System :: OS Independent',
-        'Programming Language :: Python :: 3.7',
         'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
         'Programming Language :: Python :: 3.10',
         'Programming Language :: Python :: 3.11',
+        'Programming Language :: Python :: 3.12',
         'Programming Language :: Python :: Implementation :: PyPy',
     ],
     test_suite='tests',
@@ -83,5 +83,5 @@
     cmdclass={'build_ext': custom_build_ext},
     packages=['pyrsistent'],
     package_data={'pyrsistent': ['py.typed', '__init__.pyi', 'typing.pyi']},
-    python_requires='>=3.7',
+    python_requires='>=3.8',
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/tests/freeze_test.py 
new/pyrsistent-0.20.0/tests/freeze_test.py
--- old/pyrsistent-0.19.3/tests/freeze_test.py  2022-12-29 08:50:58.000000000 
+0100
+++ new/pyrsistent-0.20.0/tests/freeze_test.py  2023-10-25 22:54:06.000000000 
+0200
@@ -1,5 +1,5 @@
 """Tests for freeze and thaw."""
-
+import collections
 from pyrsistent import v, m, s, freeze, thaw, PRecord, field, mutant
 
 
@@ -17,6 +17,13 @@
     assert result == m(a='b')
     assert type(freeze({'a': 'b'})) is type(m())
 
+def test_freeze_defaultdict():
+    test_dict = collections.defaultdict(dict)
+    test_dict['a'] = 'b'
+    result = freeze(test_dict)
+    assert result == m(a='b')
+    assert type(freeze({'a': 'b'})) is type(m())
+
 def test_freeze_set():
     result = freeze(set([1, 2, 3]))
     assert result == s(1, 2, 3)
@@ -27,6 +34,13 @@
     assert result == m(a=v(1))
     assert type(result['a']) is type(v())
 
+def test_freeze_recurse_in_defaultdict_values():
+    test_dict = collections.defaultdict(dict)
+    test_dict['a'] = [1]
+    result = freeze(test_dict)
+    assert result == m(a=v(1))
+    assert type(result['a']) is type(v())
+
 def test_freeze_recurse_in_pmap_values():
     input = {'a': m(b={'c': 1})}
     result = freeze(input)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/tests/map_test.py 
new/pyrsistent-0.20.0/tests/map_test.py
--- old/pyrsistent-0.19.3/tests/map_test.py     2022-12-29 08:50:58.000000000 
+0100
+++ new/pyrsistent-0.20.0/tests/map_test.py     2023-10-25 22:54:06.000000000 
+0200
@@ -1,7 +1,8 @@
+from collections import namedtuple
 from collections.abc import Mapping, Hashable
 from operator import add
 import pytest
-from pyrsistent import pmap, m, PVector
+from pyrsistent import pmap, m
 import pickle
 
 
@@ -64,7 +65,7 @@
     assert {('a', 1), ('b', 2)} == set(m(a=1, b=2).iteritems())
     assert {('a', 1), ('b', 2)} == set(m(a=1, b=2).items())
 
-    pm = pmap({k:k for k in range(100)})
+    pm = pmap({k: k for k in range(100)})
     assert len(pm) == len(pm.keys())
     assert len(pm) == len(pm.values())
     assert len(pm) == len(pm.items())
@@ -72,7 +73,7 @@
     assert all(k in pm for k in ks)
     assert all(k in ks for k in ks)
     us = pm.items()
-    assert all(pm[k] == v for (k,v) in us)
+    assert all(pm[k] == v for (k, v) in us)
     vs = pm.values()
     assert all(v in vs for v in vs)
 
@@ -147,12 +148,11 @@
 
 
 class HashabilityControlled(object):
-
     hashable = True
 
     def __hash__(self):
         if self.hashable:
-            return 4 # Proven random
+            return 4  # Proven random
         raise ValueError("I am not currently hashable.")
 
 
@@ -286,7 +286,6 @@
 
 
 def test_hash_collision_is_correctly_resolved():
-
     dummy1 = HashDummy()
     dummy2 = HashDummy()
     dummy3 = HashDummy()
@@ -422,7 +421,7 @@
 
 
 def test_evolver_update_with_relocation():
-    x = pmap({'a':1000}, pre_size=1)
+    x = pmap({'a': 1000}, pre_size=1)
     e = x.evolver()
     e['b'] = 3000
     e['c'] = 4000
@@ -520,3 +519,33 @@
     """
 
     assert pmap(iter([("a", "b")])) == pmap([("a", "b")])
+
+
+class BrokenPerson(namedtuple('Person', 'name')):
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.name == other.name
+
+    def __hash__(self):
+        return hash(self.name)
+
+
+class BrokenItem(namedtuple('Item', 'name')):
+    def __eq__(self, other):
+        return self.__class__ == other.__class__ and self.name == other.name
+
+    def __hash__(self):
+        return hash(self.name)
+
+
+def test_pmap_removal_with_broken_classes_deriving_from_namedtuple():
+    """
+    The two classes above implement __eq__ but also would need to implement 
__ne__ to compare
+    consistently. See issue https://github.com/tobgu/pyrsistent/issues/268 for 
details.
+    """
+    s = pmap({BrokenPerson('X'): 2, BrokenItem('X'): 3})
+    s = s.remove(BrokenPerson('X'))
+
+    # Both items are removed due to how they are compared for inequality
+    assert BrokenPerson('X') not in s
+    assert BrokenItem('X') in s
+    assert len(s) == 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyrsistent-0.19.3/tests/transform_test.py 
new/pyrsistent-0.20.0/tests/transform_test.py
--- old/pyrsistent-0.19.3/tests/transform_test.py       2022-12-29 
08:50:58.000000000 +0100
+++ new/pyrsistent-0.20.0/tests/transform_test.py       2023-10-25 
22:54:06.000000000 +0200
@@ -115,3 +115,8 @@
 def test_transform_insert_empty_pmap():
     m = pmap().transform(['123'], pmap())
     assert m == pmap({'123': pmap()})
+
+
+def test_discard_does_not_insert_nodes():
+    m = freeze({}).transform(['foo', 'bar'], discard)
+    assert m == pmap({})

Reply via email to