From 5f71d931b5a8a7bc60d9308b8772305188448a4a Mon Sep 17 00:00:00 2001 From: Andrea Guarino Date: Fri, 17 Apr 2020 13:37:31 +0200 Subject: [PATCH] Update rule metadata --- .../org/sonar/l10n/py/rules/python/S1515.html | 48 ++++++++++++++++--- .../org/sonar/l10n/py/rules/python/S2733.html | 2 + .../org/sonar/l10n/py/rules/python/S2733.json | 2 +- .../org/sonar/l10n/py/rules/python/S5655.html | 25 ++++++++-- .../org/sonar/l10n/py/rules/python/S5655.json | 6 +-- .../org/sonar/l10n/py/rules/python/S5685.html | 2 +- sonarpedia.json | 2 +- 7 files changed, 70 insertions(+), 17 deletions(-) diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S1515.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S1515.html index 3a00659eb7..617eb31659 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S1515.html +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S1515.html @@ -1,7 +1,17 @@

Nested functions and lambdas can reference variables defined in enclosing scopes. This can create tricky bugs when the variable and the function -are defined in a loop. If the function is called after the loop, it will see the variables last value instead of seeing the values corresponding to -the iteration where the function was defined.

-

This rule raises an issue when a nested function or lambda references a variable defined in an enclosing loop.

+are defined in a loop. If the function is called in another iteration or after the loop finishes, it will see the variables' last value instead of +seeing the values corresponding to the iteration where the function was defined.

+

Capturing loop variables might work for some time but:

+ +

One solution is to add a parameter to the function/lambda and use the previously captured variable as its default value. Default values are only +executed once, when the function is defined, which means that the parameter's value will remain the same even when the variable is reassigned in +following iterations.

+

Another solution is to pass the variable as an argument to the function/lambda when it is called.

+

This rule raises an issue when a function or lambda references a variable defined in an enclosing loop.

Noncompliant Code Example

 def run():
@@ -12,6 +22,20 @@ 

Noncompliant Code Example

def func(): return i # Noncompliant mylist.append(func) + +def example_of_api_change(): + """" + Passing loop variable as default values also makes sure that the code is future-proof. + For example the following code will work as intended with python 2 but not python 3. + Why? because "map" behavior changed. It now returns an iterator and only executes + the lambda when required. The same is true for other functions such as "filter". + """ + lst = [] + for i in range(5): + lst.append(map(lambda x: x + i, range(3))) # Noncompliant + for sublist in lst: + # prints [4, 5, 6] x 4 with python 3, with python 2 it prints [0, 1, 2], [1, 2, 3], ... + print(list(sublist))

Compliant Solution

@@ -23,21 +47,33 @@ 

Compliant Solution

def func(i=i): # same for nested functions return i mylist.append(func) + +def example_of_api_change(): + """" + This will work for both python 2 and python 3. + """ + lst = [] + for i in range(5): + lst.append(map(lambda x, value=i: x + value, range(3))) # Passing "i" as a default value + for sublist in lst: + print(list(sublist))

Exceptions

-

No issue will be raised if the function or lambda is only called in the same loop.

+

No issue will be raised if the function or lambda is directly called in the same loop. This still makes the design difficult to understand but it +is less error prone.

 def function_called_in_loop():
     for i in range(10):
-        print((lambda param: param * i)(42))
+        print((lambda param: param * i)(42)) # Calling the lambda directly
 
         def func(param):
             return param * i
 
-        print(func(42))
+        print(func(42))  # Calling "func" directly
 

See

diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2733.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2733.html index 5619fa4f66..8875b42ad0 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2733.html +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2733.html @@ -8,4 +8,6 @@

Noncompliant Code Example

def __exit__(self, exc_type, exc_val): # Noncompliant pass +

Deprecated

+

This rule is deprecated; use {rule:python:S5722} instead.

diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2733.json b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2733.json index 1501d5da9a..2ac2f821a5 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2733.json +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2733.json @@ -1,7 +1,7 @@ { "title": "\"__exit__\" should accept type, value, and traceback arguments", "type": "BUG", - "status": "ready", + "status": "deprecated", "remediation": { "func": "Constant\/Issue", "constantCost": "5min" diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5655.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5655.html index 6f2dae2f9c..6d0cc72e54 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5655.html +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5655.html @@ -1,16 +1,31 @@ -

Python does not check the type of arguments provided to functions. However builtin functions and methods expect a specific type for each parameter. -Providing an argument of the wrong type will make your program fail.

-

This rule raises an issue when a builtin function is called with an argument of the wrong type.

+

The CPython interpreter does not check arguments type when functions are called. However a function can express the type it expects for each +argument in its documentation or by using Type Hints. Calling such a function with an argument +of a different type can easily create a bug. Even if it works right now it can fail later when APIs evolve or when type checks are added (ex: with +isinstance).

+

This rule raises an issue when a function or method is called with an argument of a different type than the one described in its type annotations. +It also checks argument types for builtin functions.

Noncompliant Code Example

-round("42.3")  # Noncompliant
+def func(var: str):
+    pass
+
+func(42)  # Noncompliant
+
+len(1)  # Noncompliant
 

Compliant Solution

-round(42.3)
+def func(var: str):
+    pass
+
+func("42")
+
+len("1")
 

See

diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5655.json b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5655.json index c7c5351d29..3d5ce90c8c 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5655.json +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5655.json @@ -1,11 +1,11 @@ { "title": "Arguments given to functions should be of an expected type", - "type": "BUG", + "type": "CODE_SMELL", "status": "ready", "tags": [ - + "suspicious" ], - "defaultSeverity": "Blocker", + "defaultSeverity": "Critical", "ruleSpecification": "RSPEC-5655", "sqKey": "S5655", "scope": "All" diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5685.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5685.html index 9c50c46ad3..c8d4254b59 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5685.html +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5685.html @@ -1,7 +1,7 @@

The walrus operator := (also known as "assignment expression") should be used with caution as it can easily make code more difficult to understand and thus maintain. In such case it is advised to refactor the code and use an assignment statement (i.e. =) instead.

-

This rule raises an issue raises an issue when the walrus operator is used in a way which makes the code confusing, as described in This rule raises an issue when the walrus operator is used in a way which makes the code confusing, as described in PEP 572.

Noncompliant Code Example

diff --git a/sonarpedia.json b/sonarpedia.json
index 6c06175087..5bc91f0824 100644
--- a/sonarpedia.json
+++ b/sonarpedia.json
@@ -3,7 +3,7 @@
   "languages": [
     "PY"
   ],
-  "latest-update": "2020-03-24T08:46:39.066Z",
+  "latest-update": "2020-04-17T11:28:06.007445200Z",
   "options": {
     "no-language-in-filenames": true,
     "preserve-filenames": true