nested-mapping 0.12.1__tar.gz → 0.13.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/CHANGELOG.md +10 -2
  2. {nested_mapping-0.12.1/src/nested_mapping.egg-info → nested_mapping-0.13.1}/PKG-INFO +1 -1
  3. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/__version__.py +3 -3
  4. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/tools/map.py +55 -20
  5. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/tools/match.py +26 -18
  6. {nested_mapping-0.12.1 → nested_mapping-0.13.1/src/nested_mapping.egg-info}/PKG-INFO +1 -1
  7. nested_mapping-0.13.1/src/nested_mapping.egg-info/scm_version.json +8 -0
  8. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/tests/test_map.py +45 -0
  9. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/tests/test_match.py +188 -37
  10. nested_mapping-0.12.1/src/nested_mapping.egg-info/scm_version.json +0 -8
  11. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/.flake8 +0 -0
  12. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/.gitignore +0 -0
  13. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/.gitlab-ci.yml +0 -0
  14. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/CONTRIBUTING.md +0 -0
  15. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/LICENSE +0 -0
  16. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/README.md +0 -0
  17. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/conftest.py +0 -0
  18. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/pyproject.toml +0 -0
  19. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/pytest.ini +0 -0
  20. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/setup.cfg +0 -0
  21. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/__init__.py +0 -0
  22. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/class_wrapper.py +0 -0
  23. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/ipython.py +0 -0
  24. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/nested_mapping.py +0 -0
  25. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/nested_mapping_access.py +0 -0
  26. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/tools/__init__.py +0 -0
  27. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/tools/filter.py +0 -0
  28. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/tools/reorder_key.py +0 -0
  29. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/typing.py +0 -0
  30. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping/visitor.py +0 -0
  31. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping.egg-info/SOURCES.txt +0 -0
  32. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping.egg-info/dependency_links.txt +0 -0
  33. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping.egg-info/requires.txt +0 -0
  34. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping.egg-info/scm_file_list.json +0 -0
  35. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/src/nested_mapping.egg-info/top_level.txt +0 -0
  36. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/tests/test_filter.py +0 -0
  37. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/tests/test_nested_mapping.py +0 -0
  38. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/tests/test_nested_mapping_update.py +0 -0
  39. {nested_mapping-0.12.1 → nested_mapping-0.13.1}/tests/test_visitor.py +0 -0
@@ -5,10 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/).
7
7
 
8
+ ## [0.13.1] - 2026-11-03
9
+
10
+ - hotfix: print works only with `verbose` mode.
11
+
12
+ ## [0.13.0] - 2026-11-03
13
+
14
+ - feature: enable `remap_keys` and `make_reorder_fcn` to insert extra levels of nesting.
15
+ Should be enabled explicitly via `allow_insert_items`.
16
+
8
17
  ## [0.12.1] - 2026-10-29
9
18
 
10
- - fix: update check between of left-handed keys and indices in right-handed keys in `match_keys_to_key`
11
- - refactor: update code of `match_keys_to_key`
19
+ - feature: extra protection for `match_keys` to avoid keys being skipped. Can be disabled.
12
20
 
13
21
  ## [0.12.0] - 2026-10-01
14
22
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nested-mapping
3
- Version: 0.12.1
3
+ Version: 0.13.1
4
4
  Summary: A wrapper and a toolkit for working with nested mappings in Python
5
5
  Author-email: DAGModelling Team <dagflow@jinr.ru>
6
6
  Maintainer-email: DAGModelling Team <dagflow@jinr.ru>
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.12.1'
22
- __version_tuple__ = version_tuple = (0, 12, 1)
21
+ __version__ = version = '0.13.1'
22
+ __version_tuple__ = version_tuple = (0, 13, 1)
23
23
 
24
- __commit_id__ = commit_id = 'g70b286d13'
24
+ __commit_id__ = commit_id = 'gb3fd43ba6'
@@ -52,11 +52,12 @@ def remap_items(
52
52
  | tuple[tuple[str, ...], tuple[str, ...]]
53
53
  | list[int]
54
54
  | list[list[str]]
55
- | Mapping[str, list[str] | tuple[str]]
55
+ | Mapping[str, list[str] | tuple[str, ...]]
56
56
  | None
57
57
  ) = None,
58
58
  skip_indices_source: Sequence[KeyLike | set] | None = None,
59
59
  skip_indices_target: Sequence[KeyLike | set] | None = None,
60
+ allow_insert_items: bool = False,
60
61
  fcn: Callable[[Any], Any] | None = None,
61
62
  verbose: bool = False,
62
63
  ) -> NestedMapping:
