quamash icon indicating copy to clipboard operation
quamash copied to clipboard

Name mangling causes 'NoneType' object has no attribute 'append'

Open Cediddi opened this issue 9 years ago • 10 comments

While I was looking at the code I saw some double underscored attributes. One of them was __timers in QEventLoop. When I was trying the library I had series of same traceback. I tried to debug the problem, When I tried to access __timers in _add_callback I had AttributeError and when I did dir(self) I saw _QEventLoop__timers attribute.

This library is too much for me to understand but as far as I see, there's a problem with name mangling here.

Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/quamash/__init__.py", line 215, in <lambda>
    signaller.signal.connect(lambda callback, args: self.call_soon(callback, *args))
  File "/usr/local/lib/python3.4/dist-packages/quamash/__init__.py", line 331, in call_soon
    return self.call_later(0, callback, *args)
  File "/usr/local/lib/python3.4/dist-packages/quamash/__init__.py", line 307, in call_later
    return self._add_callback(asyncio.Handle(callback, args, self), delay)
  File "/usr/local/lib/python3.4/dist-packages/quamash/__init__.py", line 325, in _add_callback
    self.__timers.append(timer)
AttributeError: 'NoneType' object has no attribute 'append'

Cediddi avatar Jan 06 '16 12:01 Cediddi

Are you on windows? On Jan 6, 2016 4:26 AM, "Umut Karcı" [email protected] wrote:

While I was looking at the code I saw some double underscored attributes One of them was __timers in QEventLoop When I was trying the library I had series of same traceback I tried to debug the problem, When I tried to access __timers in _add_callback I had AttributeError and when I did dir(self) I saw _QEventLoop__timers attribute

This library is too much for me to understand but as far as I see, there's a problem with name mangling here

Traceback (most recent call last): File "/usr/local/lib/python34/dist-packages/quamash/__init__py", line 215, in signallersignalconnect(lambda callback, args: selfcall_soon(callback, *args)) File "/usr/local/lib/python34/dist-packages/quamash/__init__py", line 331, in call_soon return selfcall_later(0, callback, *args) File "/usr/local/lib/python34/dist-packages/quamash/__init__py", line 307, in call_later return self_add_callback(asyncioHandle(callback, args, self), delay) File "/usr/local/lib/python34/dist-packages/quamash/__init__py", line 325, in _add_callback self__timersappend(timer) AttributeError: 'NoneType' object has no attribute 'append'

— Reply to this email directly or view it on GitHub https://github.com/harvimt/quamash/issues/60.

harvimt avatar Jan 06 '16 16:01 harvimt

I don't understand why name mangling would cause self.__timers to be None. If anything you should get an AttributeError.

aknuds1 avatar Jan 06 '16 17:01 aknuds1

Anyhow, when you debug, you have to use the mangled name of course since at runtime the attribute name will already be mangled.

aknuds1 avatar Jan 06 '16 17:01 aknuds1

"/usr/local/lib/"

probably not a windows problem then.

hrm. if you can produce a reduced test case that's always the best.

On Wed, Jan 6, 2016 at 9:40 AM, Arve Knudsen [email protected] wrote:

Anyhow, when you debug, you have to use the mangled name of course since at runtime the attribute name will already be mangled.

— Reply to this email directly or view it on GitHub https://github.com/harvimt/quamash/issues/60#issuecomment-169399925.

harvimt avatar Jan 06 '16 18:01 harvimt

Sorry for late response, Okay, I'll try to create a test case as soon as possible. Meanwhile, this is some of my code, I hope it helps until I can create a test case.

### gui.py
app = QtWidgets.QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)

### downloader.py
def _start(queue):
    loop = asyncio.get_event_loop()
    results = loop.run_until_complete(asyncio.gather(*[worker(page_obj) for page_obj in queue]))

I'm on python 3.4, Linux Mint 17.3 (ubuntu 14.04.3 derivative) and PyQt 5.2.1

Cediddi avatar Jan 07 '16 16:01 Cediddi

Hey, I have encountered a similar traceback:

Connected to pydev debugger (build 145.260)
Error in atexit._run_exitfuncs:
Traceback (most recent call last):
  File "/usr/local/src/test3.py", line 26, in on_exit
    task.cancel()
  File "/usr/lib/python3.4/asyncio/tasks.py", line 211, in cancel
    if self._fut_waiter.cancel():
  File "/usr/lib/python3.4/asyncio/futures.py", line 228, in cancel
    self._schedule_callbacks()
  File "/usr/lib/python3.4/asyncio/futures.py", line 243, in _schedule_callbacks
    self._loop.call_soon(callback, self)
  File "/usr/local/lib/python3.4/dist-packages/quamash/__init__.py", line 352, in call_soon
    return self.call_later(0, callback, *args)
  File "/usr/local/lib/python3.4/dist-packages/quamash/__init__.py", line 329, in call_later
    return self._add_callback(asyncio.Handle(callback, args, self), delay)
  File "/usr/local/lib/python3.4/dist-packages/quamash/__init__.py", line 346, in _add_callback
    self.__timers.append(timer)
