Recursively compares two ASTs. compare_attributes affects whether AST attributes are considered in the comparison. If compare_attributes is False (default), then attributes are ignored. Otherwise they must all be equal. This option is useful to check whether the ASTs are structurall
(
a,
b,
/,
*,
compare_attributes=False,
)
| 412 | |
| 413 | |
| 414 | def compare( |
| 415 | a, |
| 416 | b, |
| 417 | /, |
| 418 | *, |
| 419 | compare_attributes=False, |
| 420 | ): |
| 421 | """Recursively compares two ASTs. |
| 422 | |
| 423 | compare_attributes affects whether AST attributes are considered |
| 424 | in the comparison. If compare_attributes is False (default), then |
| 425 | attributes are ignored. Otherwise they must all be equal. This |
| 426 | option is useful to check whether the ASTs are structurally equal but |
| 427 | might differ in whitespace or similar details. |
| 428 | """ |
| 429 | |
| 430 | sentinel = object() # handle the possibility of a missing attribute/field |
| 431 | |
| 432 | def _compare(a, b): |
| 433 | # Compare two fields on an AST object, which may themselves be |
| 434 | # AST objects, lists of AST objects, or primitive ASDL types |
| 435 | # like identifiers and constants. |
| 436 | if isinstance(a, AST): |
| 437 | return compare( |
| 438 | a, |
| 439 | b, |
| 440 | compare_attributes=compare_attributes, |
| 441 | ) |
| 442 | elif isinstance(a, list): |
| 443 | # If a field is repeated, then both objects will represent |
| 444 | # the value as a list. |
| 445 | if len(a) != len(b): |
| 446 | return False |
| 447 | for a_item, b_item in zip(a, b): |
| 448 | if not _compare(a_item, b_item): |
| 449 | return False |
| 450 | else: |
| 451 | return True |
| 452 | else: |
| 453 | return type(a) is type(b) and a == b |
| 454 | |
| 455 | def _compare_fields(a, b): |
| 456 | if a._fields != b._fields: |
| 457 | return False |
| 458 | for field in a._fields: |
| 459 | a_field = getattr(a, field, sentinel) |
| 460 | b_field = getattr(b, field, sentinel) |
| 461 | if a_field is sentinel and b_field is sentinel: |
| 462 | # both nodes are missing a field at runtime |
| 463 | continue |
| 464 | if a_field is sentinel or b_field is sentinel: |
| 465 | # one of the node is missing a field |
| 466 | return False |
| 467 | if not _compare(a_field, b_field): |
| 468 | return False |
| 469 | else: |
| 470 | return True |
| 471 |
searching dependent graphs…