@@ -67,7 +68,7 @@ def remap_items(
67
68
 
68
69
  skip_source = _make_skip_fcn(skip_indices_source)
69
70
  skip_target = _make_skip_fcn(skip_indices_target)
70
- reorder = make_reorder_function(reorder_indices)
71
+ reorder = make_reorder_function(reorder_indices, allow_insert_items=allow_insert_items)
71
72
 
72
73
  if fcn is None:
73
74
  fcn = lambda o: o
@@ -79,15 +80,11 @@ def remap_items(
79
80
  for key, value in source.walkitems():
80
81
  if skip_source(key):
81
82
  continue
82
- for newkey in product(
83
- *tuple(rename_indices.get(skey, (skey,)) for skey in key)
84
- ):
83
+ for newkey in product(*tuple(rename_indices.get(skey, (skey,)) for skey in key)):
85
84
  newkey_ordered = reorder(newkey)
86
85
  if skip_target(newkey_ordered):
87
86
  if verbose:
88
- print(
89
- f"remap: skip {'.'.join(key)} → {'.'.join(newkey_ordered)}"
90
- )
87
+ print(f"remap: skip {'.'.join(key)} → {'.'.join(newkey_ordered)}")
91
88
  continue
92
89
  if verbose:
93
90
  print(
@@ -96,6 +93,10 @@ def remap_items(
96
93
  target[newkey_ordered] = fcn(value)
97
94
  else:
98
95
  for key, value in source.walkitems():
96
+ if skip_source(key):
97
+ if verbose:
98
+ print(f"remap: skip {'.'.join(key)}")
99
+ continue
99
100
  newkey_ordered = reorder(key)
100
101
  if skip_target(newkey_ordered):
101
102
  if verbose:
@@ -128,39 +129,73 @@ def make_reorder_function(
128
129
  | tuple[tuple[str, ...], tuple[str, ...]]
129
130
  | Sequence[int]
130
131
  | Sequence[Sequence[str]]
131
- | Mapping[str, list[str] | tuple[str]]
132
+ | Mapping[str, list[str] | tuple[str, ...]]
132
133
  | None
133
134
  ),
134
135
  *,
135
136
  allow_skip_items: bool = False,
137
+ allow_insert_items: bool = False,
136
138
  ) -> Callable:
139
+ order_from_extended: list[None | str] = []
137
140
  match reorder_indices:
138
141
  case [int(), *_]:
139
- index_order = reorder_indices
142
+ index_order = list(reorder_indices)
140
143
  len_from = len(index_order)
144
+
145
+ match_length_from = not allow_skip_items
146
+
147
+ if allow_insert_items:
148
+ raise ValueError(
149
+ "make_reorder_function: inserting items is forbidden with tuple[int] arguments"
150
+ )
141
151
  case [[str(), *_] as order_from, [str(), *_] as order_to] | {
142
152
  "from": [str(), *_] as order_from,
143
153
  "to": [str(), *_] as order_to,
144
154
  }:
155
+ match_length_from = True
156
+
145
157
  len_from = len(order_from)
146
- try:
147
- index_order = tuple(order_from.index(item) for item in order_to)
148
- except ValueError:
149
- raise ValueError(
150
- f"Inconsistent order definitions {order_from} and {order_to}"
151
- )
158
+ if allow_insert_items:
159
+ order_from_extended: list[None | str] = [None] * len(order_from)
160
+ index_order: list[None | int] = [None] * len(order_to)
161
+ not_processed_indices = set(range(len(order_from)))
162
+ for i, name in enumerate(order_to):
163
+ try:
164
+ index = order_from.index(name)
165
+ not_processed_indices.remove(index)
166
+ except ValueError:
167
+ index = len(order_from_extended)
168
+ order_from_extended.append(name)
169
+ index_order[i] = index
170
+
171
+ if not_processed_indices and not allow_skip_items:
172
+ raise ValueError(
173
+ f"Inconsistent order definitions (can not skip) {order_from}→{order_to}"
174
+ )
175
+ else:
176
+ try:
177
+ index_order = list(order_from.index(item) for item in order_to)
178
+ except ValueError:
179
+ raise ValueError(
180
+ f"Inconsistent order definitions (can neigher skip no insert) {order_from}→{order_to}"
181
+ )
182
+
152
183
  case None:
153
184
  len_from = None
185
+ match_length_from = False
154
186
  allow_skip_items = True
155
187
  return lambda key: key
156
188
  case _:
157
189
  raise ValueError(f"Invalid order specification: {reorder_indices}")
158
190
 
159
191
  def reorder_indices_fcn(key: Sequence):
160
- if not allow_skip_items and len(key) != len_from:
161
- raise ValueError(
162
- f"inconsistent index length: {len(index_order)} vs required {len(key)}"
192
+ if match_length_from and len(key) != len_from:
193
+ raise ValueError(f"inconsistent key length: {len(key)} vs required {len_from}")
194
+ if allow_insert_items:
195
+ return key.__class__(
196
+ key[idx] if idx < len(key) else order_from_extended[idx] for idx in index_order
163
197
  )
164
- return key.__class__(key[idx] for idx in index_order)
198
+ else:
199
+ return key.__class__(key[idx] for idx in index_order)
165
200
 
166
201
  return reorder_indices_fcn
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from contextlib import suppress
4
- from typing import TYPE_CHECKING, Any
4
+ from typing import Any, TYPE_CHECKING, TypeVar
5
5
 
6
6
  from ordered_set import OrderedSet
7
7
 
@@ -10,30 +10,36 @@ from ..typing import Key, KeyLike, TupleKey, properkey, setkey
10
10
  if TYPE_CHECKING:
11
11
  from collections.abc import Callable, Iterable, Sequence
12
12
 
13
+ SetType = TypeVar("SetType", set[str], OrderedSet[str])
13
14
 
14
- def set_keys_consistent_symmetric(
15
- set_key_left: set | OrderedSet, set_key_right: set | OrderedSet
15
+
16
+ def set_keys_consistent_ordered(
17
+ set_key_left: OrderedSet[str], set_key_right: OrderedSet[str]
16
18
  ) -> bool:
19
+ return set_key_left == set_key_right
20
+
21
+
22
+ def set_keys_consistent_unordered(set_key_left: SetType, set_key_right: SetType) -> bool:
23
+ return not set_key_left.symmetric_difference(set_key_right)
24
+
25
+
26
+ def set_keys_consistent_symmetric(set_key_left: SetType, set_key_right: SetType) -> bool:
17
27
  return set_key_left.issubset(set_key_right) or set_key_right.issubset(set_key_left)
18
28
 
19
29
 
20
- def set_keys_consistent_left_in_right(
21
- set_key_left: set | OrderedSet, set_key_right: set | OrderedSet
22
- ) -> bool:
30
+ def set_keys_consistent_left_in_right(set_key_left: SetType, set_key_right: SetType) -> bool:
23
31
  return set_key_left.issubset(set_key_right)
24
32
 
25
33
 
26
- def set_keys_consistent_right_in_left(
27
- set_key_left: set | OrderedSet, set_key_right: set | OrderedSet
28
- ) -> bool:
34
+ def set_keys_consistent_right_in_left(set_key_left: SetType, set_key_right: SetType) -> bool:
29
35
  return set_key_right.issubset(set_key_left)
30
36
 
31
37
 
32
38
  def match_keys_to_key(
33
39
  keys_left: Sequence[KeyLike],
34
40
  key_right_tuple: TupleKey,
35
- key_right_set: set | OrderedSet,
36
- keys_consistent: Callable[[set | OrderedSet, set | OrderedSet], bool],
41
+ key_right_set: SetType,
42
+ keys_consistent_fcn: Callable[[SetType, SetType], bool],
37
43
  fcn: Callable[[TupleKey, TupleKey], Any],
38
44
  *,
39
45
  fcn_on_reject: Callable[[TupleKey, TupleKey], Any] | None = None,
@@ -57,7 +63,7 @@ def match_keys_to_key(
57
63
  key_left_tuple = properkey(key_left)
58
64
  key_left_set = OrderedSet(key_left_tuple)
59
65
 
60
- if not keys_consistent(key_left_set, key_right_set):
66
+ if not keys_consistent_fcn(key_left_set, key_right_set): # pyright: ignore [reportArgumentType]
61
67
  if (
62
68
  collect_skipped_left_keys
63
69
  and key_left_tuple
@@ -100,7 +106,9 @@ def match_keys_to_key(
100
106
  skipped_right_keys.remove(
101
107
  key_right_tuple
102
108
  ) # pyright: ignore [reportOptionalMemberAccess]
103
- processed_right_keys.add(key_right_tuple) # pyright: ignore [reportOptionalMemberAccess]
109
+ processed_right_keys.add(
110
+ key_right_tuple
111
+ ) # pyright: ignore [reportOptionalMemberAccess]
104
112
 
105
113
  return right_key_processed
106
114
 
@@ -108,27 +116,27 @@ def match_keys_to_key(
108
116
  def zip_match_keys_to_key(
109
117
  keys_left: Sequence[KeyLike],
110
118
  key_right_tuple: TupleKey,
111
- key_right_set: set | OrderedSet,
112
- keys_consistent_fcn: Callable[[set | OrderedSet, set | OrderedSet], bool],
119
+ key_right_set: SetType,
120
+ keys_consistent_fcn: Callable[[SetType, SetType], bool],
113
121
  ):
114
122
  for key_left in keys_left:
115
123
  key_left_tuple = properkey(key_left)
116
124
  key_left_set = OrderedSet(key_left_tuple)
117
- if keys_consistent_fcn(key_left_set, key_right_set):
125
+ if keys_consistent_fcn(key_left_set, key_right_set): # pyright: ignore [reportArgumentType]
118
126
  yield key_left_tuple, key_right_tuple
119
127
 
120
128
 
121
129
  def zip_match_keys_to_keys(
122
130
  keys_left: Sequence[KeyLike],
123
131
  keys_right: Sequence[KeyLike],
124
- keys_consistent_fcn: Callable[[set | OrderedSet, set | OrderedSet], bool],
132
+ keys_consistent_fcn: Callable[[SetType, SetType], bool],
125
133
  ):
126
134
  for key_right in keys_right:
127
135
  key_right_tuple = properkey(key_right)
128
136
  key_right_set = OrderedSet(key_right_tuple)
129
137
 
130
138
  yield from zip_match_keys_to_key(
131
- keys_left, key_right_tuple, key_right_set, keys_consistent_fcn
139
+ keys_left, key_right_tuple, key_right_set, keys_consistent_fcn # pyright: ignore [reportArgumentType]
132
140
  )
133
141
 
134
142
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nested-mapping
3
- Version: 0.12.1
3
+ Version: 0.13.1
4
4
  Summary: A wrapper and a toolkit for working with nested mappings in Python
5
5
  Author-email: DAGModelling Team <dagflow@jinr.ru>
6
6
  Maintainer-email: DAGModelling Team <dagflow@jinr.ru>
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.13.1",
3
+ "distance": 0,
4
+ "node": "gb3fd43ba6a9543da9456f6bf2bd25ffcadf21b28",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-11-03"
8
+ }
@@ -17,6 +17,7 @@ def test_remap_items_01():
17
17
  d_renamed_reordered_skipped_source_match = NestedMapping()
18
18
  d_renamed_reordered_skipped_target_match = NestedMapping()
19
19
  d_renamed_reordered_skipped_both_match = NestedMapping()
20
+ d_renamed_reordered_skipped_both_extra_match = NestedMapping()
20
21
 
21
22
  rename_indices = {
22
23
  "z": ("z1", "z2"),
@@ -24,6 +25,8 @@ def test_remap_items_01():
24
25
  }
25
26
  reorder_indices = [2, 1, 0]
26
27
  reorder_indices_names = (("a", "b", "c"), ("c", "b", "a"))
28
+ reorder_indices_names_extra = (("a", "b", "c"), ("c", "extra", "b", "a"))
29
+ reorder_indices_dict = {"from": ("a", "b", "c"), "to": ("c", "b", "a")}
27
30
  skip_indices_source = (("1", "z"), ("b",))
28
31
  skip_indices_target = (("1", "z2"), ("a",))
29
32
 
@@ -47,6 +50,9 @@ def test_remap_items_01():
47
50
  d_renamed_reordered_skipped_both_match["z1", i2new, i1] = c
48
51
  d_renamed_reordered_skipped_both_match["z2", i2new, i1] = c
49
52
 
53
+ d_renamed_reordered_skipped_both_extra_match["z1", "extra", i2new, i1] = c
54
+ d_renamed_reordered_skipped_both_extra_match["z2", "extra", i2new, i1] = c
55
+
50
56
  d_renamed_reordered_skipped_source_match["z1", i2new, i1] = c
51
57
  d_renamed_reordered_skipped_source_match["z2", i2new, i1] = c
52
58
 
@@ -63,6 +69,7 @@ def test_remap_items_01():
63
69
  d_renamed_reordered_skipped_source_match[i3, i2new, i1] = c
64
70
  if i2new != "a":
65
71
  d_renamed_reordered_skipped_both_match[i3, i2new, i1] = c
72
+ d_renamed_reordered_skipped_both_extra_match[i3, "extra", i2new, i1] = c
66
73
 
67
74
  d_new = remap_items(d_main, reorder_indices=reorder_indices)
68
75
  assert d_reordered_match == d_new
@@ -73,6 +80,9 @@ def test_remap_items_01():
73
80
  d_new = remap_items(d_main, reorder_indices=reorder_indices_names)
74
81
  assert d_reordered_match == d_new
75
82
 
83
+ d_new = remap_items(d_main, reorder_indices=reorder_indices_dict)
84
+ assert d_reordered_match == d_new
85
+
76
86
  d_new = remap_items(
77
87
  d_main,
78
88
  reorder_indices=reorder_indices,
@@ -122,6 +132,25 @@ def test_remap_items_01():
122
132
  skip_indices_source=skip_indices_source,
123
133
  skip_indices_target=skip_indices_target,
124
134
  )
135
+ assert d_renamed_reordered_skipped_both_match == d_new
136
+
137
+ with raises(ValueError):
138
+ d_new = remap_items(
139
+ d_main,
140
+ rename_indices=rename_indices,
141
+ reorder_indices=reorder_indices_names_extra,
142
+ skip_indices_source=skip_indices_source,
143
+ skip_indices_target=skip_indices_target,
144
+ )
145
+ d_new = remap_items(
146
+ d_main,
147
+ rename_indices=rename_indices,
148
+ reorder_indices=reorder_indices_names_extra,
149
+ skip_indices_source=skip_indices_source,
150
+ skip_indices_target=skip_indices_target,
151
+ allow_insert_items=True,
152
+ )
153
+ assert d_renamed_reordered_skipped_both_extra_match == d_new
125
154
 
126
155
  with raises(ValueError):
127
156
  remap_items(d_main, reorder_indices=[["a", "b", "c"], ["c", "a", "B"]])
@@ -227,3 +256,19 @@ def test_reorder_function():
227
256
 
228
257
  with raises(ValueError):
229
258
  make_reorder_function([list("abc"), list("cad")])
259
+
260
+ with raises(ValueError):
261
+ fcn6 = make_reorder_function([list("abc"), list("cdab")])
262
+
263
+ fcn6 = make_reorder_function([list("abc"), list("cdab")], allow_insert_items=True)
264
+ data6 = [3, "d", 1, 2]
265
+ assert data6 == fcn6(data_from)
266
+
267
+ with raises(ValueError):
268
+ fcn6 = make_reorder_function([list("abc"), list("cdb")], allow_insert_items=True)
269
+
270
+ fcn6 = make_reorder_function(
271
+ [list("abc"), list("cdb")], allow_insert_items=True, allow_skip_items=True
272
+ )
273
+ data6 = [3, "d", 2]
274
+ assert data6 == fcn6(data_from)
@@ -1,31 +1,58 @@
1
1
  from itertools import product
2
2
 
3
+ from ordered_set import OrderedSet
3
4
  from pytest import raises
4
5
 
5
6
  from nested_mapping.tools import match_keys
6
7
  from nested_mapping.tools.match import (
7
8
  match_keys_to_key,
8
9
  set_keys_consistent_left_in_right,
10
+ set_keys_consistent_ordered,
9
11
  set_keys_consistent_right_in_left,
10
12
  set_keys_consistent_symmetric,
13
+ set_keys_consistent_unordered,
11
14
  zip_match_keys_to_key,
12
15
  zip_match_keys_to_keys,
13
16
  )
14
17
 
15
18
 
16
19
  def test_set_keys_consistent():
17
- ab = set("ab")
18
- abc = set("abc")
19
- abce = set("abce")
20
- abcd = set("abcd")
21
- abd = set("abd")
22
- abe = set("abe")
23
- ac = set("ac")
24
- empty = set()
20
+ ab = OrderedSet("ab")
21
+ abc = OrderedSet("abc")
22
+ abce = OrderedSet("abce")
23
+ abcd = OrderedSet("abcd")
24
+ abd = OrderedSet("abd")
25
+ abe = OrderedSet("abe")
26
+ ac = OrderedSet("ac")
27
+ cab = OrderedSet("cab")
28
+ empty: OrderedSet[str] = OrderedSet(())
29
+
30
+ assert set_keys_consistent_ordered(abc, abc) is True
31
+ assert set_keys_consistent_ordered(ab, abc) is False
32
+ assert set_keys_consistent_ordered(abc, ac) is False
33
+ assert set_keys_consistent_ordered(abc, empty) is False
34
+
35
+ assert set_keys_consistent_ordered(abc, cab) is False
36
+ assert set_keys_consistent_ordered(ab, cab) is False
37
+ assert set_keys_consistent_ordered(cab, ac) is False
38
+
39
+ assert set_keys_consistent_unordered(abc, abc) is True
40
+ assert set_keys_consistent_unordered(ab, abc) is False
41
+ assert set_keys_consistent_unordered(abc, ac) is False
42
+ assert set_keys_consistent_unordered(abc, empty) is False
43
+
44
+ assert set_keys_consistent_unordered(abc, cab) is True
45
+ assert set_keys_consistent_unordered(ab, cab) is False
46
+ assert set_keys_consistent_unordered(cab, ac) is False
47
+
25
48
  assert set_keys_consistent_symmetric(abc, abc) is True
26
49
  assert set_keys_consistent_symmetric(ab, abc) is True
27
50
  assert set_keys_consistent_symmetric(abc, ac) is True
28
51
 
52
+ assert set_keys_consistent_symmetric(abc, cab) is True
53
+ assert set_keys_consistent_symmetric(ab, cab) is True
54
+ assert set_keys_consistent_symmetric(cab, ac) is True
55
+
29
56
  assert set_keys_consistent_symmetric(abcd, abce) is False
30
57
  assert set_keys_consistent_symmetric(abd, abce) is False
31
58
  assert set_keys_consistent_symmetric(abcd, abe) is False
@@ -36,6 +63,10 @@ def test_set_keys_consistent():
36
63
  assert set_keys_consistent_left_in_right(ab, abc) is True
37
64
  assert set_keys_consistent_left_in_right(abc, ac) is False
38
65
 
66
+ assert set_keys_consistent_left_in_right(abc, cab) is True
67
+ assert set_keys_consistent_left_in_right(ab, cab) is True
68
+ assert set_keys_consistent_left_in_right(cab, ac) is False
69
+
39
70
  assert set_keys_consistent_left_in_right(abcd, abce) is False
40
71
  assert set_keys_consistent_left_in_right(abd, abce) is False
41
72
  assert set_keys_consistent_left_in_right(abcd, abe) is False
@@ -46,6 +77,10 @@ def test_set_keys_consistent():
46
77
  assert set_keys_consistent_right_in_left(ab, abc) is False
47
78
  assert set_keys_consistent_right_in_left(abc, ac) is True
48
79
 
80
+ assert set_keys_consistent_right_in_left(abc, cab) is True
81
+ assert set_keys_consistent_right_in_left(ab, cab) is False
82
+ assert set_keys_consistent_right_in_left(cab, ac) is True
83
+
49
84
  assert set_keys_consistent_right_in_left(abcd, abce) is False
50
85
  assert set_keys_consistent_right_in_left(abd, abce) is False
51
86
  assert set_keys_consistent_right_in_left(abcd, abe) is False
@@ -61,42 +96,61 @@ def test_zip_match_keys_to_key():
61
96
  abd = tuple("abd")
62
97
  abe = tuple("abe")
63
98
  ac = tuple("ac")
99
+ cab = tuple("cab")
64
100
  x = tuple("x")
65
101
  empty = tuple()
66
102
 
67
103
  assert list(
68
104
  zip_match_keys_to_key(
69
- [ab, abc, abce, abcd, abd, abe, ac, empty],
105
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
70
106
  abc,
71
- set(abc),
107
+ OrderedSet(abc),
108
+ keys_consistent_fcn=set_keys_consistent_ordered,
109
+ )
110
+ ) == [(abc, abc)]
111
+
112
+ assert list(
113
+ zip_match_keys_to_key(
114
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
115
+ abc,
116
+ OrderedSet(abc),
117
+ keys_consistent_fcn=set_keys_consistent_unordered,
118
+ )
119
+ ) == [(abc, abc), (cab, abc)]
120
+
121
+ assert list(
122
+ zip_match_keys_to_key(
123
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
124
+ abc,
125
+ OrderedSet(abc),
72
126
  keys_consistent_fcn=set_keys_consistent_symmetric,
73
127
  )
74
- ) == [(ab, abc), (abc, abc), (abce, abc), (abcd, abc), (ac, abc), (empty, abc)]
128
+ ) == [(ab, abc), (abc, abc), (abce, abc), (abcd, abc), (ac, abc), (cab, abc), (empty, abc)]
75
129
 
76
130
  assert list(
77
131
  zip_match_keys_to_key(
78
- [ab, abc, abce, abcd, abd, abe, ac, empty],
132
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
79
133
  abc,
80
- set(abc),
134
+ OrderedSet(abc),
81
135
  keys_consistent_fcn=set_keys_consistent_left_in_right,
82
136
  )
83
- ) == [(ab, abc), (abc, abc), (ac, abc), (empty, abc)]
137
+ ) == [(ab, abc), (abc, abc), (ac, abc), (cab, abc), (empty, abc)]
84
138
 
85
139
  assert list(
86
140
  zip_match_keys_to_key(
87
- [ab, abc, abce, abcd, abd, abe, ac, empty],
141
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
88
142
  abc,
89
- set(abc),
143
+ OrderedSet(abc),
90
144
  keys_consistent_fcn=set_keys_consistent_right_in_left,
91
145
  )
92
- ) == [(abc, abc), (abce, abc), (abcd, abc)]
146
+ ) == [(abc, abc), (abce, abc), (abcd, abc), (cab, abc)]
93
147
 
94
148
  assert (
95
149
  list(
96
150
  zip_match_keys_to_key(
97
151
  [ab, abc, abce, abcd, abd, abe, ac],
98
152
  x,
99
- set(x),
153
+ OrderedSet(x),
100
154
  keys_consistent_fcn=set_keys_consistent_symmetric,
101
155
  )
102
156
  )
@@ -112,12 +166,36 @@ def test_zip_match_keys_to_keys():
112
166
  abd = tuple("abd")
113
167
  abe = tuple("abe")
114
168
  ac = tuple("ac")
169
+ cab = tuple("cab")
115
170
  x = tuple("x")
116
171
  empty = tuple()
117
172
 
118
173
  assert list(
119
174
  zip_match_keys_to_keys(
120
- [ab, abc, abce, abcd, abd, abe, ac, empty],
175
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
176
+ [abc, abd, x],
177
+ keys_consistent_fcn=set_keys_consistent_ordered,
178
+ )
179
+ ) == [
180
+ (abc, abc),
181
+ (abd, abd),
182
+ ]
183
+
184
+ assert list(
185
+ zip_match_keys_to_keys(
186
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
187
+ [abc, abd, x],
188
+ keys_consistent_fcn=set_keys_consistent_unordered,
189
+ )
190
+ ) == [
191
+ (abc, abc),
192
+ (cab, abc),
193
+ (abd, abd),
194
+ ]
195
+
196
+ assert list(
197
+ zip_match_keys_to_keys(
198
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
121
199
  [abc, abd, x],
122
200
  keys_consistent_fcn=set_keys_consistent_symmetric,
123
201
  )
@@ -127,6 +205,7 @@ def test_zip_match_keys_to_keys():
127
205
  (abce, abc),
128
206
  (abcd, abc),
129
207
  (ac, abc),
208
+ (cab, abc),
130
209
  (empty, abc),
131
210
  (ab, abd),
132
211
  (abcd, abd),
@@ -137,7 +216,7 @@ def test_zip_match_keys_to_keys():
137
216
 
138
217
  assert list(
139
218
  zip_match_keys_to_keys(
140
- [ab, abc, abce, abcd, abd, abe, ac, empty],
219
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
141
220
  [abc, abd, x],
142
221
  keys_consistent_fcn=set_keys_consistent_left_in_right,
143
222
  )
@@ -145,6 +224,7 @@ def test_zip_match_keys_to_keys():
145
224
  (ab, abc),
146
225
  (abc, abc),
147
226
  (ac, abc),
227
+ (cab, abc),
148
228
  (empty, abc),
149
229
  (ab, abd),
150
230
  (abd, abd),
@@ -154,7 +234,7 @@ def test_zip_match_keys_to_keys():
154
234
 
155
235
  assert list(
156
236
  zip_match_keys_to_keys(
157
- [ab, abc, abce, abcd, abd, abe, ac, empty],
237
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
158
238
  [abc, abd, x],
159
239
  keys_consistent_fcn=set_keys_consistent_right_in_left,
160
240
  )
@@ -162,6 +242,7 @@ def test_zip_match_keys_to_keys():
162
242
  (abc, abc),
163
243
  (abce, abc),
164
244
  (abcd, abc),
245
+ (cab, abc),
165
246
  (abcd, abd),
166
247
  (abd, abd),
167
248
  ]
@@ -175,6 +256,7 @@ def test_match_keys_to_key():
175
256
  abd = tuple("abd")
176
257
  abe = tuple("abe")
177
258
  ac = tuple("ac")
259
+ cab = tuple("cab")
178
260
  x = tuple("x")
179
261
  empty = tuple()
180
262
 
@@ -224,17 +306,86 @@ def test_match_keys_to_key():
224
306
  skipped_right_keys,
225
307
  processed_right_keys,
226
308
  ) = call_match(
227
- [ab, abc, abce, abcd, abd, abe, ac, empty],
309
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
228
310
  abc,
229
- set(abc),
311
+ OrderedSet(abc),
312
+ set_keys_consistent_ordered,
313
+ )
314
+ assert right_processed == True
315
+ assert processed == [(abc, abc)]
316
+ assert skipped == [
317
+ (ab, abc),
318
+ (abce, abc),
319
+ (abcd, abc),
320
+ (abd, abc),
321
+ (abe, abc),
322
+ (ac, abc),
323
+ (cab, abc),
324
+ (empty, abc),
325
+ ]
326
+ assert skipped_left_keys == {ab, abce, abcd, abd, abe, ac, cab, empty}
327
+ assert processed_left_keys == {abc}
328
+ assert skipped_right_keys == OrderedSet(())
329
+ assert processed_right_keys == {abc}
330
+
331
+ (
332
+ right_processed,
333
+ processed,
334
+ skipped,
335
+ skipped_left_keys,
336
+ processed_left_keys,
337
+ skipped_right_keys,
338
+ processed_right_keys,
339
+ ) = call_match(
340
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
341
+ abc,
342
+ OrderedSet(abc),
343
+ set_keys_consistent_unordered,
344
+ )
345
+ assert right_processed == True
346
+ assert processed == [(abc, abc), (cab, abc)]
347
+ assert skipped == [
348
+ (ab, abc),
349
+ (abce, abc),
350
+ (abcd, abc),
351
+ (abd, abc),
352
+ (abe, abc),
353
+ (ac, abc),
354
+ (empty, abc),
355
+ ]
356
+ assert skipped_left_keys == {ab, abce, abcd, abd, abe, ac, empty}
357
+ assert processed_left_keys == {abc, cab}
358
+ assert skipped_right_keys == OrderedSet(())
359
+ assert processed_right_keys == {abc}
360
+
361
+ (
362
+ right_processed,
363
+ processed,
364
+ skipped,
365
+ skipped_left_keys,
366
+ processed_left_keys,
367
+ skipped_right_keys,
368
+ processed_right_keys,
369
+ ) = call_match(
370
+ [ab, abc, abce, abcd, abd, abe, ac, cab, empty],
371
+ abc,
372
+ OrderedSet(abc),
230
373
  set_keys_consistent_symmetric,
231
374
  )
232
375
  assert right_processed == True
233
- assert processed == [(ab, abc), (abc, abc), (abce, abc), (abcd, abc), (ac, abc), (empty, abc)]
376
+ assert processed == [
377
+ (ab, abc),
378
+ (abc, abc),
379
+ (abce, abc),
380
+ (abcd, abc),
381
+ (ac, abc),
382
+ (cab, abc),
383
+ (empty, abc),
384
+ ]
234
385
  assert skipped == [(abd, abc), (abe, abc)]
235
386
  assert skipped_left_keys == {abd, abe}
236
- assert processed_left_keys == {ab, abc, abce, abcd, ac, empty}
237
- assert skipped_right_keys == set()
387
+ assert processed_left_keys == {ab, abc, abce, abcd, ac, cab, empty}
388
+ assert skipped_right_keys == OrderedSet(())
238
389
  assert processed_right_keys == {abc}
239
390
 
240
391
  (
@@ -248,7 +399,7 @@ def test_match_keys_to_key():
248
399
  ) = call_match(
249
400
  [ab, abc, abce, abcd, abd, abe, ac, empty],
250
401
  abc,
251
- set(abc),
402
+ OrderedSet(abc),
252
403
  set_keys_consistent_left_in_right,
253
404
  )
254
405
  assert right_processed == True
@@ -256,7 +407,7 @@ def test_match_keys_to_key():
256
407
  assert skipped == [(abce, abc), (abcd, abc), (abd, abc), (abe, abc)]
257
408
  assert skipped_left_keys == {abd, abce, abcd, abe}
258
409
  assert processed_left_keys == {ab, abc, ac, empty}
259
- assert skipped_right_keys == set()
410
+ assert skipped_right_keys == OrderedSet(())
260
411
  assert processed_right_keys == {abc}
261
412
 
262
413
  (
@@ -270,7 +421,7 @@ def test_match_keys_to_key():
270
421
  ) = call_match(
271
422
  [ab, abc, abce, abcd, abd, abe, ac, empty],
272
423
  abc,
273
- set(abc),
424
+ OrderedSet(abc),
274
425
  set_keys_consistent_right_in_left,
275
426
  )
276
427
  assert right_processed == True
@@ -278,7 +429,7 @@ def test_match_keys_to_key():
278
429
  assert skipped == [(ab, abc), (abd, abc), (abe, abc), (ac, abc), (empty, abc)]
279
430
  assert skipped_left_keys == {ab, abd, abe, ac, empty}
280
431
  assert processed_left_keys == {abc, abce, abcd}
281
- assert skipped_right_keys == set()
432
+ assert skipped_right_keys == OrderedSet(())
282
433
  assert processed_right_keys == {abc}
283
434
 
284
435
  (
@@ -292,16 +443,16 @@ def test_match_keys_to_key():
292
443
  ) = call_match(
293
444
  [ab, abc, abce, abcd, abd, abe, ac],
294
445
  x,
295
- set(x),
446
+ OrderedSet(x),
296
447
  set_keys_consistent_symmetric,
297
448
  )
298
449
  assert right_processed == False
299
450
  assert processed == []
300
451
  assert skipped == [(ab, x), (abc, x), (abce, x), (abcd, x), (abd, x), (abe, x), (ac, x)]
301
452
  assert skipped_left_keys == {ab, abc, abce, abcd, abd, abe, ac}
302
- assert processed_left_keys == set()
453
+ assert processed_left_keys == OrderedSet(())
303
454
  assert skipped_right_keys == {x}
304
- assert processed_right_keys == set()
455
+ assert processed_right_keys == OrderedSet(())
305
456
 
306
457
  with raises(ValueError):
307
458
  (
@@ -315,7 +466,7 @@ def test_match_keys_to_key():
315
466
  ) = call_match(
316
467
  [ab, abc, abc, abce, abcd, abd, abe, ac, empty],
317
468
  abc,
318
- set(abc),
469
+ OrderedSet(abc),
319
470
  set_keys_consistent_symmetric,
320
471
  require_no_duplicate_right_matches=True,
321
472
  )
@@ -544,7 +695,7 @@ def test_match_1():
544
695
  require_all_left_keys_processed=True,
545
696
  require_all_right_keys_processed=True,
546
697
  require_all_left_keys_match_right=False,
547
- unmatched_right_keys_should_contain=[("2",)]
698
+ unmatched_right_keys_should_contain=[("2",)],
548
699
  )
549
700
  assert processed == [
550
701
  (0, a, a1x),
@@ -585,7 +736,7 @@ def test_match_1():
585
736
  require_all_left_keys_processed=True,
586
737
  require_all_right_keys_processed=True,
587
738
  require_all_left_keys_match_right=False,
588
- unmatched_right_keys_should_contain=[("2", "a")]
739
+ unmatched_right_keys_should_contain=[("2", "a")],
589
740
  )
590
741
  (
591
742
  processed,
@@ -598,7 +749,7 @@ def test_match_1():
598
749
  require_all_left_keys_processed=True,
599
750
  require_all_right_keys_processed=True,
600
751
  require_all_left_keys_match_right=False,
601
- unmatched_right_keys_should_contain=[("2", "a"), ("b", "2")]
752
+ unmatched_right_keys_should_contain=[("2", "a"), ("b", "2")],
602
753
  )
603
754
  assert processed == [
604
755
  (0, a, a1x),
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "0.12.1",
3
- "distance": 0,
4
- "node": "g70b286d139ee9177b2886dfbe9a73efe2e19880a",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-10-29"
8
- }
File without changes
File without changes