New Upstream Release - pyrsistent

Ready changes

Summary

Merged new upstream version: 0.19.3 (was: 0.18.1).

Resulting package

Built on 2023-06-02T21:14 (took 4m53s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases python3-pyrsistent-dbgsymapt install -t fresh-releases python3-pyrsistent

Lintian Result

Diff

diff --git a/CHANGES.txt b/CHANGES.txt
index 6374107..70c60c6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,25 @@
 Revision history
 ----------------
+0.19.3, 2022-12-29
+ * Fix #264, add wheels and official support for Python 3.11. Thanks @hugovk for this!
+
+0.19.2, 2022-11-03
+ * Fix #263, pmap regression in 0.19.1. Element access sometimes unreliable after insert.
+   Thanks @mwchase for reporting this!
+
+0.19.1, 2022-10-30
+ * Fix #159 (through PR #243). Pmap keys/values/items now behave more like the corresponding Python 3
+   methods on dicts. Previously they returned a materialized PVector holding the items, now they return
+   views instead. This is a slight backwards incompatibility compared to previous behaviour, hence stepping
+   version to 0.19. Thanks @noahbenson for this!
+ * Fix #244, type for argument to PVector.delete missing. @thanks dscrofts for this!
+ * Fix #249, rename perf test directory to avoid tripping up automatic discovery in more recent setuptools versions
+ * Fix #247, performance bug when setting elements in maps and adding elements to sets
+ * Fix #248, build pure Python wheels. This is used by some installers. Thanks @andyreagan for this!
+ * Fix #254, #258, support manylinux_2014_aarch64 wheels. Thanks @Aaron-Durant for this!
+
+0.19.0 - Never released due to issues found on test-PyPI
+
 0.18.1, 2022-01-14
  * Add universal wheels for MacOS, thanks @ntamas for this!
  * Add support for Python 3.10, thanks @hugovk for this!
@@ -170,6 +190,7 @@ v0.11.11, 2016-01-31
 
 v0.11.10, 2015-12-27, NOTE! This release contains a backwards incompatible change
                       despite only stepping the patch version number. See below.
+
  * Implement #74, attribute access on PClass evolver
  * Implement #75, lazily evaluated invariant messages by providing a
    callable with no arguments.
diff --git a/PKG-INFO b/PKG-INFO
index e592ceb..32bd549 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,12 @@
 Metadata-Version: 2.1
 Name: pyrsistent
-Version: 0.18.1
+Version: 0.19.3
 Summary: Persistent/Functional/Immutable data structures
-Home-page: http://github.com/tobgu/pyrsistent/
+Home-page: https://github.com/tobgu/pyrsistent/
 Author: Tobias Gustafsson
 Author-email: tobias.l.gustafsson@gmail.com
 License: MIT
-Platform: UNKNOWN
+Project-URL: Changelog, https://pyrsistent.readthedocs.io/en/latest/changes.html
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
@@ -14,6 +14,7 @@ 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 :: Implementation :: PyPy
 Requires-Python: >=3.7
 Description-Content-Type: text/x-rst
@@ -25,7 +26,8 @@ Pyrsistent
     :target: https://github.com/tobgu/pyrsistent/actions/workflows/tests.yaml
 
 
-.. _Pyrthon: https://www.github.com/tobgu/pyrthon/
+.. _Pyrthon: https://www.github.com/tobgu/pyrthon
+.. _Pyrsistent_extras: https://github.com/mingmingrr/pyrsistent-extras
 
 Pyrsistent is a number of persistent collections (by some referred to as functional data structures). Persistent in
 the sense that they are immutable.
@@ -43,8 +45,13 @@ data structures are designed to share common elements through path copying.
 It aims at taking these concepts and make them as pythonic as possible so that they can be easily integrated into any python
 program without hassle.
 
-If you want to go all in on persistent data structures and use literal syntax to define them in your code rather
-than function calls check out Pyrthon_.
+If you want use literal syntax to define them in your code rather
+than function calls check out Pyrthon_. Be aware, that one is experimental, unmaintained and alpha software. 
+
+If you cannot find the persistent data structure you're looking for here you may want to take a look at
+Pyrsistent_extras_ which is maintained by @mingmingrr. If you still don't find what you're looking for please
+open an issue for discussion. If we agree that functionality is missing you may want to go ahead and create
+a Pull Request implement the missing functionality.
 
 Examples
 --------
@@ -726,6 +733,13 @@ Hugo van Kemenade https://github.com/hugovk
 
 Ben Beasley https://github.com/musicinmybrain
 
+Noah C. Benson https://github.com/noahbenson
+
+dscrofts https://github.com/dscrofts
+
+Andy Reagan https://github.com/andyreagan
+
+Aaron Durant https://github.com/Aaron-Durant
 
 Contributing
 ------------
@@ -750,7 +764,7 @@ Release
 * Update README.rst with any new contributors and potential info needed.
 * Update _pyrsistent_version.py
 * Commit and tag with new version: `git add -u . && git commit -m 'Prepare version vX.Y.Z' && git tag -a vX.Y.Z -m 'vX.Y.Z'`
-* Push commit and tags: `git push && git push --tags`
+* Push commit and tags: `git push --follow-tags`
 * Build new release using Github actions
 
 Project status
@@ -767,5 +781,3 @@ interested in working on any of them.
 If you feel that you have a grand master plan for where you would like Pyrsistent to go and have the time to put into
 it please don't hesitate to discuss this with me and submit PRs for it. If all goes well I'd be more than happy to add
 additional maintainers to the project!
-
-
diff --git a/README b/README
index 91dbb0e..1b36b4f 100644
--- a/README
+++ b/README
@@ -4,7 +4,8 @@ Pyrsistent
     :target: https://github.com/tobgu/pyrsistent/actions/workflows/tests.yaml
 
 
-.. _Pyrthon: https://www.github.com/tobgu/pyrthon/
+.. _Pyrthon: https://www.github.com/tobgu/pyrthon
+.. _Pyrsistent_extras: https://github.com/mingmingrr/pyrsistent-extras
 
 Pyrsistent is a number of persistent collections (by some referred to as functional data structures). Persistent in
 the sense that they are immutable.
@@ -22,8 +23,13 @@ data structures are designed to share common elements through path copying.
 It aims at taking these concepts and make them as pythonic as possible so that they can be easily integrated into any python
 program without hassle.
 
-If you want to go all in on persistent data structures and use literal syntax to define them in your code rather
-than function calls check out Pyrthon_.
+If you want use literal syntax to define them in your code rather
+than function calls check out Pyrthon_. Be aware, that one is experimental, unmaintained and alpha software. 
+
+If you cannot find the persistent data structure you're looking for here you may want to take a look at
+Pyrsistent_extras_ which is maintained by @mingmingrr. If you still don't find what you're looking for please
+open an issue for discussion. If we agree that functionality is missing you may want to go ahead and create
+a Pull Request implement the missing functionality.
 
 Examples
 --------
@@ -705,6 +711,13 @@ Hugo van Kemenade https://github.com/hugovk
 
 Ben Beasley https://github.com/musicinmybrain
 
+Noah C. Benson https://github.com/noahbenson
+
+dscrofts https://github.com/dscrofts
+
+Andy Reagan https://github.com/andyreagan
+
+Aaron Durant https://github.com/Aaron-Durant
 
 Contributing
 ------------
@@ -729,7 +742,7 @@ Release
 * Update README.rst with any new contributors and potential info needed.
 * Update _pyrsistent_version.py
 * Commit and tag with new version: `git add -u . && git commit -m 'Prepare version vX.Y.Z' && git tag -a vX.Y.Z -m 'vX.Y.Z'`
-* Push commit and tags: `git push && git push --tags`
+* Push commit and tags: `git push --follow-tags`
 * Build new release using Github actions
 
 Project status
diff --git a/README.rst b/README.rst
index 91dbb0e..1b36b4f 100644
--- a/README.rst
+++ b/README.rst
@@ -4,7 +4,8 @@ Pyrsistent
     :target: https://github.com/tobgu/pyrsistent/actions/workflows/tests.yaml
 
 
-.. _Pyrthon: https://www.github.com/tobgu/pyrthon/
+.. _Pyrthon: https://www.github.com/tobgu/pyrthon
+.. _Pyrsistent_extras: https://github.com/mingmingrr/pyrsistent-extras
 
 Pyrsistent is a number of persistent collections (by some referred to as functional data structures). Persistent in
 the sense that they are immutable.
@@ -22,8 +23,13 @@ data structures are designed to share common elements through path copying.
 It aims at taking these concepts and make them as pythonic as possible so that they can be easily integrated into any python
 program without hassle.
 
-If you want to go all in on persistent data structures and use literal syntax to define them in your code rather
-than function calls check out Pyrthon_.
+If you want use literal syntax to define them in your code rather
+than function calls check out Pyrthon_. Be aware, that one is experimental, unmaintained and alpha software. 
+
+If you cannot find the persistent data structure you're looking for here you may want to take a look at
+Pyrsistent_extras_ which is maintained by @mingmingrr. If you still don't find what you're looking for please
+open an issue for discussion. If we agree that functionality is missing you may want to go ahead and create
+a Pull Request implement the missing functionality.
 
 Examples
 --------
@@ -705,6 +711,13 @@ Hugo van Kemenade https://github.com/hugovk
 
 Ben Beasley https://github.com/musicinmybrain
 
+Noah C. Benson https://github.com/noahbenson
+
+dscrofts https://github.com/dscrofts
+
+Andy Reagan https://github.com/andyreagan
+
+Aaron Durant https://github.com/Aaron-Durant
 
 Contributing
 ------------
@@ -729,7 +742,7 @@ Release
 * Update README.rst with any new contributors and potential info needed.
 * Update _pyrsistent_version.py
 * Commit and tag with new version: `git add -u . && git commit -m 'Prepare version vX.Y.Z' && git tag -a vX.Y.Z -m 'vX.Y.Z'`
-* Push commit and tags: `git push && git push --tags`
+* Push commit and tags: `git push --follow-tags`
 * Build new release using Github actions
 
 Project status
diff --git a/_pyrsistent_version.py b/_pyrsistent_version.py
index 5877c8d..b699138 100644
--- a/_pyrsistent_version.py
+++ b/_pyrsistent_version.py
@@ -1 +1 @@
-__version__ = '0.18.1'
+__version__ = '0.19.3'
diff --git a/debian/changelog b/debian/changelog
index 04c0ff2..892980d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+pyrsistent (0.19.3-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Fri, 02 Jun 2023 21:10:02 -0000
+
 pyrsistent (0.18.1-1) unstable; urgency=medium
 
   [ Ondřej Nový ]
diff --git a/pyrsistent.egg-info/PKG-INFO b/pyrsistent.egg-info/PKG-INFO
index e592ceb..32bd549 100644
--- a/pyrsistent.egg-info/PKG-INFO
+++ b/pyrsistent.egg-info/PKG-INFO
@@ -1,12 +1,12 @@
 Metadata-Version: 2.1
 Name: pyrsistent
-Version: 0.18.1
+Version: 0.19.3
 Summary: Persistent/Functional/Immutable data structures
-Home-page: http://github.com/tobgu/pyrsistent/
+Home-page: https://github.com/tobgu/pyrsistent/
 Author: Tobias Gustafsson
 Author-email: tobias.l.gustafsson@gmail.com
 License: MIT
-Platform: UNKNOWN
+Project-URL: Changelog, https://pyrsistent.readthedocs.io/en/latest/changes.html
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
@@ -14,6 +14,7 @@ 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 :: Implementation :: PyPy
 Requires-Python: >=3.7
 Description-Content-Type: text/x-rst
@@ -25,7 +26,8 @@ Pyrsistent
     :target: https://github.com/tobgu/pyrsistent/actions/workflows/tests.yaml
 
 
-.. _Pyrthon: https://www.github.com/tobgu/pyrthon/
+.. _Pyrthon: https://www.github.com/tobgu/pyrthon
+.. _Pyrsistent_extras: https://github.com/mingmingrr/pyrsistent-extras
 
 Pyrsistent is a number of persistent collections (by some referred to as functional data structures). Persistent in
 the sense that they are immutable.
@@ -43,8 +45,13 @@ data structures are designed to share common elements through path copying.
 It aims at taking these concepts and make them as pythonic as possible so that they can be easily integrated into any python
 program without hassle.
 
-If you want to go all in on persistent data structures and use literal syntax to define them in your code rather
-than function calls check out Pyrthon_.
+If you want use literal syntax to define them in your code rather
+than function calls check out Pyrthon_. Be aware, that one is experimental, unmaintained and alpha software. 
+
+If you cannot find the persistent data structure you're looking for here you may want to take a look at
+Pyrsistent_extras_ which is maintained by @mingmingrr. If you still don't find what you're looking for please
+open an issue for discussion. If we agree that functionality is missing you may want to go ahead and create
+a Pull Request implement the missing functionality.
 
 Examples
 --------
@@ -726,6 +733,13 @@ Hugo van Kemenade https://github.com/hugovk
 
 Ben Beasley https://github.com/musicinmybrain
 
+Noah C. Benson https://github.com/noahbenson
+
+dscrofts https://github.com/dscrofts
+
+Andy Reagan https://github.com/andyreagan
+
+Aaron Durant https://github.com/Aaron-Durant
 
 Contributing
 ------------
@@ -750,7 +764,7 @@ Release
 * Update README.rst with any new contributors and potential info needed.
 * Update _pyrsistent_version.py
 * Commit and tag with new version: `git add -u . && git commit -m 'Prepare version vX.Y.Z' && git tag -a vX.Y.Z -m 'vX.Y.Z'`
-* Push commit and tags: `git push && git push --tags`
+* Push commit and tags: `git push --follow-tags`
 * Build new release using Github actions
 
 Project status
@@ -767,5 +781,3 @@ interested in working on any of them.
 If you feel that you have a grand master plan for where you would like Pyrsistent to go and have the time to put into
 it please don't hesitate to discuss this with me and submit PRs for it. If all goes well I'd be more than happy to add
 additional maintainers to the project!
-
-
diff --git a/pyrsistent/_immutable.py b/pyrsistent/_immutable.py
index 7c75945..d23deca 100644
--- a/pyrsistent/_immutable.py
+++ b/pyrsistent/_immutable.py
@@ -60,14 +60,9 @@ def immutable(members='', name='Immutable', verbose=False):
 
         return ''
 
-    verbose_string = ""
-    if sys.version_info < (3, 7):
-        # Verbose is no longer supported in Python 3.7
-        verbose_string = ", verbose={verbose}".format(verbose=verbose)
-
     quoted_members = ', '.join("'%s'" % m for m in members)
     template = """
-class {class_name}(namedtuple('ImmutableBase', [{quoted_members}]{verbose_string})):
+class {class_name}(namedtuple('ImmutableBase', [{quoted_members}])):
     __slots__ = tuple()
 
     def __repr__(self):
@@ -87,7 +82,6 @@ class {class_name}(namedtuple('ImmutableBase', [{quoted_members}]{verbose_string
 """.format(quoted_members=quoted_members,
                member_set="set([%s])" % quoted_members if quoted_members else 'set()',
                frozen_member_test=frozen_member_test(),
-               verbose_string=verbose_string,
                class_name=name)
 
     if verbose:
diff --git a/pyrsistent/_pmap.py b/pyrsistent/_pmap.py
index 056d478..c6c7c7f 100644
--- a/pyrsistent/_pmap.py
+++ b/pyrsistent/_pmap.py
@@ -3,6 +3,105 @@ from itertools import chain
 from pyrsistent._pvector import pvector
 from pyrsistent._transformations import transform
 
+class PMapView:
+    """View type for the persistent map/dict type `PMap`.
+
+    Provides an equivalent of Python's built-in `dict_values` and `dict_items`
+    types that result from expreessions such as `{}.values()` and
+    `{}.items()`. The equivalent for `{}.keys()` is absent because the keys are
+    instead represented by a `PSet` object, which can be created in `O(1)` time.
+
+    The `PMapView` class is overloaded by the `PMapValues` and `PMapItems`
+    classes which handle the specific case of values and items, respectively
+
+    Parameters
+    ----------
+    m : mapping
+        The mapping/dict-like object of which a view is to be created. This
+        should generally be a `PMap` object.
+    """
+    # The public methods that use the above.
+    def __init__(self, m):
+        # Make sure this is a persistnt map
+        if not isinstance(m, PMap):
+            # We can convert mapping objects into pmap objects, I guess (but why?)
+            if isinstance(m, Mapping):
+                m = pmap(m)
+            else:
+                raise TypeError("PViewMap requires a Mapping object")
+        object.__setattr__(self, '_map', m)
+
+    def __len__(self):
+        return len(self._map)
+
+    def __setattr__(self, k, v):
+        raise TypeError("%s is immutable" % (type(self),))
+
+    def __reversed__(self):
+        raise TypeError("Persistent maps are not reversible")
+
+class PMapValues(PMapView):
+    """View type for the values of the persistent map/dict type `PMap`.
+
+    Provides an equivalent of Python's built-in `dict_values` type that result
+    from expreessions such as `{}.values()`. See also `PMapView`.
+
+    Parameters
+    ----------
+    m : mapping
+        The mapping/dict-like object of which a view is to be created. This
+        should generally be a `PMap` object.
+    """
+    def __iter__(self):
+        return self._map.itervalues()
+
+    def __contains__(self, arg):
+        return arg in self._map.itervalues()
+
+    # The str and repr methods imitate the dict_view style currently.
+    def __str__(self):
+        return f"pmap_values({list(iter(self))})"
+    
+    def __repr__(self):
+        return f"pmap_values({list(iter(self))})"
+    
+    def __eq__(self, x):
+        # For whatever reason, dict_values always seem to return False for ==
+        # (probably it's not implemented), so we mimic that.
+        if x is self: return True
+        else: return False
+    
+class PMapItems(PMapView):
+    """View type for the items of the persistent map/dict type `PMap`.
+
+    Provides an equivalent of Python's built-in `dict_items` type that result
+    from expreessions such as `{}.items()`. See also `PMapView`.
+
+    Parameters
+    ----------
+    m : mapping
+        The mapping/dict-like object of which a view is to be created. This
+        should generally be a `PMap` object.
+    """
+    def __iter__(self):
+        return self._map.iteritems()
+
+    def __contains__(self, arg):
+        try: (k,v) = arg
+        except Exception: return False
+        return k in self._map and self._map[k] == v
+
+    # The str and repr methods mitate the dict_view style currently.
+    def __str__(self):
+        return f"pmap_items({list(iter(self))})"
+    
+    def __repr__(self):
+        return f"pmap_items({list(iter(self))})"
+        
+    def __eq__(self, x):
+        if x is self: return True
+        elif not isinstance(x, type(self)): return False
+        else: return self._map == x._map
 
 class PMap(object):
     """
@@ -89,6 +188,12 @@ class PMap(object):
     def __iter__(self):
         return self.iterkeys()
 
+    # If this method is not defined, then reversed(pmap) will attempt to reverse
+    # the map using len() and getitem, usually resulting in a mysterious
+    # KeyError.
+    def __reversed__(self):
+        raise TypeError("Persistent maps are not reversible")
+
     def __getattr__(self, key):
         try:
             return self[key]
@@ -115,13 +220,14 @@ class PMap(object):
                     yield k, v
 
     def values(self):
-        return pvector(self.itervalues())
+        return PMapValues(self)
 
     def keys(self):
-        return pvector(self.iterkeys())
+        from ._pset import PSet
+        return PSet(self)
 
     def items(self):
-        return pvector(self.iteritems())
+        return PMapItems(self)
 
     def __len__(self):
         return self._size
@@ -296,11 +402,9 @@ class PMap(object):
             self.set(key, val)
 
         def set(self, key, val):
-            if len(self._buckets_evolver) < 0.67 * self._size:
-                self._reallocate(2 * len(self._buckets_evolver))
-
             kv = (key, val)
             index, bucket = PMap._get_bucket(self._buckets_evolver, key)
+            reallocation_required = len(self._buckets_evolver) < 0.67 * self._size
             if bucket:
                 for k, v in bucket:
                     if k == key:
@@ -310,17 +414,28 @@ class PMap(object):
 
                         return self
 
+                # Only check and perform reallocation if not replacing an existing value.
+                # This is a performance tweak, see #247.
+                if reallocation_required:
+                    self._reallocate()
+                    return self.set(key, val)
+
                 new_bucket = [kv]
                 new_bucket.extend(bucket)
                 self._buckets_evolver[index] = new_bucket
                 self._size += 1
             else:
+                if reallocation_required:
+                    self._reallocate()
+                    return self.set(key, val)
+
                 self._buckets_evolver[index] = [kv]
                 self._size += 1
 
             return self
 
-        def _reallocate(self, new_size):
+        def _reallocate(self):
+            new_size = 2 * len(self._buckets_evolver)
             new_list = new_size * [None]
             buckets = self._buckets_evolver.persistent()
             for k, v in chain.from_iterable(x for x in buckets if x):
diff --git a/pyrsistent/_toolz.py b/pyrsistent/_toolz.py
index a7faed1..0bf2cb1 100644
--- a/pyrsistent/_toolz.py
+++ b/pyrsistent/_toolz.py
@@ -4,7 +4,7 @@ to add toolz as a dependency.
 
 See https://github.com/pytoolz/toolz/.
 
-toolz is relased under BSD licence. Below is the licence text
+toolz is released under BSD licence. Below is the licence text
 from toolz as it appeared when copying the code.
 
 --------------------------------------------------------------
@@ -72,7 +72,7 @@ def get_in(keys, coll, default=None, no_default=False):
     0
     >>> get_in(['y'], {}, no_default=True)
     Traceback (most recent call last):
-        ...
+    ...
     KeyError: 'y'
     """
     try:
diff --git a/pyrsistent/typing.pyi b/pyrsistent/typing.pyi
index 0221c48..801dc70 100644
--- a/pyrsistent/typing.pyi
+++ b/pyrsistent/typing.pyi
@@ -68,7 +68,7 @@ class PVector(Sequence[T], Hashable):
     def __len__(self) -> int: ...
     def __mul__(self, other: PVector[T]) -> PVector[T]: ...
     def append(self, val: T) -> PVector[T]: ...
-    def delete(self, index: int, stop: Optional[int]) -> PVector[T]: ...
+    def delete(self, index: int, stop: Optional[int] = None) -> PVector[T]: ...
     def evolver(self) -> PVectorEvolver[T]: ...
     def extend(self, obj: Iterable[T]) -> PVector[T]: ...
     def tolist(self) -> List[T]: ...
diff --git a/setup.py b/setup.py
index c87058f..6777c8c 100644
--- a/setup.py
+++ b/setup.py
@@ -15,7 +15,7 @@ else:
     readme = "Persistent collections, see https://github.com/tobgu/pyrsistent/ for details."
 
 extensions = []
-if platform.python_implementation() == 'CPython':
+if platform.python_implementation() == 'CPython' and os.getenv("PYRSISTENT_SKIP_EXTENSION") is None:
     extensions = [Extension('pvectorc', sources=['pvectorcmodule.c'])]
 
 needs_pytest = {'pytest', 'test', 'ptr'}.intersection(sys.argv)
@@ -57,7 +57,10 @@ setup(
     long_description_content_type='text/x-rst',
     author='Tobias Gustafsson',
     author_email='tobias.l.gustafsson@gmail.com',
-    url='http://github.com/tobgu/pyrsistent/',
+    url='https://github.com/tobgu/pyrsistent/',
+    project_urls={
+        'Changelog': 'https://pyrsistent.readthedocs.io/en/latest/changes.html',
+    },
     license='MIT',
     license_files=['LICENSE.mit'],
     py_modules=['_pyrsistent_version'],
@@ -69,6 +72,7 @@ setup(
         'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
         'Programming Language :: Python :: 3.10',
+        'Programming Language :: Python :: 3.11',
         'Programming Language :: Python :: Implementation :: PyPy',
     ],
     test_suite='tests',
diff --git a/tests/map_test.py b/tests/map_test.py
index 982bd11..8ca8eed 100644
--- a/tests/map_test.py
+++ b/tests/map_test.py
@@ -4,6 +4,7 @@ import pytest
 from pyrsistent import pmap, m, PVector
 import pickle
 
+
 def test_instance_of_hashable():
     assert isinstance(m(), Hashable)
 
@@ -18,8 +19,8 @@ def test_literalish_works():
 
 
 def test_empty_initialization():
-    map = pmap()
-    assert len(map) == 0
+    a_map = pmap()
+    assert len(a_map) == 0
 
 
 def test_initialization_with_one_element():
@@ -54,26 +55,35 @@ def test_remove_non_existing_element_raises_key_error():
 
 
 def test_various_iterations():
-    assert set(['a', 'b']) == set(m(a=1, b=2))
+    assert {'a', 'b'} == set(m(a=1, b=2))
     assert ['a', 'b'] == sorted(m(a=1, b=2).keys())
-    assert isinstance(m().keys(), PVector)
 
-    assert set([1, 2]) == set(m(a=1, b=2).itervalues())
+    assert {1, 2} == set(m(a=1, b=2).itervalues())
     assert [1, 2] == sorted(m(a=1, b=2).values())
-    assert isinstance(m().values(), PVector)
 
-    assert set([('a', 1), ('b', 2)]) == set(m(a=1, b=2).iteritems())
-    assert set([('a', 1), ('b', 2)]) == set(m(a=1, b=2).items())
-    assert isinstance(m().items(), PVector)
+    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)})
+    assert len(pm) == len(pm.keys())
+    assert len(pm) == len(pm.values())
+    assert len(pm) == len(pm.items())
+    ks = pm.keys()
+    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)
+    vs = pm.values()
+    assert all(v in vs for v in vs)
 
 
 def test_initialization_with_two_elements():
