Skip to content

Misleading return type for RequestsMock.__exit__ #766

@olavmo-sikt

Description

@olavmo-sikt

Describe the bug

The RequestsMock.__exit__(...) method will return True in some cases.
Returning True indicates that it may have suppressed an exception:

If an exception is supplied, and the method wishes to suppress the exception (i.e., prevent it from being propagated), it should return a true value. Otherwise, the exception will be processed normally upon exit from this method.

(https://docs.python.org/3/reference/datamodel.html#object.__exit__)

This confuses the Pyright type checker since it cannot assume that all code within the context manager has been successfully executed.
For example, it will assume that variables assigned within the with-statement can be unbound:

from responses import RequestsMock

with RequestsMock():
    foo = "bar"

assert foo == "bar"  # Pyright fails with: "foo" is possibly unbound

The __exit__(...)-method looks like the following:

def __exit__(self, type: Any, value: Any, traceback: Any) -> bool:
    success = type is None
    try:
         self.stop(allow_assert=success)
    finally:
        self.reset()
    return success

(https://github.com/getsentry/responses/blob/0.25.7/responses/__init__.py#L993-L999)

Which means that it will return True (asking for the exception to be suppressed) only if type is None (there is no exception to suppress).
If there is an exception, it will return False, propagating the exception.

Returning True is therefore unnecessary, and the method can be changed to return None with no change to its behavior:

-def __exit__(self, type: Any, value: Any, traceback: Any) -> bool:
+def __exit__(self, type: Any, value: Any, traceback: Any) -> None:
     success = type is None
     try:
          self.stop(allow_assert=success)
     finally:
         self.reset()
-    return success

Doing this enables Pyright to see that exceptions are propagated, and it will see that all the code in the with-statement is executed.
See example fix in Pyright playground.

Additional context

No response

Version of responses

0.25.7

Steps to Reproduce

from responses import RequestsMock

with RequestsMock():
    foo = "bar"

assert foo == "bar"  # Pyright fails with: "foo" is possibly unbound

See in Pyright playground

Expected Result

No type error.

Actual Result

Pyright fails with: "foo" is possibly unbound

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No fields configured for issues without a type.

    Projects

    Status

    Waiting for: Product Owner

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions