From e960a442f9393b278aea881c90be2209fc187ba2 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 3 Sep 2020 23:27:26 +0300 Subject: [PATCH 1/3] Implement NoRedundantLambdaFunction --- fixit/rules/no_redundant_lambda.py | 77 ++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 fixit/rules/no_redundant_lambda.py diff --git a/fixit/rules/no_redundant_lambda.py b/fixit/rules/no_redundant_lambda.py new file mode 100644 index 00000000..0ccab1ea --- /dev/null +++ b/fixit/rules/no_redundant_lambda.py @@ -0,0 +1,77 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import libcst as cst +import libcst.matchers as m +from libcst.helpers import get_full_name_for_node + +from fixit import CstLintRule, InvalidTestCase as Invalid, ValidTestCase as Valid + + +UNNECESSARY_LAMBDA: str = ( + "The lambda that is wrapping {function} is redundant. " + + "It can unwrapped safely and used purely." +) + + +class NoRedundantLambdaFunction(CstLintRule): + + VALID = [ + Valid("lambda x: foo(y)"), + Valid("lambda x: foo(x, y)"), + Valid("lambda x, y: foo(x)"), + Valid("lambda x, /: foo(x)"), + Valid("lambda *, x: foo(x)"), + Valid("lambda x = y: foo(x)"), + Valid("lambda x, y: foo(y, x)"), + Valid("lambda x, y: foo(y=x, x=y)"), + Valid("lambda x, y, *z: foo(x, y, z)"), + Valid("lambda x, y, **z: foo(x, y, z)"), + ] + INVALID = [ + Invalid("lambda x: foo(x)", expected_replacement="foo"), + Invalid( + "lambda x, y, z: (t + u).math_call(x, y, z)", + expected_replacement="(t + u).math_call", + ), + ] + + @staticmethod + def _is_simple_parameter_spec(node: cst.Parameters) -> bool: + if ( + node.star_kwarg is not None + or len(node.kwonly_params) > 0 + or len(node.posonly_params) > 0 + or not isinstance(node.star_arg, cst.MaybeSentinel) + ): + return False + + return all(param.default is None for param in node.params) + + def visit_Lambda(self, node: cst.Lambda) -> None: + if m.matches( + node, + m.Lambda( + params=m.MatchIfTrue(self._is_simple_parameter_spec), + body=m.Call( + args=[ + m.Arg( + value=m.Name(value=param.name.value), star="", keyword=None + ) + for param in node.params.params + ] + ), + ), + ): + call = cst.ensure_type(node.body, cst.Call) + full_name = get_full_name_for_node(call) + if full_name is None: + full_name = "function" + + self.report( + node, + UNNECESSARY_LAMBDA.format(function=full_name), + replacement=call.func, + ) From f91c70f0ee8f6ed723ab66d68cf52903a68241e3 Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Thu, 3 Sep 2020 23:38:29 +0300 Subject: [PATCH 2/3] Remove 3.8+ only test () --- fixit/rules/no_redundant_lambda.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fixit/rules/no_redundant_lambda.py b/fixit/rules/no_redundant_lambda.py index 0ccab1ea..b69de05d 100644 --- a/fixit/rules/no_redundant_lambda.py +++ b/fixit/rules/no_redundant_lambda.py @@ -22,7 +22,6 @@ class NoRedundantLambdaFunction(CstLintRule): Valid("lambda x: foo(y)"), Valid("lambda x: foo(x, y)"), Valid("lambda x, y: foo(x)"), - Valid("lambda x, /: foo(x)"), Valid("lambda *, x: foo(x)"), Valid("lambda x = y: foo(x)"), Valid("lambda x, y: foo(y, x)"), From 970eea081733666e358fcdd3c21d4067d3cebf3a Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Sat, 5 Sep 2020 01:09:48 +0300 Subject: [PATCH 3/3] Add more example, fix class name, add docstrings --- fixit/rules/no_redundant_lambda.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fixit/rules/no_redundant_lambda.py b/fixit/rules/no_redundant_lambda.py index b69de05d..932ad55b 100644 --- a/fixit/rules/no_redundant_lambda.py +++ b/fixit/rules/no_redundant_lambda.py @@ -16,7 +16,10 @@ ) -class NoRedundantLambdaFunction(CstLintRule): +class NoRedundantLambdaRule(CstLintRule): + """A lamba function which has a single objective of + passing all it is arguments to another callable can + be safely replaced by that callable.""" VALID = [ Valid("lambda x: foo(y)"), @@ -25,11 +28,13 @@ class NoRedundantLambdaFunction(CstLintRule): Valid("lambda *, x: foo(x)"), Valid("lambda x = y: foo(x)"), Valid("lambda x, y: foo(y, x)"), + Valid("lambda self: self.func()"), Valid("lambda x, y: foo(y=x, x=y)"), Valid("lambda x, y, *z: foo(x, y, z)"), Valid("lambda x, y, **z: foo(x, y, z)"), ] INVALID = [ + Invalid("lambda: self.func()", expected_replacement="self.func"), Invalid("lambda x: foo(x)", expected_replacement="foo"), Invalid( "lambda x, y, z: (t + u).math_call(x, y, z)",