Skip to content

omit exception does not work with generator methods #773

Open
@amirreza8002

Description

@amirreza8002

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions