| Total Complexity | 85 |
| Total Lines | 241 |
| Duplicated Lines | 12.03 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Reducer_Edit often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | #!/usr/bin/env python |
||
| 145 | View Code Duplication | class Reducer_Edit(Reducer): |
|
|
|
|||
| 146 | def reduce(self, state: State, action: Action) -> State: |
||
| 147 | result = state |
||
| 148 | if isinstance(action, Action_ChangeItemText): |
||
| 149 | project_tree = state.project_tree |
||
| 150 | old_item = project_tree.find_item(action.item_uid) if project_tree else None |
||
| 151 | |||
| 152 | if old_item: |
||
| 153 | old_item_text = old_item.text |
||
| 154 | new_item_text = action.item_new_text |
||
| 155 | if old_item_text != new_item_text: |
||
| 156 | result = copy.deepcopy(result) |
||
| 157 | project_tree = result.project_tree |
||
| 158 | if project_tree: |
||
| 159 | new_item = project_tree.find_item(action.item_uid) |
||
| 160 | new_item.text = new_item_text |
||
| 161 | result.session_pending_change = True |
||
| 162 | if isinstance(action, Action_ChangeItemReference): |
||
| 163 | project_tree = state.project_tree |
||
| 164 | old_item = project_tree.find_item(action.item_uid) if project_tree else None |
||
| 165 | |||
| 166 | if old_item: |
||
| 167 | old_item_reference = old_item.ref |
||
| 168 | new_item_reference = action.item_new_reference |
||
| 169 | if old_item_reference != new_item_reference: |
||
| 170 | result = copy.deepcopy(result) |
||
| 171 | project_tree = result.project_tree |
||
| 172 | if project_tree: |
||
| 173 | new_item = project_tree.find_item(action.item_uid) |
||
| 174 | new_item.ref = new_item_reference |
||
| 175 | result.session_pending_change = True |
||
| 176 | elif isinstance(action, Action_ChangeItemActive): |
||
| 177 | project_tree = state.project_tree |
||
| 178 | old_item = project_tree.find_item(action.item_uid) if project_tree else None |
||
| 179 | |||
| 180 | if old_item: |
||
| 181 | old_item_active = old_item.active |
||
| 182 | new_item_active = action.item_new_active |
||
| 183 | if old_item_active != new_item_active: |
||
| 184 | result = copy.deepcopy(result) |
||
| 185 | project_tree = result.project_tree |
||
| 186 | if project_tree: |
||
| 187 | new_item = project_tree.find_item(action.item_uid) |
||
| 188 | new_item.active = new_item_active |
||
| 189 | result.session_pending_change = True |
||
| 190 | elif isinstance(action, Action_ChangeItemDerived): |
||
| 191 | project_tree = state.project_tree |
||
| 192 | old_item = project_tree.find_item(action.item_uid) if project_tree else None |
||
| 193 | |||
| 194 | if old_item: |
||
| 195 | old_item_derived = old_item.derived |
||
| 196 | new_item_derived = action.item_new_derived |
||
| 197 | if old_item_derived != new_item_derived: |
||
| 198 | result = copy.deepcopy(result) |
||
| 199 | project_tree = result.project_tree |
||
| 200 | if project_tree: |
||
| 201 | new_item = project_tree.find_item(action.item_uid) |
||
| 202 | new_item.derived = new_item_derived |
||
| 203 | result.session_pending_change = True |
||
| 204 | elif isinstance(action, Action_ChangeItemNormative): |
||
| 205 | project_tree = state.project_tree |
||
| 206 | old_item = project_tree.find_item(action.item_uid) if project_tree else None |
||
| 207 | |||
| 208 | if old_item: |
||
| 209 | old_item_normative = old_item.normative |
||
| 210 | new_item_normative = action.item_new_normative |
||
| 211 | if old_item_normative != new_item_normative: |
||
| 212 | result = copy.deepcopy(result) |
||
| 213 | project_tree = result.project_tree |
||
| 214 | if project_tree: |
||
| 215 | new_item = project_tree.find_item(action.item_uid) |
||
| 216 | new_item.normative = new_item_normative |
||
| 217 | result.session_pending_change = True |
||
| 218 | elif isinstance(action, Action_ChangeItemHeading): |
||
| 219 | project_tree = state.project_tree |
||
| 220 | old_item = project_tree.find_item(action.item_uid) if project_tree else None |
||
| 221 | |||
| 222 | if old_item: |
||
| 223 | old_item_heading = old_item.heading |
||
| 224 | new_item_heading = action.item_new_heading |
||
| 225 | if old_item_heading != new_item_heading: |
||
| 226 | result = copy.deepcopy(result) |
||
| 227 | project_tree = result.project_tree |
||
| 228 | if project_tree: |
||
| 229 | new_item = project_tree.find_item(action.item_uid) |
||
| 230 | new_item.heading = new_item_heading |
||
| 231 | result.session_pending_change = True |
||
| 232 | elif isinstance(action, Action_ChangeItemRemoveLink): |
||
| 233 | project_tree = state.project_tree |
||
| 234 | old_item = project_tree.find_item(action.item_uid) if project_tree else None |
||
| 235 | |||
| 236 | if old_item: |
||
| 237 | item_link = action.item_link |
||
| 238 | result = copy.deepcopy(result) |
||
| 239 | project_tree = result.project_tree |
||
| 240 | if project_tree: |
||
| 241 | new_item = project_tree.find_item(action.item_uid) |
||
| 242 | count_before = len(new_item.links) |
||
| 243 | new_item.links = [x for x in new_item.links if str(x) not in [str(y) for y in item_link]] |
||
| 244 | result.session_selected_link = frozenset([x for x in result.session_selected_link if str(x) not in [str(y) for y in item_link]]) |
||
| 245 | count_after = len(new_item.links) |
||
| 246 | if count_before != count_after: |
||
| 247 | View Code Duplication | result.session_pending_change = True |
|
| 248 | elif isinstance(action, Action_ChangeItemAddLink): |
||
| 249 | new_link = action.new_link |
||
| 250 | if "" != new_link: |
||
| 251 | |||
| 252 | project_tree = state.project_tree |
||
| 253 | old_item = project_tree.find_item(action.item_uid) if project_tree else None |
||
| 254 | |||
| 255 | if old_item: |
||
| 256 | if new_link not in old_item.links: |
||
| 257 | result = copy.deepcopy(result) |
||
| 258 | project_tree = result.project_tree |
||
| 259 | if project_tree: |
||
| 260 | new_item = project_tree.find_item(action.item_uid) |
||
| 261 | links = new_item.links |
||
| 262 | links.append(UID(new_link)) |
||
| 263 | new_item.links = links |
||
| 264 | result.session_pending_change = True |
||
| 265 | elif isinstance(action, Action_ChangeExtendedValue): |
||
| 266 | project_tree = state.project_tree |
||
| 267 | old_item = project_tree.find_item(action.item_uid) if project_tree else None |
||
| 268 | if old_item: |
||
| 269 | old_item_extended_value = old_item.get(action.extendedName) |
||
| 270 | new_item_extended_value = action.extendedValue |
||
| 271 | if old_item_extended_value != new_item_extended_value: |
||
| 272 | result = copy.deepcopy(result) |
||
| 273 | project_tree = result.project_tree |
||
| 274 | if project_tree: |
||
| 275 | new_item = project_tree.find_item(action.item_uid) |
||
| 276 | if new_item_extended_value and new_item_extended_value.strip(): |
||
| 277 | new_item.set(action.extendedName, new_item_extended_value) |
||
| 278 | else: |
||
| 279 | new_item.remove(action.extendedName) |
||
| 280 | result.session_pending_change = True |
||
| 281 | elif isinstance(action, Action_AddNewItemNextToSelection): |
||
| 282 | project_tree = state.project_tree |
||
| 283 | if project_tree is not None: |
||
| 284 | result = copy.deepcopy(result) |
||
| 285 | project_tree = result.project_tree |
||
| 286 | assert project_tree is not None |
||
| 287 | session_selected_item_principal = state.session_selected_item_principal |
||
| 288 | session_selected_item_principal_item = None if session_selected_item_principal is None else project_tree.find_item(session_selected_item_principal) |
||
| 289 | document = project_tree.find_document(result.session_selected_document) |
||
| 290 | new_item = document.add_item(level=None if session_selected_item_principal_item is None else session_selected_item_principal_item.level + 1) |
||
| 291 | result.session_pending_change = True |
||
| 292 | result.session_selected_item = (new_item.uid, ) |
||
| 293 | elif isinstance(action, Action_RemoveSelectedItem): |
||
| 294 | project_tree = state.project_tree |
||
| 295 | if (project_tree is not None) and (state.session_selected_item_principal is not None): |
||
| 296 | result = copy.deepcopy(result) |
||
| 297 | |||
| 298 | session_selected_item_principal = result.session_selected_item_principal |
||
| 299 | assert session_selected_item_principal is not None |
||
| 300 | |||
| 301 | project_tree = result.project_tree |
||
| 302 | assert project_tree is not None |
||
| 303 | |||
| 304 | document = project_tree.find_document(result.session_selected_document) |
||
| 305 | item_before = None |
||
| 306 | item = None |
||
| 307 | item_after = None |
||
| 308 | found_it = False |
||
| 309 | for curr_neighboor in document.items: |
||
| 310 | if found_it: |
||
| 311 | if str(curr_neighboor.uid) not in result.session_selected_item: |
||
| 312 | item_after = curr_neighboor |
||
| 313 | break |
||
| 314 | else: |
||
| 315 | if str(session_selected_item_principal) == str(curr_neighboor.uid): |
||
| 316 | item = curr_neighboor |
||
| 317 | found_it = True |
||
| 318 | else: |
||
| 319 | if str(curr_neighboor.uid) not in result.session_selected_item: |
||
| 320 | item_before = curr_neighboor |
||
| 321 | |||
| 322 | assert item is not None, str(session_selected_item_principal) |
||
| 323 | |||
| 324 | new_selection = None |
||
| 325 | if item_before is None: |
||
| 326 | if item_after is None: |
||
| 327 | new_selection = None |
||
| 328 | else: |
||
| 329 | new_selection = [item_after.uid] |
||
| 330 | else: |
||
| 331 | if item_after is None: |
||
| 332 | new_selection = [item_before.uid] |
||
| 333 | else: |
||
| 334 | # Use heuristic to chose the best userfriendly new selection. |
||
| 335 | item_before_level = item_before.level.value |
||
| 336 | item_level = item.level.value |
||
| 337 | item_after_level = item_after.level.value |
||
| 338 | |||
| 339 | for idx, val in enumerate(item_level): |
||
| 340 | if val == item_after_level[idx]: |
||
| 341 | if val == item_before_level[idx]: |
||
| 342 | continue # They are both equaly similar |
||
| 343 | else: |
||
| 344 | # The after looks more similar |
||
| 345 | new_selection = [item_after.uid] |
||
| 346 | break |
||
| 347 | else: |
||
| 348 | if val == item_before_level[idx]: |
||
| 349 | # The before looks more similar |
||
| 350 | new_selection = [item_before.uid] |
||
| 351 | break |
||
| 352 | else: |
||
| 353 | # They are both equaly not similar |
||
| 354 | new_selection = [item_after.uid] |
||
| 355 | break |
||
| 356 | |||
| 357 | for c_currUID in result.session_selected_item: |
||
| 358 | item = project_tree.find_item(c_currUID) |
||
| 359 | if item is not None: |
||
| 360 | item = project_tree.remove_item(item) |
||
| 361 | result.session_pending_change |= item is not None |
||
| 362 | result.session_selected_item = new_selection |
||
| 363 | elif isinstance(action, Action_Import): |
||
| 364 | source = action.file_to_import |
||
| 365 | if source: |
||
| 366 | project_tree = state.project_tree |
||
| 367 | if project_tree is not None: |
||
| 368 | resultX = copy.deepcopy(result) |
||
| 369 | project_tree = resultX.project_tree |
||
| 370 | assert project_tree is not None |
||
| 371 | |||
| 372 | the_document = None |
||
| 373 | try: |
||
| 374 | the_document = project_tree.find_document(state.session_selected_document) |
||
| 375 | except DoorstopError: |
||
| 376 | pass # The document is not found. |
||
| 377 | if the_document is not None: |
||
| 378 | ext = source[source.rfind("."):] |
||
| 379 | func = importer.check(ext) |
||
| 380 | if func is not None: |
||
| 381 | func(is_auto_save=False, path=source, document=the_document, mapping=None) |
||
| 382 | result = resultX |
||
| 383 | result.session_pending_change = True |
||
| 384 | |||
| 385 | return result |
||
| 386 | |||
| 442 |