Skip to content

omit exception does not work with generator methods #773

@amirreza-sf80

Description

@amirreza-sf80

hi
so in my testings i have found that, possibly, omit exception lacks generator support (e.g: iter_keys and sscan_iter)

this is becaouse omit_exception calls the method https://github.com/jazzband/django-redis/blob/master/django_redis/cache.py#L29 and catches errors
but, calling a generator doesn't raise any errors, it'll only error once you iterate over it

as a simple example you can run:

>>> def my_gen():
...     for i in range(10):
...         yield
...         raise
...         
>>> my_gen()
<generator object my_gen at 0x7f8fc7a56800>
>>> for i in my_gen():
...     print(1)
...     
1
Traceback (most recent call last):
  File "<python-input-4>", line 1, in <module>
    for i in my_gen():
             ~~~~~~^^
  File "<python-input-2>", line 4, in my_gen
    raise
RuntimeError: No active exception to reraise

anyway the way i went to fix it was with something like this:

def omit_exception(method: Callable | None = None, return_value: Any | None = None):
    """
    Simple decorator that intercepts connection
    errors and ignores these if settings specify this.
    """

    if method is None:
        return functools.partial(omit_exception, return_value=return_value)

    @functools.wraps(method)
    def _decorator(self, *args, **kwargs):
        try:
            return method(self, *args, **kwargs)
        except ConnectionInterrupted as e:
            if getattr(self, "_ignore_exceptions", None) or getattr(
                self._backend, "_ignore_exceptions"
            ):
                if getattr(self, "_log_ignored_exceptions", None) or getattr(
                    self._backend, "_log_ignored_exceptions"
                ):
                    logger = getattr(self, "logger", None) or getattr(
                        self._backend, "logger"
                    )
                    logger.exception("Exception ignored")

                return return_value
            raise e.__cause__  # noqa: B904

    @functools.wraps(method)
    def _generator_decorator(self, *args, **kwargs):
        try:
            for item in method(self, *args, **kwargs):
                yield item
        except ConnectionInterrupted as e:
            if getattr(self, "_ignore_exceptions", None) or getattr(
                self._backend, "_ignore_exceptions"
            ):
                if getattr(self, "_log_ignored_exceptions", None) or getattr(
                    self._backend, "_log_ignored_exceptions"
                ):
                    logger = getattr(self, "logger", None) or getattr(
                        self._backend, "logger"
                    )
                    logger.exception("Exception ignored")
                return return_value
            raise e.__cause__

    wrapper = _generator_decorator if inspect.isgeneratorfunction(method) else _decorator

let me know if this is ok with you , i can open a PR, or you can commit it as you wish

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions