diff mercurial/thirdparty/jaraco/collections.py @ 50408:82e5a9b1ef1e

extras: re-use Projection from jaraco.collections
author Jason R. Coombs <jaraco@jaraco.com>
date Tue, 21 Mar 2023 20:47:30 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/thirdparty/jaraco/collections.py	Tue Mar 21 20:47:30 2023 -0400
@@ -0,0 +1,56 @@
+# adapted from jaraco.collections 3.9
+
+import collections
+
+
+class Projection(collections.abc.Mapping):
+    """
+    Project a set of keys over a mapping
+
+    >>> sample = {'a': 1, 'b': 2, 'c': 3}
+    >>> prj = Projection(['a', 'c', 'd'], sample)
+    >>> prj == {'a': 1, 'c': 3}
+    True
+
+    Keys should only appear if they were specified and exist in the space.
+
+    >>> sorted(list(prj.keys()))
+    ['a', 'c']
+
+    Attempting to access a key not in the projection
+    results in a KeyError.
+
+    >>> prj['b']
+    Traceback (most recent call last):
+    ...
+    KeyError: 'b'
+
+    Use the projection to update another dict.
+
+    >>> target = {'a': 2, 'b': 2}
+    >>> target.update(prj)
+    >>> target == {'a': 1, 'b': 2, 'c': 3}
+    True
+
+    Also note that Projection keeps a reference to the original dict, so
+    if you modify the original dict, that could modify the Projection.
+
+    >>> del sample['a']
+    >>> dict(prj)
+    {'c': 3}
+    """
+
+    def __init__(self, keys, space):
+        self._keys = tuple(keys)
+        self._space = space
+
+    def __getitem__(self, key):
+        if key not in self._keys:
+            raise KeyError(key)
+        return self._space[key]
+
+    def __iter__(self):
+        return iter(set(self._keys).intersection(self._space))
+
+    def __len__(self):
+        return len(tuple(iter(self)))