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

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

The newest version!

This rule raises an issue when:

  • an __exit__ method has a bare raise outside of an except block.
  • an __exit__ method raises the exception provided as parameter.

Why is this an issue?

Methods __enter__ and __exit__ make it possible to implement objects which can be used as the expression of a with statement:

with MyContextManager() as c :
    ... # do something with c

This statement can be rewritten as a try...finally and an explicit call to the __enter__ and __exit__ methods:

c = MyContextManager()
c.__enter__()
try:
    ... # do something with c
finally:
    c.__exit__()

The __exit__ is the method of a statement context manager which is called when exiting the runtime context related to this object.

If an exception is supplied as an argument, its propagation can be suppressed by having the method return a truthy value. Otherwise, the exception will be processed normally upon exit from the method.

The special method __exit__ should only raise an exception when it fails. It should never raise the provided exception, it is the caller’s responsibility. The __exit__ method can filter provided exceptions by simply returning True or False. Raising this exception will make the stack trace difficult to understand.

How to fix it

To fix this issue, make sure to avoid raising the exception provided to an __exit__ method.

Code examples

Noncompliant code example

class MyContextManager:
    def __enter__(self):
        return self

    def __exit__(self, *args):
        raise  # Noncompliant: __exit__ method has a bare raise outside of an except block.

class MyContextManager:
    def __enter__(self):
        return self

    def __exit__(self, *args):
        raise args[2]  # Noncompliant: __exit__() methods should not reraise the provided exception; this is the caller’s responsibility.

class MyContextManager:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        raise exc_value # Noncompliant: __exit__() methods should not reraise the provided exception; this is the caller’s responsibility.

Compliant solution

class MyContextManager:
    def __enter__(self, stop_exceptions):
        return self

    def __exit__(self, *args):
        try:
            ...
        except:
            raise  # No issue when raising another exception. The __exit__ method can fail and raise an exception

class MyContextManager:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        pass # by default the function will return None, which is always False, and the exc_value will naturally raise.

class MyContextManager:
    def __enter__(self, stop_exceptions):
        return self

    def __exit__(self, *args):
        raise MemoryError("No more memory")  # This is ok too.

Resources

Documentation





© 2015 - 2025 Weber Informatics LLC | Privacy Policy