Remove @unittest.expectedFailure decorators from tests that now pass.
(
contents: str, tests_to_remove: set[tuple[str, str]]
)
| 477 | |
| 478 | |
| 479 | def remove_expected_failures( |
| 480 | contents: str, tests_to_remove: set[tuple[str, str]] |
| 481 | ) -> str: |
| 482 | """Remove @unittest.expectedFailure decorators from tests that now pass.""" |
| 483 | if not tests_to_remove: |
| 484 | return contents |
| 485 | |
| 486 | tree = ast.parse(contents) |
| 487 | lines = contents.splitlines() |
| 488 | lines_to_remove = set() |
| 489 | |
| 490 | class_bases, class_methods = _build_inheritance_info(tree) |
| 491 | |
| 492 | resolved_tests = set() |
| 493 | for class_name, method_name in tests_to_remove: |
| 494 | defining_class = _find_method_definition( |
| 495 | class_name, method_name, class_bases, class_methods |
| 496 | ) |
| 497 | if defining_class: |
| 498 | resolved_tests.add((defining_class, method_name)) |
| 499 | |
| 500 | for node in ast.walk(tree): |
| 501 | if not isinstance(node, ast.ClassDef): |
| 502 | continue |
| 503 | class_name = node.name |
| 504 | for item in node.body: |
| 505 | if not isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)): |
| 506 | continue |
| 507 | method_name = item.name |
| 508 | if (class_name, method_name) not in resolved_tests: |
| 509 | continue |
| 510 | |
| 511 | remove_entire_method = _is_super_call_only(item) |
| 512 | |
| 513 | if remove_entire_method: |
| 514 | lines_to_remove.update(_method_removal_range(item, lines)) |
| 515 | else: |
| 516 | for dec in item.decorator_list: |
| 517 | dec_line = dec.lineno - 1 |
| 518 | line_content = lines[dec_line] |
| 519 | |
| 520 | if "expectedFailure" not in line_content: |
| 521 | continue |
| 522 | |
| 523 | has_comment_on_line = COMMENT in line_content |
| 524 | has_comment_before = ( |
| 525 | dec_line > 0 |
| 526 | and lines[dec_line - 1].strip().startswith("#") |
| 527 | and COMMENT in lines[dec_line - 1] |
| 528 | ) |
| 529 | has_comment_after = ( |
| 530 | dec_line + 1 < len(lines) |
| 531 | and lines[dec_line + 1].strip().startswith("#") |
| 532 | and COMMENT not in lines[dec_line + 1] |
| 533 | ) |
| 534 | |
| 535 | if has_comment_on_line or has_comment_before: |
| 536 | lines_to_remove.add(dec_line) |