Python Analyzer Updates - February & March 2021

The Python analyzer can detect 9 new issues and can automatically fix 15 more issues now.
We have also made some improvements in the existing autofixers and fixed the false positives you reported!

Here is a detailed changelog:

New Issues:

  • PTC-W0052: Field duplicates the name of its containing class
class Orange:
    '''We mean, the fruit.'''
    orange = "#FFA500"
    
    # Other class implementations
    
    def get_orange(self):
        return abc

fruit = Orange()
render_to_frontend(fruit.orange)  # Rendering a color, but one can get confused with the fruit
render_bg(fruit.get_orange)  # Not clear that `get_orange` is returning a color
  • PTC-W0055: Set size changed during iteration
magic_numbers = {0, 1, 1, 2, 3, 5}

for elem in magic_numbers:
    magic_numbers.add(get_next(elem))  # This will raise a `RuntimeError`.
  • PTC-W0056: Dictionary size changed during iteration
basket = {"oranges": 2, "apples": 4, "mangoes": 10}

for fruit in basket:
    if fruit == "apples":
        del basket[fruit] # Runtime Error
  • PTC-W0057: Sequence value overwritten unconditionally
some_numbers = [1, 2, 3, 4, 5]
some_numbers[0] = 3
some_numbers[0] = 4  # unconditionally overwritting the existing value

mymap = {'one': 1, 'two': 2}
mymap['one'] = 4
mymap['one'] = 3 # unconditionally overwritting value mapped to `one`
  • PTC-W0059: yield would not work as expected in the magic method
class MyClass:
    def __init__(self):
        yield 1
  • PTC-W0060: Implicit enumerate calls found
for index in range(len(mylist)):
    ...
  • PTC-W0063: Unguarded next inside generator
def get_team_structure(team):
    for team in class:
        students = iter(team)
        # StopIteration exception will be raised if team doesn't have elements.
        leader = next(students)
        members = [m for m in students]
        yield leader, members
  • PTC-W0066: Use of =+ / =- looks ambiguous
    This issue is added to detect the use of operator pairs (=+ / =-) without any space after =.
    This looks ambiguous and can possibly be a typo for += / -=.
total = 10
count = 5
total =+ count # total = 5, Addition assignment doesn't take place
loss =- count # loss = -5, Not clear whether intent is to assign the inverse or perfrom Subtraction assignment
  • PTC-W0908: Use of unique_for constrant found
class MyModel(models.Model):
    date = models.DateField()
    somefield = models.CharField(unique_for_date='date')

New Autofixes:

  • PTC-W0029: Flask app detected with DEBUG mode enabled

The autofix will change debug=True to debug=False.

  • PTC-W0054: Special method should return NotImplemented

This fixer will change NotImplementedError to NotImplemented for special methods.

  • PTC-W0055: Set size changed during iteration

The fixer will change the flagged code snippet to use a shallow copy of the set for iteration so that changes can be made in the original set during iteration.

  • PTC-W0056: Dictionary size changed during iteration

The fixer will change the flagged code snippet to use a shallow copy of the dictionary for iteration so that changes can be made in the original dict during iteration.

  • PTC-W0066: Use of =+ / =- looks ambiguous

This autofix should be reviewed by the user. At the moment DeepSource assumes the issue to be a typo and autofixes the issue by changing =+ to += and =- to -= respectively.

Note: DeepSource will be providing multiple patches to select from in the future :confetti_ball:

  • PTC-W6003: Sensitive cookie without secure attribute

The fixer will set secure flag to True while setting a cookie.

  • PYL-E0101: return found in init

Since the __init__() method is required to return None, the fixer will remove the return statement.

  • PYL-E1141: Missing .items()

The issue is raised when .items() is missing during iterating a dictionary.
The fixer will add this to fix the issue.

  • PYL-W0126: Missing parentheses for a call in test

Fixer will add the missing parentheses for the function call.

  • PYL-W0127: Variable assigned to itself

Since it is unnecessary to assign a variable to itself without any modification,
the fixer will remove such assignments.

  • PYL-W0199: assert called on tuple

The fixer will change assert (x, y) to assert x, y.

  • PYL-W0602: Global variable is declared but not used

The fixer will remove unused global variables.

  • PYL-W1301: Format string contains unused key

The fixer will remove the unused keys from the format string.

  • PYL-W1401: Anomalous backslash detected

The fixer will convert the string with anomalous backslash into a raw string.

  • PYL-W1510: Subprocess run with ignored non-zero exit

subprocess.run uses a default of check=False, which means that a nonzero exit code will be
ignored by default, instead of raising an exception.

The fixer will set the check flag to True for all such calls.

Autofix Improvements

  • Improve Autofix for PYL-R1720 to fix occurrences like:

if 5 > 2: return 1
else: return 0

  • Handle multiple not in autofix for PYL-C0113
if not not 3 in [1, 2, 3]
    ...

This will now be fixed as:

if  3 in [1, 2, 3]
    ...
  • PTC-W0050 : Bugfix when the end element of a set has no comma

  • PTC-W0018 : Autofix unnecessary dict literal

X = dict([(1, 2)])
Is now fixed as:
X = {1: 2}

  • Improve Autofix for PTC-W0053

Preserve method docstring when changing return/pass to NotImplemented

Improve Autofix for PYL-R0205

Remove extra parentheses when there is no base class after Autofix

  • Handle negation for Simple Strings during Autofix of BAN-B101

  • Improve Auotifx for PYL-C1801 to handle cases like if not(len(X))

Checker Improvements:

  • Fix false positive in W0611

Don’t raise issue when an import is used as a keyword in a class definition

  • Suppress W0048 for if __name__ == "__main__":

  • Suppress false positive in PYL-W1201 when there is no string formatting

  • Fix false positive in PTC-W0062 when the nested with statements are not of the same kinds (synchronous and asynchronous).

  • Don’t raise PTC-W0020 if the function call has keyword arguments.
    Fixed false positives for calls like: dict({'foo': 'bar'}, **x)

  • Improve descriptions of all the performance issues.

1 Like