python/asyncio

Exception ignored in: <object repr() failed> when quit

ahuigo opened this issue · 3 comments

The following program sometime produces Exception ignored in: <object repr() failed> when quit

import asyncio
async def coro(name):
    await asyncio.sleep(1)
    print('coro {}: waiting for lock'.format(name))

loop = asyncio.get_event_loop()
coros = asyncio.gather(coro(1), coro(2 ))
loop.run_until_complete(coros)
loop.close()
quit()

Here is output of the program above.
My platform is : Mac OS X, python3.5.2

coro 1: waiting for lock
coro 2: waiting for lock
Exception ignored in: <object repr() failed>
Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.5.2_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/asyncio/tasks.py", line 85, in __del__
AttributeError: 'NoneType' object has no attribute '_PENDING'
Exception ignored in: <object repr() failed>
Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.5.2_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/asyncio/tasks.py", line 85, in __del__
AttributeError: 'NoneType' object has no attribute '_PENDING'

Hi,

I cannot reproduce the issue with python 3.5.2 on Linux.

I am not sure that why you would use quit() here: since the loop is closed and nothing else will be executed, your python script will exit anyway.

@Martiusweb I won't use quit() in my project , I'm just confused by this exception and I wanna figure out it.
I'll close this issue since this is not a bug, but a wrong use of loop

@AHui132 @Martiusweb
For posterity, as I had the same issue and found #423 by searching on google, and I assume there will be some other people having similar problems.

Conclusion is you need to explicitly del your tasks to prevent these types of errors.
Otherwise at the end, when all the finalizers run (order varies) it can happen that futures is already unloaded so futures._PENDING or futures.Future will not resolve properly, thus resulting in AttributeError: 'NoneType' object has no attribute '_PENDING'.

In my case both Tasks were actually FINISHED and everything was fine.

How did I find this? I have modified asyncio.Task._del_ in the following way:

  • replace futures._PENDING with 'PENDING'
  • added AttributeError exception handling for futures.Future
    if compat.PY34:
        def __del__(self):
            if self._state == 'PENDING' and self._log_destroy_pending:
                context = {
                    'task': self,
                    'message': 'Task was destroyed but it is pending!',
                }
                if self._source_traceback:
                    context['source_traceback'] = self._source_traceback
                self._loop.call_exception_handler(context)
            try:
                futures.Future.__del__(self)
            except AttributeError:
                name = getattr(self._coro, '__qualname__', None) or getattr(self._coro, '__name__', None)
                code = getattr(self._coro, 'gi_code', None) or getattr(self._coro, 'cr_code', None)
                frame = getattr(self._coro, 'gi_frame', None) or getattr(self._coro, 'cr_frame', None)

                filename = code.co_filename
                lineno = (frame and frame.f_lineno) or code.co_firstlineno

                print('!> Finalizer error in {}() {} at {} line {}'.format(
                    name,
                    self._state,
                    filename, lineno
                ))