-    map = pmap({'a': 2, 'b': 3})
-    assert len(map) == 2
-    assert map['a'] == 2
-    assert map['b'] == 3
+    map1 = pmap({'a': 2, 'b': 3})
+    assert len(map1) == 2
+    assert map1['a'] == 2
+    assert map1['b'] == 3
 
-    map2 = map.remove('a')
+    map2 = map1.remove('a')
     assert 'a' not in map2
     assert map2['b'] == 3
 
@@ -243,9 +253,11 @@ def test_update_no_arguments():
 def test_addition():
     assert m(x=1, y=2) + m(y=3, z=4) == m(x=1, y=3, z=4)
 
+
 def test_union_operator():
     assert m(x=1, y=2) | m(y=3, z=4) == m(x=1, y=3, z=4)
 
+
 def test_transform_base_case():
     # Works as set when called with only one key
     x = m(a=1, b=2)
@@ -280,39 +292,39 @@ def test_hash_collision_is_correctly_resolved():
     dummy3 = HashDummy()
     dummy4 = HashDummy()
 
-    map = pmap({dummy1: 1, dummy2: 2, dummy3: 3})
-    assert map[dummy1] == 1
-    assert map[dummy2] == 2
-    assert map[dummy3] == 3
-    assert dummy4 not in map
+    map1 = pmap({dummy1: 1, dummy2: 2, dummy3: 3})
+    assert map1[dummy1] == 1
+    assert map1[dummy2] == 2
+    assert map1[dummy3] == 3
+    assert dummy4 not in map1
 
     keys = set()
     values = set()
