Skip to content

Commit c492c27

Browse files
Update rule metadata (#680)
1 parent 2151bf1 commit c492c27

File tree

7 files changed

+70
-17
lines changed

7 files changed

+70
-17
lines changed

python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S1515.html

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
<p>Nested functions and lambdas can reference variables defined in enclosing scopes. This can create tricky bugs when the variable and the function
2-
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
3-
the iteration where the function was defined.</p>
4-
<p>This rule raises an issue when a nested function or lambda references a variable defined in an enclosing loop.</p>
2+
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
3+
seeing the values corresponding to the iteration where the function was defined.</p>
4+
<p>Capturing loop variables might work for some time but:</p>
5+
<ul>
6+
<li> it makes the code difficult to understand. </li>
7+
<li> it increases the risk of introducing a bug when the code is refactored or when dependencies are updated. See an example with the builtin "map"
8+
below. </li>
9+
</ul>
10+
<p>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
11+
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
12+
following iterations.</p>
13+
<p>Another solution is to pass the variable as an argument to the function/lambda when it is called.</p>
14+
<p>This rule raises an issue when a function or lambda references a variable defined in an enclosing loop.</p>
515
<h2>Noncompliant Code Example</h2>
616
<pre>
717
def run():
@@ -12,6 +22,20 @@ <h2>Noncompliant Code Example</h2>
1222
def func():
1323
return i # Noncompliant
1424
mylist.append(func)
25+
26+
def example_of_api_change():
27+
""""
28+
Passing loop variable as default values also makes sure that the code is future-proof.
29+
For example the following code will work as intended with python 2 but not python 3.
30+
Why? because "map" behavior changed. It now returns an iterator and only executes
31+
the lambda when required. The same is true for other functions such as "filter".
32+
"""
33+
lst = []
34+
for i in range(5):
35+
lst.append(map(lambda x: x + i, range(3))) # Noncompliant
36+
for sublist in lst:
37+
# prints [4, 5, 6] x 4 with python 3, with python 2 it prints [0, 1, 2], [1, 2, 3], ...
38+
print(list(sublist))
1539
</pre>
1640
<h2>Compliant Solution</h2>
1741
<pre>
@@ -23,21 +47,33 @@ <h2>Compliant Solution</h2>
2347
def func(i=i): # same for nested functions
2448
return i
2549
mylist.append(func)
50+
51+
def example_of_api_change():
52+
""""
53+
This will work for both python 2 and python 3.
54+
"""
55+
lst = []
56+
for i in range(5):
57+
lst.append(map(lambda x, value=i: x + value, range(3))) # Passing "i" as a default value
58+
for sublist in lst:
59+
print(list(sublist))
2660
</pre>
2761
<h2>Exceptions</h2>
28-
<p>No issue will be raised if the function or lambda is only called in the same loop.</p>
62+
<p>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
63+
is less error prone.</p>
2964
<pre>
3065
def function_called_in_loop():
3166
for i in range(10):
32-
print((lambda param: param * i)(42))
67+
print((lambda param: param * i)(42)) # Calling the lambda directly
3368

3469
def func(param):
3570
return param * i
3671

37-
print(func(42))
72+
print(func(42)) # Calling "func" directly
3873
</pre>
3974
<h2>See</h2>
4075
<ul>
4176
<li> <a href="https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments">The Hitchhiker's Guide to Python - Common Gotchas</a> </li>
77+
<li> Python documentation - <a href="https://docs.python.org/3/reference/compound_stmts.html#function-definitions">Function definitions</a> </li>
4278
</ul>
4379

python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2733.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ <h2>Noncompliant Code Example</h2>
88
def __exit__(self, exc_type, exc_val): # Noncompliant
99
pass
1010
</pre>
11+
<h2>Deprecated</h2>
12+
<p>This rule is deprecated; use {rule:python:S5722} instead.</p>
1113

python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S2733.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"title": "\"__exit__\" should accept type, value, and traceback arguments",
33
"type": "BUG",
4-
"status": "ready",
4+
"status": "deprecated",
55
"remediation": {
66
"func": "Constant\/Issue",
77
"constantCost": "5min"
Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,31 @@
1-
<p>Python does not check the type of arguments provided to functions. However builtin functions and methods expect a specific type for each parameter.
2-
Providing an argument of the wrong type will make your program fail.</p>
3-
<p>This rule raises an issue when a builtin function is called with an argument of the wrong type.</p>
1+
<p>The CPython interpreter does not check arguments type when functions are called. However a function can express the type it expects for each
2+
argument in its documentation or by using <a href="https://www.python.org/dev/peps/pep-0484/">Type Hints</a>. Calling such a function with an argument
3+
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
4+
<code>isinstance</code>).</p>
5+
<p>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.
6+
It also checks argument types for builtin functions.</p>
47
<h2>Noncompliant Code Example</h2>
58
<pre>
6-
round("42.3") # Noncompliant
9+
def func(var: str):
10+
pass
11+
12+
func(42) # Noncompliant
13+
14+
len(1) # Noncompliant
715
</pre>
816
<h2>Compliant Solution</h2>
917
<pre>
10-
round(42.3)
18+
def func(var: str):
19+
pass
20+
21+
func("42")
22+
23+
len("1")
1124
</pre>
1225
<h2>See</h2>
1326
<ul>
1427
<li> <a href="https://docs.python.org/3/library/functions.html#built-in-funcs">Python documentation - builtins</a> </li>
28+
<li> <a href="https://www.python.org/dev/peps/pep-0484/">PEP 484 <del></del> Type Hints</a> </li>
29+
<li> <a href="https://docs.python.org/3/library/typing.html">Python documentation - typing — Support for type hints</a> </li>
1530
</ul>
1631

python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5655.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
22
"title": "Arguments given to functions should be of an expected type",
3-
"type": "BUG",
3+
"type": "CODE_SMELL",
44
"status": "ready",
55
"tags": [
6-
6+
"suspicious"
77
],
8-
"defaultSeverity": "Blocker",
8+
"defaultSeverity": "Critical",
99
"ruleSpecification": "RSPEC-5655",
1010
"sqKey": "S5655",
1111
"scope": "All"

python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5685.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<p>The <a href="https://www.python.org/dev/peps/pep-0572">walrus operator</a> <code>:=</code> (also known as "assignment expression") should be used
22
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
33
assignment statement (i.e. <code>=</code>) instead.</p>
4-
<p>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 <a
4+
<p>This rule raises an issue when the walrus operator is used in a way which makes the code confusing, as described in <a
55
href="https://www.python.org/dev/peps/pep-0572/#exceptional-cases">PEP 572</a>.</p>
66
<h2>Noncompliant Code Example</h2>
77
<pre>

sonarpedia.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"languages": [
44
"PY"
55
],
6-
"latest-update": "2020-03-24T08:46:39.066Z",
6+
"latest-update": "2020-04-17T11:28:06.007445200Z",
77
"options": {
88
"no-language-in-filenames": true,
99
"preserve-filenames": true

0 commit comments

Comments
 (0)