Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What type of message "Exception ignored in" is?

Here's code:

def g():
    try:
        yield 1
        yield 2
        yield 3
    except GeneratorExit:
        yield 4

gen = g()
print(gen.__next__())

If you run it you'll see:

1
Exception ignored in: <generator object g at 0x00000216BB546A98>
RuntimeError: generator ignored GeneratorExit

I understand what happened, but I can't find what type of message this warning is.

Looks like it's not logging warning (I can't remove it setting logging level). It's also not warnings warning (It doesn't look like what we get when call warnings.warn).

I thought it can be associated with exception, but I can't catch it with sys.excepthook, while msg itself disappears:

import sys

def hook(exc_type, exc_val, tb):
    print(exc_type, exc_val, tb)  # Nothing prints, while msg disappear

sys.excepthook = hook

How can I catch this warning?

How can I manually create this type of warning?

like image 886
Mikhail Gerasimov Avatar asked Jun 26 '16 08:06

Mikhail Gerasimov


1 Answers

As some have noted, not everyone always gets the behaviour that you describe. For instance, you won't get this behaviour at the REPL. To reproduce this behaviour on the REPL you have to add del gen at the end. This lets us know where the warning is coming. The warning is coming from the clean up function of the generator object, which has noticed that the generator has not exited cleanly.

What specifically has happened is that the generator has raised an exception whilst the interpreter is trying clean up the generator and release its resources. The interpreter has no way to propagate this exception back, so instead it logs this state and carries on. Specifically, PyErr_WriteUnraisable is is being called. And here is how it is being called (comments mine).

void
_PyGen_Finalize(PyObject *self)
{
    ...

    if (gen is a coroutine) {
        // special error detecting logic for coroutines
    }
    else {
        res = gen_close(gen, NULL); // <- raises GeneratorExit
    }

    if (res == NULL) {
        if (PyErr_Occurred()) {
            PyErr_WriteUnraisable(self);
        }
    }
    else {
        Py_DECREF(res);
    }

    ...
}
like image 117
Dunes Avatar answered Oct 20 '22 17:10

Dunes