|
| 1 | +import libcst as cst |
| 2 | + |
| 3 | +from codemodder.codemods.libcst_transformer import ( |
| 4 | + LibcstResultTransformer, |
| 5 | + LibcstTransformerPipeline, |
| 6 | + NewArg, |
| 7 | +) |
| 8 | +from codemodder.codemods.utils import is_zero |
| 9 | +from codemodder.codemods.utils_mixin import NameAndAncestorResolutionMixin |
| 10 | +from core_codemods.api import Metadata, Reference, ReviewGuidance |
| 11 | +from core_codemods.api.core_codemod import CoreCodemod |
| 12 | + |
| 13 | + |
| 14 | +class FixMathIsCloseTransformer( |
| 15 | + LibcstResultTransformer, |
| 16 | + NameAndAncestorResolutionMixin, |
| 17 | +): |
| 18 | + change_description = "Add `abs_tol` to `math.isclose` call" |
| 19 | + |
| 20 | + def leave_Call(self, original_node: cst.Call, updated_node: cst.Call): |
| 21 | + if ( |
| 22 | + not self.node_is_selected(original_node) |
| 23 | + or self.find_base_name(original_node.func) != "math.isclose" |
| 24 | + or len(original_node.args) < 2 |
| 25 | + ): |
| 26 | + return updated_node |
| 27 | + |
| 28 | + if self.at_least_one_zero_arg(original_node.args): |
| 29 | + for arg in original_node.args[2:]: |
| 30 | + match arg: |
| 31 | + case cst.Arg(keyword=cst.Name(value="abs_tol")) as matched_arg: |
| 32 | + # A `abs_tol` kwarg set to not 0 is acceptable if comparing to 0 |
| 33 | + if not is_zero(matched_arg.value): |
| 34 | + return updated_node |
| 35 | + |
| 36 | + new_args = self.replace_args( |
| 37 | + original_node, |
| 38 | + [NewArg(name="abs_tol", value="1e-09", add_if_missing=True)], |
| 39 | + ) |
| 40 | + |
| 41 | + self.report_change(original_node) |
| 42 | + return self.update_arg_target(updated_node, new_args) |
| 43 | + |
| 44 | + return updated_node |
| 45 | + |
| 46 | + def at_least_one_zero_arg(self, original_args: list[cst.Arg]): |
| 47 | + first_arg = self.resolve_expression(original_args[0].value) |
| 48 | + second_arg = self.resolve_expression(original_args[1].value) |
| 49 | + return is_zero(first_arg) or is_zero(second_arg) |
| 50 | + |
| 51 | + |
| 52 | +FixMathIsClose = CoreCodemod( |
| 53 | + metadata=Metadata( |
| 54 | + name="fix-math-isclose", |
| 55 | + summary="Add `abs_tol` to `math.isclose` Call", |
| 56 | + review_guidance=ReviewGuidance.MERGE_AFTER_REVIEW, |
| 57 | + references=[ |
| 58 | + Reference(url="https://docs.python.org/3/library/math.html#math.isclose"), |
| 59 | + ], |
| 60 | + ), |
| 61 | + transformer=LibcstTransformerPipeline(FixMathIsCloseTransformer), |
| 62 | + detector=None, |
| 63 | +) |
0 commit comments