|
7 | 7 |
|
8 | 8 | from __future__ import annotations |
9 | 9 |
|
10 | | -from typing import TYPE_CHECKING, Callable, Union |
| 10 | +from typing import TYPE_CHECKING, Any, Callable, Union |
11 | 11 | from typing_extensions import Self |
12 | 12 |
|
13 | 13 | from ..types import ld_dict, ld_list |
@@ -76,9 +76,8 @@ def merge( |
76 | 76 | This value will always be value. |
77 | 77 | :rtype: ld_merge_list |
78 | 78 | """ |
79 | | - # If necessary, add the entry that data has been rejected. |
80 | | - if value != update: |
81 | | - target.reject(key, update) |
| 79 | + # Add the entry that data has been rejected. |
| 80 | + target.reject(key, update) |
82 | 81 | # Return value unchanged. |
83 | 82 | return value |
84 | 83 |
|
@@ -111,8 +110,7 @@ def merge( |
111 | 110 | :rtype: BASIC_TYPE | TIME_TYPE | ld_dict | ld_list |
112 | 111 | """ |
113 | 112 | # If necessary, add the entry that data has been replaced. |
114 | | - if value != update: |
115 | | - target.replace(key, value) |
| 113 | + target.replace(key, value) |
116 | 114 | # Return the new value. |
117 | 115 | return update |
118 | 116 |
|
@@ -151,32 +149,21 @@ def merge( |
151 | 149 |
|
152 | 150 |
|
153 | 151 | class Collect(MergeAction): |
154 | | - def __init__( |
155 | | - self: Self, |
156 | | - match: Union[ |
157 | | - Callable[ |
158 | | - [ |
159 | | - Union[BASIC_TYPE, TIME_TYPE, ld_merge_dict, ld_merge_list], |
160 | | - Union[BASIC_TYPE, TIME_TYPE, ld_dict, ld_list] |
161 | | - ], |
162 | | - bool |
163 | | - ], |
164 | | - Callable[[ld_merge_dict, ld_dict], bool] |
165 | | - ] |
166 | | - ) -> None: |
| 152 | + def __init__(self: Self, match: Callable[[Any, Any], bool], reject_incoming: bool = True) -> None: |
167 | 153 | """ |
168 | | - Set the match function for this collect merge action. |
| 154 | + Set the match function for this collect merge action. And the behaivior for matches. |
169 | 155 |
|
170 | 156 | :param match: The function used to evaluate equality while merging. |
171 | | - :type match: Callable[ |
172 | | - [BASIC_TYPE | TIME_TYPE | ld_merge_dict | ld_merge_list, BASIC_TYPE | TIME_TYPE | ld_dict | ld_list], |
173 | | - bool |
174 | | - ] | Callable[[ld_merge_dict, ld_dict], bool] |
| 157 | + :type match: Callable[[Any, Any], bool] |
| 158 | + :param reject_incoming: If an incoming item matches an already collected one, if ``reject_incoming`` True, |
| 159 | + the incoming item gets rejected, if ``reject_incoming`` False, the match of the incoming item gets replaced. |
| 160 | + :type reject_incoming: bool |
175 | 161 |
|
176 | 162 | :return: |
177 | 163 | :rtype: None |
178 | 164 | """ |
179 | 165 | self.match = match |
| 166 | + self.reject_incoming = reject_incoming |
180 | 167 |
|
181 | 168 | def merge( |
182 | 169 | self: Self, |
@@ -206,44 +193,31 @@ def merge( |
206 | 193 |
|
207 | 194 | # iterate over all new items |
208 | 195 | for update_item in update: |
209 | | - # If the current new item has no occurence in value (according to self.match) add it to value. |
210 | | - if not any(self.match(item, update_item) for item in value): |
| 196 | + # Iterate over all items in value and if a match is found replace the first one or reject update_item. |
| 197 | + for index, item in enumerate(value): |
| 198 | + if self.match(item, update_item): |
| 199 | + if not self.reject_incoming: |
| 200 | + value[index] = update_item |
| 201 | + break |
| 202 | + else: |
| 203 | + # If the current new item has no occurence in value (according to self.match) add it to value. |
211 | 204 | value.append(update_item) |
212 | 205 |
|
213 | 206 | return value |
214 | 207 |
|
215 | 208 |
|
216 | 209 | class MergeSet(MergeAction): |
217 | | - def __init__( |
218 | | - self: Self, |
219 | | - match: Union[ |
220 | | - Callable[ |
221 | | - [ |
222 | | - Union[BASIC_TYPE, TIME_TYPE, ld_merge_dict, ld_merge_list], |
223 | | - Union[BASIC_TYPE, TIME_TYPE, ld_dict, ld_list] |
224 | | - ], |
225 | | - bool |
226 | | - ], |
227 | | - Callable[[ld_merge_dict, ld_dict], bool] |
228 | | - ], |
229 | | - merge_items: bool = True |
230 | | - ) -> None: |
| 210 | + def __init__(self: Self, match: Callable[[Any, Any], bool]) -> None: |
231 | 211 | """ |
232 | 212 | Set the match function for this collect merge action. |
233 | 213 |
|
234 | 214 | :param match: The function used to evaluate equality while merging. |
235 | | - :type match: Callable[ |
236 | | - [BASIC_TYPE | TIME_TYPE | ld_merge_dict | ld_merge_list, BASIC_TYPE | TIME_TYPE | ld_dict | ld_list], |
237 | | - bool |
238 | | - ] | Callable[[ld_merge_dict, ld_dict], bool] |
239 | | - :param merge_items: Whether or to to merge similar items. (If false this is basically :class:`Concat`) |
240 | | - :type merge_items: bool |
| 215 | + :type match: Callable[[ANy, Any], bool] |
241 | 216 |
|
242 | 217 | :return: |
243 | 218 | :rtype: None |
244 | 219 | """ |
245 | 220 | self.match = match |
246 | | - self.merge_items = merge_items |
247 | 221 |
|
248 | 222 | def merge( |
249 | 223 | self: Self, |
@@ -271,13 +245,19 @@ def merge( |
271 | 245 | if not isinstance(update, (list, ld_list)): |
272 | 246 | update = [update] |
273 | 247 |
|
274 | | - for item in update: |
| 248 | + for update_item in update: |
275 | 249 | # For each new item merge it into a similar item (according to match) inside target[key[-1]] |
276 | | - # (aka inside value) if such an item exists and merging is permitted. |
| 250 | + # (aka inside value) if such an item exists. |
277 | 251 | # Otherwise append it to target[key[-1]] (aka to value). |
278 | | - target_item = target.match(key[-1], item, self.match) |
279 | | - if target_item and self.merge_items: |
280 | | - target_item.update(item) |
| 252 | + for index, item in enumerate(value): |
| 253 | + if self.match(item, update_item): |
| 254 | + if isinstance(item, ld_dict) and isinstance(update_item, ld_dict): |
| 255 | + item.update(update_item) |
| 256 | + elif isinstance(item, ld_list) and isinstance(update_item, ld_list): |
| 257 | + self.merge(target, [*key, index], item, update_item) |
| 258 | + elif isinstance(item, (ld_dict, ld_list)) or isinstance(update_item, (ld_dict, ld_list)): |
| 259 | + """ FIXME: log error """ |
| 260 | + break |
281 | 261 | else: |
282 | 262 | value.append(item) |
283 | 263 | # Return the merged values. |
|
0 commit comments