-    for k, v in map.iteritems():
+    for k, v in map1.iteritems():
         keys.add(k)
         values.add(v)
 
-    assert keys == set([dummy1, dummy2, dummy3])
-    assert values == set([1, 2, 3])
+    assert keys == {dummy1, dummy2, dummy3}
+    assert values == {1, 2, 3}
 
-    map2 = map.set(dummy1, 11)
+    map2 = map1.set(dummy1, 11)
     assert map2[dummy1] == 11
 
     # Re-use existing structure when inserted element is the same
     assert map2.set(dummy1, 11) is map2
 
-    map3 = map.set('a', 22)
+    map3 = map1.set('a', 22)
     assert map3['a'] == 22
     assert map3[dummy3] == 3
 
     # Remove elements
-    map4 = map.discard(dummy2)
+    map4 = map1.discard(dummy2)
     assert len(map4) == 2
     assert map4[dummy1] == 1
     assert dummy2 not in map4
     assert map4[dummy3] == 3
 
-    assert map.discard(dummy4) is map
+    assert map1.discard(dummy4) is map1
 
     # Empty map handling
     empty_map = map4.remove(dummy1).remove(dummy3)
@@ -321,19 +333,19 @@ def test_hash_collision_is_correctly_resolved():
 
 
 def test_bitmap_indexed_iteration():
