All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.l10n.py.rules.python.S3862.html Maven / Gradle / Ivy

There is a newer version: 4.23.0.17664
Show newest version

This rule raises an issue when a non iterable object is used in a for-in loop, in a yield from or when it is unpacked.

Why is this an issue?

for-in loops, yield from and iterable unpacking only work with iterable objects. In order to be iterable, an object should have either an __iter__ method or a __getitem__ method implementing the Sequence protocol.

When trying to iterate over an object which does not implement the required methods, a TypeError will be raised.

Below is an example of a basic implementation of a iterator with __iter__:

class IterExample(object):
    def __init__(self):
        self._values = [1,2,3,4]

    def __iter__(self):
        return iter(self._values)

Here is a similar example with __getitem__:

class GetItemExample(object):
    def __init__(self):
        self._values = [1,2,3,4]

    def __getitem__(self, item):
        return self._values[item]

These implementations make it possible to execute the following program:

my_iterator = IterExample()
for i in my_iterator:
    print(i) # Prints 1,2,3,4

my_iterator = GetItemExample()
for i in my_iterator:
    print(i) # Prints 1,2,3,4

Note also that iterating over an asynchronous iterable, i.e. an object having the __aiter__ method, requires the use of async for ... in instead of for ... in. Failing to provide the async keyword will result in a TypeError stating the object is not iterable.

How to fix it

Make sure your object is an iterable when using it in for-in loops,yield from and unpacking statements, by implementing __iter__ or __getitem__. To iterate over an asynchronous iterable, make sure to use the async keyword, i.e async for …​ in.

Code examples

Noncompliant code example

class MyIterable:
    def __init__(self, values):
        self._values = values

my_iterable = MyIterable(range(10))

for a in my_iterable:  # Noncompliant: MyIterable is not an iterable
    print(a)

a, b, *c = my_iterable  # Noncompliant: MyIterable is not an iterable

# yield from
def generator():
    yield from my_iterable  # Noncompliant: MyIterable is not an iterable

For async generators:

async def async_function():
  # async generators
  async def async_generator():
      yield 1

  for a in async_generator():  # Noncompliant: "async" is missing before "for"
      print(a)

Compliant solution

class MyIterable:
    def __init__(self, values):
        self._values = values

    def __iter__(self):
        return iter(self._values)

my_iterable = MyIterable(range(10))

for a in my_iterable:
    print(a)

a, b, *c = my_iterable

# yield from
def generator():
    yield from my_iterable

Make sure to use the async keyword when iterating over async generators.

async def async_function():
  # async generators
  async def async_generator():
      yield 1

  async for a in async_generator():
      print(a)

Resources

Documentation

Standards





© 2015 - 2024 Weber Informatics LLC | Privacy Policy