AttributeError: 'NoneType' object has no attribute 'append'
Task was destroyed but it is pending!
task: <Task pending coro=<master() done, defined at /usr/local/src/test3.py:35> wait_for=<Future cancelled>>

This is my test code:

from atexit import register, unregister
from PySide.QtGui import QApplication, QProgressBar
from quamash import QEventLoop
import sys
import asyncio
import signal
import os

app = QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)  # NEW must set the event loop

loop.add_signal_handler(signal.SIGINT, lambda *a: loop.stop())


def safe_spawn(coro):

    def on_done(*a, **kw):
        assert isinstance(task, asyncio.Task)
        task.result()
        unregister(on_exit)

    def on_exit(*a, **kw):
        assert isinstance(task, asyncio.Task)
        task.remove_done_callback(on_done)
        task.cancel()

    task = loop.create_task(coro)
    assert isinstance(task, asyncio.Task)
    task.add_done_callback(on_done)
    register(on_exit)

    return task

@asyncio.coroutine
def master():

    process = yield from asyncio.create_subprocess_exec(
        '/usr/bin/env', 'true')
    yield from process.wait()

    progress = QProgressBar()
    progress.setRange(0, 99)
    progress.show()

    os.system("{ sleep 0.5; kill -INT %s; } &" % os.getpid())

    yield from asyncio.sleep(1)
    progress.hide()

    loop.call_later(2, lambda: safe_spawn(master()))


with loop:

    safe_spawn(master())
    loop.run_forever()


I think there is a problem with my shutdown logic, but I hope this helps @Cediddi

croepha avatar Apr 11 '16 20:04 croepha

OK, so this has nothing to do with name mangling. It's clearly a problem with trying to run _add_callback after the loop is closed.

If you're getting this, you may want to refrain from using with loop and call loop.close manually, when you know that you're done with the loop. (or just let garbage collection clean it up)

I may work on making the error message friendlier.

(or we've found out why the builtin event loop doesn't use a context manager)

harvimt avatar Apr 11 '16 20:04 harvimt

Thanks David, but my issue was on runtime, not at exit. Problem is I left the project, so this issue is no longer in my scope.

Cediddi avatar Apr 11 '16 20:04 Cediddi

I have also seen that error..

  • Trying to use:
with loop: ## context manager calls .close() when loop completes, and releases all resources
    loop.run_until_complete(master())


with loop: ## context manager calls .close() when loop completes, and releases all resources
    loop.run_until_complete(master())

the application is closed with a deadly report:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "D:\Python34\lib\site-packages\quamash-0.5.5-py3.4.egg\quamash\__init__.p
y", line 260, in run_until_complete
  File "D:\Python34\lib\asyncio\tasks.py", line 505, in async
    task = loop.create_task(coro_or_future)
  File "D:\Python34\lib\asyncio\base_events.py", line 172, in create_task
    task = tasks.Task(coro, loop=self)
  File "D:\Python34\lib\asyncio\tasks.py", line 74, in __init__
    self._loop.call_soon(self._step)
  File "D:\Python34\lib\site-packages\quamash-0.5.5-py3.4.egg\quamash\__init__.p
y", line 352, in call_soon
  File "D:\Python34\lib\site-packages\quamash-0.5.5-py3.4.egg\quamash\__init__.p
y", line 329, in call_later
  File "D:\Python34\lib\site-packages\quamash-0.5.5-py3.4.egg\quamash\__init__.p
y", line 346, in _add_callback
AttributeError: 'NoneType' object has no attribute 'append'
>>> Traceback (most recent call last):
  File "D:\Python34\lib\site-packages\quamash-0.5.5-py3.4.egg\quamash\__init__.p
y", line 192, in timerEvent
  File "D:\Python34\lib\site-packages\quamash-0.5.5-py3.4.egg\quamash\__init__.p
y", line 335, in upon_timeout
TypeError: argument of type 'NoneType' is not iterable

F:\miguel 2\Proyectos\instaladores>

Salmista-94 avatar Apr 29 '16 19:04 Salmista-94

this is expected. once a loop closes it can't be started again.

(though the error message could be better)

(I'm starting to realize why the builtin loop isn't a context manager maybe?)

If you start/stop the loop multiple times then you need to manage the loop yourself, and call close on it when you're done.

harvimt avatar Apr 29 '16 20:04 harvimt