-    map = pmap({'a': 2, 'b': 1})
+    a_map = pmap({'a': 2, 'b': 1})
     keys = set()
     values = set()
 
     count = 0
-    for k, v in map.iteritems():
+    for k, v in a_map.iteritems():
         count += 1
         keys.add(k)
         values.add(v)
 
     assert count == 2
-    assert keys == set(['a', 'b'])
-    assert values == set([2, 1])
+    assert keys == {'a', 'b'}
+    assert values == {2, 1}
 
 
 def test_iteration_with_many_elements():
@@ -348,12 +360,12 @@ def test_iteration_with_many_elements():
     # those properly as well
     init_dict[hash_dummy1] = 12345
     init_dict[hash_dummy2] = 54321
-    map = pmap(init_dict)
+    a_map = pmap(init_dict)
 
     actual_values = set()
     actual_keys = set()
 
-    for k, v in map.iteritems():
+    for k, v in a_map.iteritems():
         actual_values.add(v)
         actual_keys.add(k)
 
@@ -369,6 +381,7 @@ def test_empty_truthiness():
     assert m(a=1)
     assert not m()
 
+
 def test_update_with():
     assert m(a=1).update_with(add, m(a=2, b=4)) == m(a=3, b=4)
     assert m(a=1).update_with(lambda l, r: l, m(a=2, b=4)) == m(a=1, b=4)
