Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
<p>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.</p>
<p>This rule raises an issue when a nested function or lambda references a variable defined in an enclosing loop.</p>
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.</p>
<p>Capturing loop variables might work for some time but:</p>
<ul>
<li> it makes the code difficult to understand. </li>
<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"
below. </li>
</ul>
<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
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.</p>
<p>Another solution is to pass the variable as an argument to the function/lambda when it is called.</p>
<p>This rule raises an issue when a function or lambda references a variable defined in an enclosing loop.</p>
<h2>Noncompliant Code Example</h2>
<pre>
def run():
Expand All @@ -12,6 +22,20 @@ <h2>Noncompliant Code Example</h2>
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))
</pre>
<h2>Compliant Solution</h2>
<pre>
Expand All @@ -23,21 +47,33 @@ <h2>Compliant Solution</h2>
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))
</pre>
<h2>Exceptions</h2>
<p>No issue will be raised if the function or lambda is only called in the same loop.</p>
<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
is less error prone.</p>
<pre>
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
</pre>
<h2>See</h2>
<ul>
<li> <a href="https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments">The Hitchhiker's Guide to Python - Common Gotchas</a> </li>
<li> Python documentation - <a href="https://docs.python.org/3/reference/compound_stmts.html#function-definitions">Function definitions</a> </li>
</ul>

Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ <h2>Noncompliant Code Example</h2>
def __exit__(self, exc_type, exc_val): # Noncompliant
pass
</pre>
<h2>Deprecated</h2>
<p>This rule is deprecated; use {rule:python:S5722} instead.</p>

Original file line number Diff line number Diff line change
@@ -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"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
<p>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.</p>
<p>This rule raises an issue when a builtin function is called with an argument of the wrong type.</p>
<p>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 <a href="https://www.python.org/dev/peps/pep-0484/">Type Hints</a>. 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
<code>isinstance</code>).</p>
<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.
It also checks argument types for builtin functions.</p>
<h2>Noncompliant Code Example</h2>
<pre>
round("42.3") # Noncompliant
def func(var: str):
pass

func(42) # Noncompliant

len(1) # Noncompliant
</pre>
<h2>Compliant Solution</h2>
<pre>
round(42.3)
def func(var: str):
pass

func("42")

len("1")
</pre>
<h2>See</h2>
<ul>
<li> <a href="https://docs.python.org/3/library/functions.html#built-in-funcs">Python documentation - builtins</a> </li>
<li> <a href="https://www.python.org/dev/peps/pep-0484/">PEP 484 <del></del> Type Hints</a> </li>
<li> <a href="https://docs.python.org/3/library/typing.html">Python documentation - typing — Support for type hints</a> </li>
</ul>

Original file line number Diff line number Diff line change
@@ -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"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<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
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. <code>=</code>) instead.</p>
<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
<p>This rule raises an issue when the walrus operator is used in a way which makes the code confusing, as described in <a
href="https://www.python.org/dev/peps/pep-0572/#exceptional-cases">PEP 572</a>.</p>
<h2>Noncompliant Code Example</h2>
<pre>
Expand Down
2 changes: 1 addition & 1 deletion 2 sonarpedia.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.