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({})