@@ -388,7 +401,7 @@ def test_pickling_non_empty_map():
 
 
 def test_set_with_relocation():
-    x = pmap({'a':1000}, pre_size=1)
+    x = pmap({'a': 1000}, pre_size=1)
     x = x.set('b', 3000)
     x = x.set('c', 4000)
     x = x.set('d', 5000)
@@ -490,6 +503,17 @@ def test_supports_weakref():
     weakref.ref(m(a=1))
 
 
+def test_insert_and_get_many_elements():
+    # This test case triggers reallocation of the underlying bucket structure.
+    a_map = m()
+    for x in range(1000):
+        a_map = a_map.set(str(x), x)
+
+    assert len(a_map) == 1000
+    for x in range(1000):
+        assert a_map[str(x)] == x, x
+
+
 def test_iterable():
     """
     PMaps can be created from iterables even though they can't be len() hinted.

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/lib/debug/.build-id/62/ac110ad35b2d7196bf49533560343ef91acd76.debug
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/pvectorc.cpython-311-x86_64-linux-gnu.so
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/pyrsistent-0.19.3.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/pyrsistent-0.19.3.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/pyrsistent-0.19.3.egg-info/top_level.txt

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/debug/.build-id/8b/86795a7ea3256763ecef560609f0cf0104726a.debug
-rw-r--r--  root/root   /usr/lib/debug/.build-id/a8/08ea030ba5d2ddc185ccb0b1fa6623f9adce86.debug
-rw-r--r--  root/root   /usr/lib/debug/.dwz/x86_64-linux-gnu/python3-pyrsistent.debug
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/pvectorc.cpython-310-x86_64-linux-gnu.so
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/pvectorc.cpython-39-x86_64-linux-gnu.so
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/pyrsistent-0.18.1.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/pyrsistent-0.18.1.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/pyrsistent-0.18.1.egg-info/top_level.txt

Control files of package python3-pyrsistent: lines which differ (wdiff format)

  • Depends: python3 (<< 3.11), 3.12), python3 (>= 3.9~), 3.11~), python3:any, libc6 (>= 2.14)

Control files of package python3-pyrsistent-dbgsym: lines which differ (wdiff format)

  • Build-Ids: 8b86795a7ea3256763ecef560609f0cf0104726a a808ea030ba5d2ddc185ccb0b1fa6623f9adce86 62ac110ad35b2d7196bf49533560343ef91acd76

More details

Full run details