Code Monkey home page Code Monkey logo

quamash's People

Contributors

aknuds1 avatar erdewit avatar graingert avatar harvimt avatar horazont avatar insoleet avatar jck avatar korijn avatar neilgirdhar avatar peterazmanov avatar rr- avatar rustybird avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

quamash's Issues

pip fails to create wheel

Starting from pip v7, pip automatically creates wheels and caches them to speed up future installs(such as in virtualenvs).

When I pip install quamash, this happens:

Collecting quamash
  Using cached Quamash-0.5.1.tar.gz
Building wheels for collected packages: quamash
  Running setup.py bdist_wheel for quamash
  Complete output from command /home/jck/.local/share/virtualenvs/e6bfc48f73624c6/bin/python3 -c "import setuptools;__file__='/tmp/jck/pip-build-7ucxlcsb/quamash/setup.py';exec(compile(open(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" bdist_wheel -d /tmp/jck/tmpmbpkxqo7pip-wheel-:
  running bdist_wheel
  running build
  running build_py
  creating build
  creating build/lib
  creating build/lib/quamash
  copying quamash/_unix.py -> build/lib/quamash
  copying quamash/__init__.py -> build/lib/quamash
  copying quamash/_common.py -> build/lib/quamash
  copying quamash/_windows.py -> build/lib/quamash
  installing to build/bdist.linux-x86_64/wheel
  running install
  running install_lib
  creating build/bdist.linux-x86_64
  creating build/bdist.linux-x86_64/wheel
  creating build/bdist.linux-x86_64/wheel/quamash
  copying build/lib/quamash/_windows.py -> build/bdist.linux-x86_64/wheel/quamash
  copying build/lib/quamash/_common.py -> build/bdist.linux-x86_64/wheel/quamash
  copying build/lib/quamash/__init__.py -> build/bdist.linux-x86_64/wheel/quamash
  copying build/lib/quamash/_unix.py -> build/bdist.linux-x86_64/wheel/quamash
  running install_egg_info
  running egg_info
  writing Quamash.egg-info/PKG-INFO
  writing requirements to Quamash.egg-info/requires.txt
  writing dependency_links to Quamash.egg-info/dependency_links.txt
  writing top-level names to Quamash.egg-info/top_level.txt
  warning: manifest_maker: standard file '-c' not found

  reading manifest file 'Quamash.egg-info/SOURCES.txt'
  writing manifest file 'Quamash.egg-info/SOURCES.txt'
  Copying Quamash.egg-info to build/bdist.linux-x86_64/wheel/Quamash-0.5.1-py3.4.egg-info
  running install_scripts
  error: [Errno 2] No such file or directory: 'LICENSE'

  ----------------------------------------
  Failed building wheel for quamash
Failed to build quamash
Installing collected packages: quamash
  Running setup.py install for quamash
Successfully installed quamash-0.5.1

My guess is that the cause of the error is that the LICENSE file is not included in the sdist.

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

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'

aiohttp do not work with QEventLoop

Hello!
I am writing Qt web socket chat. I have next code of function:

async def master():
    with aiohttp.ClientSession() as session:# make session
        async with session.post('http://127.0.0.1:8080', data={'nickname': 'Admin'}) as response:
            assert response.status == 200
            print(await response.text())

        async with session.ws_connect('http://127.0.0.1:8080/127.0.0.1/ws/') as ws:
            async for msg in ws:
                if msg.tp == aiohttp.MsgType.text:
                    print(msg.data)

This function works with loop = asyncio.get_event_loop()
but does not works QEventLoop

I am using version aiohttp==0.20.2, asyncio==3.4.3, Quamash==0.5.4, Python3.5

Quamash loop and asyncio.open_connection error!

Hello Guys!

I'm David and i'm working now with your module and pyqt. Also y have a loop to obtain data from a database 'Rethinkdb' that uses asyncio also, so in the quamash loop i have to put this loop on the Rethinkdb class and open the connection.
The problem itself is in the asyncio module, when throw a lot of functions pass the quamash loop to the 'create_connection'.
This is the error:

  File "/home/dpineda/.virtualenvs/dragoncharts/lib/python3.6/site-packages/rethinkdb/asyncio_net/net_asyncio.py", line 148, in connect
    loop=self._io_loop)
  File "/usr/local/lib/python3.6/asyncio/streams.py", line 76, in open_connection
    lambda: protocol, host, port, **kwds)
  File "/usr/local/lib/python3.6/asyncio/base_events.py", line 731, in create_connection
    yield from tasks.wait(fs, loop=self)
  File "/usr/local/lib/python3.6/asyncio/tasks.py", line 311, in wait
    fs = {ensure_future(f, loop=loop) for f in set(fs)}
  File "/usr/local/lib/python3.6/asyncio/tasks.py", line 311, in <setcomp>
    fs = {ensure_future(f, loop=loop) for f in set(fs)}
  File "/usr/local/lib/python3.6/asyncio/tasks.py", line 514, in ensure_future
    raise ValueError('loop argument must agree with Future')
ValueError: loop argument must agree with Future

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/asyncio/events.py", line 127, in _run
    self._callback(*self._args)
  File "/home/dpineda/Proyectos/TaskTools/tasktools/taskloop.py", line 40, in renew_quamash
    raise task.result()
  File "/home/dpineda/Proyectos/TaskTools/tasktools/taskloop.py", line 11, in coromask
    obtained=await coro(*args)
  File "/home/dpineda/Proyectos/DragonCharts/dragoncharts/qtgui/interface.py", line 382, in updates
    await self.read_stations_queue()
  File "/home/dpineda/Proyectos/DragonCharts/dragoncharts/qtgui/interface.py", line 257, in read_stations_queue
    conn=await self.connect_rethinkdb()
  File "/home/dpineda/Proyectos/DragonCharts/dragoncharts/qtgui/interface.py", line 315, in connect_rethinkdb
    conn=await r.async_connect()
  File "/home/dpineda/Proyectos/NetworkTools/networktools/dbs/rethinkdb.py", line 43, in async_connect
    **kwargs)
  File "/home/dpineda/.virtualenvs/dragoncharts/lib/python3.6/site-packages/rethinkdb/asyncio_net/net_asyncio.py", line 293, in reconnect
    return (yield from self._instance.connect(timeout))
  File "/home/dpineda/.virtualenvs/dragoncharts/lib/python3.6/site-packages/rethinkdb/asyncio_net/net_asyncio.py", line 156, in connect
    (self._parent.host, self._parent.port, str(err)))
rethinkdb.errors.ReqlDriverError: Could not connect to atlas.csn.uchile.cl:28015. Error: loop argument must agree with Future

So, it's look like the quamash loop has some incompatibilities with some Future on the 'ensure_future' methods.

I hope that could has some solution and be useful to develop your module.

If you need some more, i'm here to help

Best regards!

RuntimeError: Failed to disconnect signal activated(int)

Im getting this randomly.... having trouble tying it down to a cause, but I figured I'd post here to see if anyone knew of any possible causes

Traceback (most recent call last):
  File "/usr/lib/python3.4/asyncio/events.py", line 120, in _run
    self._callback(*self._args)
  File "/usr/local/lib/python3.4/dist-packages/quamash/__init__.py", line 449, in __notifier_cb_wrapper
    notifier.activated.disconnect()
RuntimeError: Failed to disconnect signal activated(int).

aiohttp Too long request causes InvalidStateError

Mysterious crash when aiohttp.request takes too much time to execute ( ~2-3 sec ).
In my case it happens almost everytime when i make request to twitch.tv.
Doesn't seem to be aiohttp-only issue as it only happens with quamash loop.

import asyncio
import aiohttp
import sys
import quamash
import PyQt5
import PyQt5.QtWidgets

class Window( PyQt5.QtWidgets.QWidget ):

	def __init__( self ):

		super( ).__init__()

		self.resize( 200, 200 )
		self.setWindowTitle( "Test" )

		Layout = PyQt5.QtWidgets.QVBoxLayout()

		Button = PyQt5.QtWidgets.QPushButton( "Get twitch.tv ( crash )" )
		Button.clicked.connect( lambda: asyncio.Task( self.aRequest( "http://twitch.tv/" ), loop=Loop ) ) 
		Layout.addWidget( Button )

		Button = PyQt5.QtWidgets.QPushButton( "Get google.com" )
		Button.clicked.connect( lambda: asyncio.Task( self.aRequest( "http://google.com/" ), loop=Loop ) ) 
		Layout.addWidget( Button )

		self.setLayout( Layout )

		self.show()

	async def aRequest( self, URL ):
		Response = await aiohttp.request( "GET", URL, loop=Loop )

if __name__ == "__main__":
	
	Application = PyQt5.QtWidgets.QApplication( sys.argv )
	Loop = quamash.QEventLoop( Application )
	asyncio.set_event_loop( Loop )

	_ = Window()

	with Loop:
		Loop.run_forever()
>test.py
Traceback (most recent call last):
  File "C:\Py36\lib\site-packages\quamash\_windows.py", line 46, in _process_events
    f.set_result(value)
  File "C:\Py36\lib\asyncio\windows_events.py", line 83, in set_result
    super().set_result(result)
asyncio.base_futures.InvalidStateError: invalid state

Windows==10.0.15063
Python==3.6
PyQt5==5.9
aiohttp>=2.0.3
quamash==0.5.5

@asvetlov

Quamash crashes when no network is available

Here is a nice bug to fix...

When running our app in a network namespace without internet connexion ( https://unix.stackexchange.com/questions/68956/block-network-access-of-a-process ), quamash sometimes crashes with the following error :

DEBUG:main:Exception handler executing
ERROR:main:Future exception was never retrieved
future: <Future finished exception=gaierror(-2, 'Name or service unknown')>
Traceback (most recent call last):
  File "/usr/lib/python3.4/site-packages/quamash/__init__.py", line 89, in run
    r = callback(*args, **kwargs)
  File "/usr/lib/python3.4/socket.py", line 533, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -2] Name or service unknown

Context Manager / set_event_loop & event loop policies

Relevant Section of the PEP

This i rambly, sorry.

in bug #22 a user seemed to show confusion about the necessity of and proper place to set the event loop. The context manager sort of obscures all this. Additionally, it's not clear whether unsetting the event loop is particularly necessary. I'm struggling to understand how/why

To give some context, some parts of quamash pre-date quamash, namely \@easycallback which was a helper I made to make working with QThreads easier, (but not easy enough, I still had to write "twisted" callback based code). I was mostly using QThreads for asyncio (like making http requests) anyway, so this worked ok. Executors use a context manager to call shutdown and it seemed event loops should to. At least custom ones, but after reading the PEP as it has evolved this is beginning to seem like a presumption about how event loops are used: set, use, reset to defaults. This doesn't seem to be how they're used at all, usually you use one event loop as sort of the master, and then you can go off and do work in the same thread, in a separate process, in a different thread, but have it all call back to the master event loop.

So several questions:

  1. Should the context manager be deprecated, it doesn't violate the PEP, but it's a feature unique (as far as I know) to Quamash.
  2. If we keep the context manager, since it is somewhat useful, should it be the preferred way to set the event loop?
  3. How often will people be using multiple event loops? (using one, then switching back and forth between which one is active). This seems to be an unusual use case. Not one that should be forbidden, but we don't need to work extra hard to make it easy.
  4. Should an event loop policy be implemented. Then the appropriate usage would be to set the event loop policy, instead of setting the event loop directly. This makes using different event loop implementations harder, (but is also not required usage, you could still set/get the event loop manually or use QEventLoop with the standard policy)
  5. A custom event loop policy has the possibility of making QThreadExecutors more useful as you could run coroutines in them, with a per-thread event loop with less. Even more useful, the .execute could check if a coroutine or a regular function is being passed in, and a coroutine could be wrapped in asyncio.async()' (The policy would then need to manage thread affinity)
    see: http://qt-project.org/doc/qt-4.8/threads-qobject.html (tricky but potentially useful)
  6. A custom event loop policy will likely lead to even more platform specific stuff, and is one more moving part that can go wrong. (well the baseclass will need to be different on windows & unix)

Example code:

@asyncio.coroutine
def async_job():
     yield from asyncio.sleep(.1)

def threaded_job():
    local_loop = asyncio.get_event_loop()  # with standard policy, this will raise an Exception
    asyncio.async(async_job())

    local_loop.run_until_complete(async_job())

asyncio.set_event_loop_policy(quamash.QEventLoopPolicy(app))
loop = asyncio.get_event_loop()
with QThreadExecutor(5) as exec:
   yield from loop.run_in_executor(exec, threaded_job)

Exceptions in callbacks cause tests to terminate and potentially succeed

Fellow quamashians,

I came across this while debugging another issue I am having, and this makes writing tests quite hard if you donโ€™t know about this.

Exceptions in callbacks are swallowed by the pytest setup. In a setup like the following:

def test_scheduling(loop, sock_pair):
    s1, s2 = sock_pair
    fd = s1.fileno()
    cb_called = asyncio.Future()
    def writer_cb(fut):
        fut.set_result(None)
    def fut_cb(fut):
        loop.remove_writer(fd)
        cb_called.set_result(None)

    fut = asyncio.Future()
    fut.add_done_callback(fut_cb)
    loop.add_writer(fd, writer_cb, fut)
    loop.run_until_complete(cb_called)

What happens here is the following (part of this is part of another bug):

  1. writer_cb gets called, sets the future to None
  2. writer_cb gets called again (before fut_cb, which is part of another bug), but trying to set the future to None will result in an exception
  3. event loop gets stopped by the exception (due to the code in test_qeventloop.py, loop(request, application))
  4. run_until_complete returns successfully as the future is already done

My proposal is that either exceptions in callbacks in tests should be treated critically and cause the test to fail, or they should be treated like in live quamash. I donโ€™t know which of the two options I prefer though.

cheers,
horazont

QEventLoopPolicy to manage multiple event loops (one per thread)

see: #23

A custom event loop policy has the possibility of making QThreadExecutors more useful as you could run coroutines in them, with a per-thread event loop with less. Even more useful, the .execute could check if a coroutine or a regular function is being passed in, and a coroutine could be wrapped in asyncio.async()' (The policy would then need to manage thread affinity)
see: http://qt-project.org/doc/qt-4.8/threads-qobject.html (tricky but potentially useful)

A custom event loop policy will likely lead to even more platform specific stuff, and is one more moving part that can go wrong. (well the baseclass will need to be different on windows & unix)

Example code:

@asyncio.coroutine
def async_job():
     yield from asyncio.sleep(.1)

def threaded_job():
    local_loop = asyncio.get_event_loop()  # with standard policy, this will raise an Exception
    asyncio.async(async_job())

    local_loop.run_until_complete(async_job())

asyncio.set_event_loop_policy(quamash.QEventLoopPolicy(app))
loop = asyncio.get_event_loop()
with QThreadExecutor(5) as exec:
   yield from loop.run_in_executor(exec, threaded_job)

asyncio.async working?

Hi!

Please have a look at the minimum example below.
I'ts working. The coroutine will print out 0, 1, 3,...
But when I change the True to False, nothing will happen.
Shouldn't asyncio.async(...) work as well as loop.run_unti_complete(...)?

I'm using Python 3.4.1 with PyQt5 under Windows 7.

Regards,

Dietmar

import sys
import asyncio


from PyQt5.QtWidgets import QApplication
from quamash import QEventLoop

app = QApplication(sys.argv)
loop = QEventLoop(app)

@asyncio.coroutine
def coroutine():
    n = 0
    while True:
        print(n)
        yield from asyncio.sleep(1.0)
        n += 1

if True:
    with loop:
        loop.run_until_complete(coroutine())
else:
    asyncio.async( coroutine() )
    with loop:
        loop.run_forever()

python 3.5 support

Thanks for awesome project ๐Ÿ‘
When will quamash start working with python 3.5 on windows? Is it stopped by missed binary packages PyQt 5.5.1 (will support 3.5), which stopped by Qt 5.5.1?
My app works fine on ubuntu with python 3.4.3 and PyQt 5.5, and have some known troubles with https on windows (cause event loop, as far as I remember). Right now I have windows python 3.5 + PyQt 5.5.1-snapshot builded from source and get such traceback (it is not about https part):

Traceback (most recent call last):
  File "C:\Python35\lib\asyncio\coroutines.py", line 270, in _format_coroutine
    coro_code = coro.gi_code
AttributeError: '_DetachedRequestContextManager' object has no attribute 'gi_code'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\pro\py\bazar-watcher\bazar_parser.py", line 98, in bazar_theme_retriever
    yield from job(task)
  File "C:\pro\py\bazar-watcher\bazar_parser.py", line 32, in job
    10,
  File "C:\Python35\lib\asyncio\tasks.py", line 365, in wait_for
    fut = ensure_future(fut, loop=loop)
  File "C:\Python35\lib\asyncio\tasks.py", line 526, in ensure_future
    task = loop.create_task(coro_or_future)
  File "C:\Python35\lib\asyncio\base_events.py", line 216, in create_task
    task = tasks.Task(coro, loop=self)
  File "C:\Python35\lib\asyncio\tasks.py", line 77, in __init__
    self._loop.call_soon(self._step)
  File "C:\Python35\lib\site-packages\quamash\__init__.py", line 370, in call_soon
    return self.call_later(0, callback, *args)
  File "C:\Python35\lib\site-packages\quamash\__init__.py", line 345, in call_later
    .format(callback, args, delay))
  File "C:\Python35\lib\asyncio\futures.py", line 194, in __repr__
    info = self._repr_info()
  File "C:\Python35\lib\asyncio\tasks.py", line 102, in _repr_info
    coro = coroutines._format_coroutine(self._coro)
  File "C:\Python35\lib\asyncio\coroutines.py", line 272, in _format_coroutine
    coro_code = coro.cr_code
AttributeError: '_DetachedRequestContextManager' object has no attribute 'cr_code'

How to get traceback of uncaught exceptions ?

Hi

I'd like to display tracebacks of uncaught exceptions.
At the moment I can't find a way to do it. Setting an exception_handler in the loop never calls it, enabling the debug by every possible way neither does.

Is there any limitations about this I dont know ?

pip install crash

pip install quamash says:

SyntaxError: Non-ASCII character '\xc2' in file quamash/__init__.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

on

Distributor ID: Ubuntu
Description:    Ubuntu 15.04
Release:    15.04
Codename:   vivid

Qt Implementation Dependency Injection?

The current system where quamash loads the first Qt Implementation it finds or one in an environment variable is hacky.

Additionally since version, author and license are loaded from init.py, a Qt Implementation (doesn't matter which one) needs to be available when setup.py is used. It would be nice if a source install could be done without PyQt/PySide being present. Even if that's unusual.

A lazy-load dependency injection type system that decides which Qt implementation to use at instantiation time could be really slick, or it could just be even more hackish.

@aknuds1 @horazont thoughts?

Exception when leaving the app in debug mode

Hello,

When exiting our app in debug mode quamash crashes with the following exception :

ERROR:__init__:Exception in default exception handler
Traceback (most recent call last):
  File "/usr/lib/python3.4/site-packages/quamash/__init__.py", line 543, in call_exception_handler
    self.default_exception_handler(context)
  File "/usr/lib/python3.4/site-packages/quamash/__init__.py", line 522, in default_exception_handler
    self._logger.debug('Default exception handler executing')
  File "/usr/lib/python3.4/logging/__init__.py", line 1262, in debug
    self._log(DEBUG, msg, args, **kwargs)
  File "/usr/lib/python3.4/logging/__init__.py", line 1409, in _log
    self.handle(record)
  File "/usr/lib/python3.4/logging/__init__.py", line 1419, in handle
    self.callHandlers(record)
  File "/usr/lib/python3.4/logging/__init__.py", line 1481, in callHandlers
    hdlr.handle(record)
  File "/usr/lib/python3.4/logging/__init__.py", line 853, in handle
    self.emit(record)
  File "/usr/lib/python3.4/logging/__init__.py", line 1040, in emit
    self.stream = self._open()
  File "/usr/lib/python3.4/logging/__init__.py", line 1030, in _open
    return open(self.baseFilename, self.mode, encoding=self.encoding)
NameError: name 'open' is not defined
('Exception in default exception handler',), {'exc_info': True}

Modal dialogs stops the asyncio event loop

Here is a simple test file :

import sys
import unittest
import os
import asyncio
import quamash
import logging
from PyQt5.QtWidgets import QDialog, QMessageBox
from PyQt5.QtCore import Qt
from PyQt5.QtTest import QTest


class Dialog(QDialog):
    def __init__(self):
        super().__init__()

    @asyncio.coroutine
    def message_box(self):
        result = QMessageBox.question(self, "Test", "Do I bug ?")
        return result


class TestBug(unittest.TestCase):
    def setUp(self):
        self.qapplication = quamash.QApplication(sys.argv)
        self.lp = quamash.QEventLoop(self.qapplication)
        asyncio.set_event_loop(self.lp)

    def tearDown(self):
        try:
            self.lp.close()
        finally:
            asyncio.set_event_loop(None)

    def test_bug(self):
        dialog = Dialog()
        @asyncio.coroutine
        def exec_test():
            asyncio.async(dialog.message_box())
            yield from asyncio.sleep(3)
            for widget in quamash.QApplication.topLevelWidgets():
                if isinstance(widget, QMessageBox):
                    QTest.mouseClick(widget.button(QMessageBox.Yes), Qt.LeftButton)
            yield from asyncio.sleep(1)

        self.lp.run_until_complete(asyncio.wait_for(exec_test(), timeout=10))

if __name__ == '__main__':
    logging.basicConfig( stream=sys.stderr )
    logging.getLogger().setLevel( logging.DEBUG )
    unittest.main()

This outputs :

/usr/bin/python3.4 /home/inso/bin/pycharm-4.5.4/helpers/pycharm/utrunner.py /home/inso/code/ucoin/cutecoin/src/cutecoin/tests/process_cfg_community/test_bug.py true
Testing started at 16:44 ...
Exception in callback Task._step()
handle: <Handle Task._step()>
Traceback (most recent call last):
  File "/usr/lib/python3.4/asyncio/events.py", line 120, in _run
    self._callback(*self._args)
  File "/usr/lib/python3.4/asyncio/tasks.py", line 282, in _step
    self.__class__._current_tasks.pop(self._loop)
KeyError: <QEventLoop running=True closed=False debug=False>

Error
Traceback (most recent call last):
  File "/home/inso/code/ucoin/cutecoin/src/cutecoin/tests/process_cfg_community/test_bug.py", line 47, in test_bug
    self.lp.run_until_complete(asyncio.wait_for(exec_test(), timeout=10))
  File "/usr/lib/python3.4/site-packages/quamash/__init__.py", line 291, in run_until_complete
    raise RuntimeError('Event loop stopped before Future completed.')
RuntimeError: Event loop stopped before Future completed.

Task was destroyed but it is pending!
task: <Task pending coro=<wait_for() done, defined at /usr/lib/python3.4/asyncio/tasks.py:340> wait_for=<Future pending cb=[Task._wakeup()]>>
Task was destroyed but it is pending!
task: <Task pending coro=<exec_test() running at /home/inso/code/ucoin/cutecoin/src/cutecoin/tests/process_cfg_community/test_bug.py:45> wait_for=<Future pending cb=[Task._wakeup()]> cb=[_release_waiter(<Future pendi...sk._wakeup()]>)() at /usr/lib/python3.4/asyncio/tasks.py:335]>

Process finished with exit code 0

I think it's due to this behaviour of QMessageBoxes :

As a special case, modal widgets like QMessageBox can be used before calling exec(), because modal widgets use their own local event loop.

http://doc.qt.io/qt-5.5/qeventloop.html

Loop stops after dialog goes away

Please disregard if I'm doing something bone-headed. It may be due to my lack, of either asyncio or Qt knowledge.

I'm trying to show two dialogs, one after the other.
In this small example I use QWizard's
After the first one goes away either by pressing cancel or finish, I get the error shown below.
However, if I have a button sitting there in the background it behaves just fine.
If instead of running run_until_complete(amain()) I run asyncio.ensure_future(amain()) followed by loop.run_forever() then I don't get any errors but the 2nd wizard never shows up. It just exists as soon as there is nothing left to display on the screen.

#!/usr/bin/env python3
import asyncio
import sys

from PyQt5.QtWidgets import QApplication, QWizard, QWizardPage, QDialog, QPushButton
from quamash import QEventLoop


def async_dialog_exec(dlg: QDialog):
    fut = asyncio.Future()
    dlg.finished.connect(lambda result: fut.set_result(result))
    dlg.open()
    return fut

async def amain():
    # if these two lines are uncommented you'll be able to see both wizards
    # b = QPushButton('hi')
    # b.show()
    wiz1 = QWizard()
    wiz1.addPage(QWizardPage())
    wiz1.setWindowTitle("First Wizard")
    result = await async_dialog_exec(wiz1)
    if result != QDialog.Accepted:
        return

    wiz2 = QWizard()
    wiz2.addPage(QWizardPage())
    wiz2.setWindowTitle("Second Wizard")
    result = await async_dialog_exec(wiz2)
    if result != QDialog.Accepted:
        return

app = QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
with loop:
    loop.run_until_complete(amain())
Traceback (most recent call last):
  File "/home/vagrant/PycharmProjects/test/dlg_example.py", line 37, in <module>
    loop.run_until_complete(amain())
  File "/opt/Python-3/lib/python3.5/site-packages/quamash/__init__.py", line 270, in run_until_complete
    raise RuntimeError('Event loop stopped before Future completed.')
RuntimeError: Event loop stopped before Future completed.

AppVeyor test suite fails

As discovered in #74 and #75 there are failures occurring in the AppVeyor test suite. They seem to occur randomly in various parts of the test suite. It's not something we can fix with boxing or skipping.

My guess is that either the test setup & teardown are not thorough enough, or there is an actual bug (race condition?) in quamash.

Memory usage grow on task switching

import asyncio

from PyQt5 import QtWidgets
from quamash import QEventLoop


@asyncio.coroutine
def Switcher():

    while True:

        yield from asyncio.sleep(0.001)


if __name__ == "__main__":

    import sys

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

    with loop:

        loop.run_until_complete(Switcher())

Usage grow proportinally to switching speed. I made some big app with awesome ๐Ÿ‘ quamash, and saw slow growing for hours of work.

Tested with:

  • Ubuntu 14.04 / Python 3.4.3 / PyQt 5.5
  • Windows 7 / Python 3.5.0 / PyQt 5.5.1
  • Windows xp / Python 3.4.4 / PyQt 5.5

WinError 995 confuses Quamash

WinError 995

It's an alias for ERROR_OPERATION_ABORTED:

The I/O operation has been aborted because of either a thread exit or an application request.

The issue

Cancelling the I/O-based coroutine (e.g. asyncio.open_connection) might lead to an OSError (with that WinError 995 as a reason) somewhere inside of asyncio machinery.

Minimal code to reproduce:

import asyncio
import sys

from PyQt5.QtWidgets import QApplication

from quamash import QEventLoop


async def main(*, loop):
    f = asyncio.ensure_future(
        asyncio.open_connection('example.org', 8888, loop=loop),
        loop=loop
    )

    await asyncio.sleep(0.1, loop=loop)
    f.cancel()


app = QApplication(sys.argv)

with QEventLoop(app) as loop:
    asyncio.set_event_loop(loop)
    loop.run_until_complete(main(loop=loop))

Output:

(venv) D:\Python\requested-cctv>python quamash-test.py
Event callback failed: [WinError 995] ะžะฟะตั€ะฐั†ะธั ะฒะฒะพะดะฐ/ะฒั‹ะฒะพะดะฐ ะฑั‹ะปะฐ ะฟั€ะตั€ะฒะฐะฝะฐ ะธะท-ะทะฐ ะทะฐะฒะตั€ัˆะตะฝะธั ะฟะพั‚ะพะบะฐ ะบะพะผะฐะฝะด ะธะปะธ ะฟะพ ะทะฐะฟั€ะพััƒ ะฟั€ะธะปะพะถะตะฝะธั
Traceback (most recent call last):
  File "D:\Python\requested-cctv\venv\lib\site-packages\quamash\_windows.py", line 41, in _process_events
    value = callback(transferred, key, ov)
  File "c:\python36\Lib\asyncio\windows_events.py", line 514, in finish_connect
    ov.getresult()
OSError: [WinError 995] โ•ฌัั…ะั€ะŽัˆย  ั‚ั‚ัŽั„ั€/ั‚โˆšั‚ัŽั„ั€ ัโˆšั‹ั€ ัะั…ะั‚ั€ัั€ ัˆั‡-ั‡ั€ ั‡ั€ั‚ั…ะยฐั…ััˆย  ััŽะ„ัŽัŠั€ ัŠัŽัŒั€ัั„ ัˆั‹ัˆ ััŽ ั‡ั€ัะัŽั‘ั” ัะัˆั‹ัŽั†ั…ััˆย 

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\Python\requested-cctv\venv\lib\site-packages\quamash\_windows.py", line 44, in _process_events
    f.set_exception(e)
  File "c:\python36\Lib\asyncio\windows_events.py", line 79, in set_exception
    super().set_exception(exception)
asyncio.base_futures.InvalidStateError: invalid state

(venv) D:\Python\requested-cctv>

The application crashes.

Now that's an exception in Quamash when it tries to set that OSError as an exception on the local f variable in _windows._ProactorEventLoop._process_events.
Printing that f variable gives

<_OverlappedFuture cancelled>

If done without Qt and Quamash, this OSError doesn't appear anywhere.

Note: The bug is inconsistent. Sometimes (rarely) it doesn't occur.

System info

Windows 10 x64, Python 3.6.0

_IocpProactor implementation causes race condition (on Windows)

Quamash uses separate thread for event polling. Polling in separate thread can cause race condition with 'event initiation' which is handled in MainThread. E.g. method recv of asyncio.windows_events.IocpProactor starts waiting to receive data from socket (via call to WSARecv) in MainThread. Before recv calls self._register(ov, conn, finish_recv) to register event in self._cache event is received in parallel poller thread (via call to GetQueuedCompletionStatus) and causes KeyError, in this case event is lost forever and app hangs on exit. I believe this bug is the reason for hangs in PR #44 (issue #38).

What is the intended way of blocking synchronous slots until some async. code is done?

Sometimes it is required to wait for result of asynchronous operation in synchronous Qt slot, is there any proper way to do it?

For example I have QMainWindow subclass that has QWebEngineView as one of it's child, QWebEngineView runs some JavaScript client code, and my application communicates with it asynchronously using WebSockets.
Now I want to request from QWebEngineView some data to store on application exit: in overridden QMainWindow::closeEvent().

I can't create async. task and let closeEvent() to finish, since the main window will destroy QWebEngineView on close, and most probably I won't get results in time.
I can't use BaseEventLoop.run_until_complete() with my async. call, since event loop is already running and is not reentrant.
I can't create second thread, start second event loop there, call async. method in the second event loop, and in closeEvent() wait when the thread will finish, since my web socket is already managed by event loop in the main thread.

My current solution is to postpone the main window closing by ignoring first close event, start async. task, and call QMainWindow::close() second time manually from async. task when work is done.
This solution works in closeEvent(), since it's possible to postpone closing, but will not in most of other synchronous slots.

Weird behaviour with exceptions

Consider the following code :

import asyncio
from PyQt5.QtCore import QTimer
import logging
import quamash
from quamash import QApplication


class Bug():
    def __init__(self):
        pass

    @asyncio.coroutine
    def errorlvl3(self):
        raise TypeError()

    @asyncio.coroutine
    def errorlvl2(self):
        yield from self.errorlvl3()

    @asyncio.coroutine
    def errorlvl1(self):
        yield from self.errorlvl2()

    def go(self):
        asyncio.async(self.wait_and_close())
        asyncio.async(self.errorlvl1())

    @asyncio.coroutine
    def wait_and_close(self):
        for i in range(0, 3):
            yield from asyncio.sleep(1)
        self.lp.stop()

    def test_bug(self):
        self.qapplication = QApplication([])
        self.lp = quamash.QEventLoop(self.qapplication)
        self.lp.set_debug(True)
        asyncio.set_event_loop(self.lp)

        with self.lp:
            QTimer.singleShot(0, self.go)
            self.lp.run_forever()
        asyncio.set_event_loop(None)


if __name__ == '__main__':
    logging.basicConfig(format='%(levelname)s:%(module)s:%(funcName)s:%(message)s',
        level=logging.DEBUG)
    Bug().test_bug()

When I run this, I get the following output :

/home/inso/.pyenv/versions/cutecoin/bin/python3 /home/inso/code/quamash/bug.py -d
DEBUG:selector_events:__init__:Using selector: _Selector
DEBUG:__init__:add_reader:Adding reader callback for file descriptor 10
DEBUG:__init__:run_forever:Starting Qt event loop
DEBUG:__init__:call_later:Registering callback <bound method Task._step of <Task pending coro=<wait_and_close() running at /home/inso/code/quamash/bug.py:30> created at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/base_events.py:212>> to be invoked with arguments () after 0 second(s)
DEBUG:__init__:_add_callback:Adding callback <Handle Task._step() created at /home/inso/code/quamash/quamash/__init__.py:346> with delay 0
DEBUG:__init__:call_later:Registering callback <bound method Task._step of <Task pending coro=<errorlvl1() running at /home/inso/code/quamash/bug.py:22> created at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/base_events.py:212>> to be invoked with arguments () after 0 second(s)
DEBUG:__init__:_add_callback:Adding callback <Handle Task._step() created at /home/inso/code/quamash/quamash/__init__.py:346> with delay 0
DEBUG:__init__:upon_timeout:Callback timer fired, calling <Handle Task._step() created at /home/inso/code/quamash/quamash/__init__.py:346>
DEBUG:__init__:call_later:Registering callback <bound method Future._set_result_unless_cancelled of <Future pending created at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/tasks.py:490>> to be invoked with arguments (None,) after 1 second(s)
DEBUG:__init__:_add_callback:Adding callback <Handle Future._set_result_unless_cancelled(None) created at /home/inso/code/quamash/quamash/__init__.py:346> with delay 1
DEBUG:__init__:upon_timeout:Callback timer fired, calling <Handle Task._step() created at /home/inso/code/quamash/quamash/__init__.py:346>
DEBUG:__init__:upon_timeout:Callback timer fired, calling <Handle Future._set_result_unless_cancelled(None) created at /home/inso/code/quamash/quamash/__init__.py:346>
DEBUG:__init__:call_later:Registering callback <bound method Task._wakeup of <Task pending coro=<wait_and_close() running at /home/inso/code/quamash/bug.py:33> wait_for=<Future finished result=None created at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/tasks.py:490> created at /home/inso/code/quamash/bug.py:27>> to be invoked with arguments (<Future finished result=None created at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/tasks.py:490>,) after 0 second(s)
DEBUG:__init__:_add_callback:Adding callback <Handle Task._wakeup(<Future finis.../tasks.py:490>) created at /home/inso/code/quamash/quamash/__init__.py:346> with delay 0
DEBUG:__init__:upon_timeout:Callback timer fired, calling <Handle Task._wakeup(<Future finis.../tasks.py:490>) created at /home/inso/code/quamash/quamash/__init__.py:346>
DEBUG:__init__:call_later:Registering callback <bound method Future._set_result_unless_cancelled of <Future pending created at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/tasks.py:490>> to be invoked with arguments (None,) after 1 second(s)
DEBUG:__init__:_add_callback:Adding callback <Handle Future._set_result_unless_cancelled(None) created at /home/inso/code/quamash/quamash/__init__.py:346> with delay 1
DEBUG:__init__:upon_timeout:Callback timer fired, calling <Handle Future._set_result_unless_cancelled(None) created at /home/inso/code/quamash/quamash/__init__.py:346>
DEBUG:__init__:call_later:Registering callback <bound method Task._wakeup of <Task pending coro=<wait_and_close() running at /home/inso/code/quamash/bug.py:33> wait_for=<Future finished result=None created at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/tasks.py:490> created at /home/inso/code/quamash/bug.py:27>> to be invoked with arguments (<Future finished result=None created at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/tasks.py:490>,) after 0 second(s)
DEBUG:__init__:_add_callback:Adding callback <Handle Task._wakeup(<Future finis.../tasks.py:490>) created at /home/inso/code/quamash/quamash/__init__.py:346> with delay 0
DEBUG:__init__:upon_timeout:Callback timer fired, calling <Handle Task._wakeup(<Future finis.../tasks.py:490>) created at /home/inso/code/quamash/quamash/__init__.py:346>
DEBUG:__init__:call_later:Registering callback <bound method Future._set_result_unless_cancelled of <Future pending created at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/tasks.py:490>> to be invoked with arguments (None,) after 1 second(s)
DEBUG:__init__:_add_callback:Adding callback <Handle Future._set_result_unless_cancelled(None) created at /home/inso/code/quamash/quamash/__init__.py:346> with delay 1
DEBUG:__init__:upon_timeout:Callback timer fired, calling <Handle Future._set_result_unless_cancelled(None) created at /home/inso/code/quamash/quamash/__init__.py:346>
DEBUG:__init__:call_later:Registering callback <bound method Task._wakeup of <Task pending coro=<wait_and_close() running at /home/inso/code/quamash/bug.py:33> wait_for=<Future finished result=None created at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/tasks.py:490> created at /home/inso/code/quamash/bug.py:27>> to be invoked with arguments (<Future finished result=None created at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/tasks.py:490>,) after 0 second(s)
DEBUG:__init__:_add_callback:Adding callback <Handle Task._wakeup(<Future finis.../tasks.py:490>) created at /home/inso/code/quamash/quamash/__init__.py:346> with delay 0
DEBUG:__init__:upon_timeout:Callback timer fired, calling <Handle Task._wakeup(<Future finis.../tasks.py:490>) created at /home/inso/code/quamash/quamash/__init__.py:346>
DEBUG:__init__:stop:Stopping event loop...
DEBUG:__init__:stop:Stopped event loop
DEBUG:__init__:run_forever:Qt event loop ended with result 0
DEBUG:__init__:stop:Already stopped
DEBUG:__init__:close:Closing event loop...
DEBUG:__init__:remove_reader:Removing reader callback for file descriptor 10
DEBUG:base_events:close:Close <QEventLoop running=False closed=False debug=True>
DEBUG:_unix:close:Closing
DEBUG:__init__:default_exception_handler:Default exception handler executing
ERROR:__init__:__log_error:Task exception was never retrieved
future: <Task finished coro=<errorlvl1() done, defined at /home/inso/code/quamash/bug.py:22> exception=TypeError() created at /home/inso/code/quamash/bug.py:28>
source_traceback: [('/home/inso/code/quamash/bug.py', 51, '<module>', 'Bug().test_bug()'), ('/home/inso/code/quamash/bug.py', 44, 'test_bug', 'self.lp.run_forever()'), ('/home/inso/code/quamash/quamash/__init__.py', 271, 'run_forever', 'rslt = self.__app.exec_()'), ('/home/inso/code/quamash/bug.py', 28, 'go', 'asyncio.async(self.errorlvl1())')]
Traceback (most recent call last):
  File "/home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/tasks.py", line 238, in _step
    result = next(coro)
  File "/home/inso/code/quamash/bug.py", line 24, in errorlvl1
    yield from self.errorlvl2()
  File "/home/inso/code/quamash/bug.py", line 20, in errorlvl2
    yield from self.errorlvl3()
  File "/home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/coroutines.py", line 141, in coro
    res = func(*args, **kw)
  File "/home/inso/code/quamash/bug.py", line 16, in errorlvl3
    raise TypeError()
TypeError

Process finished with exit code 0

What we can see here, is that the exception is only displayed when the loop closes. Shouldn't the exception be displayed during the "wait_and_close" method ?

Support awaiting on qt signals

I did some experimenting with quamash, and I think it's fairly easy to make an awaitable wrapper for Qt signals. While it's not part of a regular asyncio event loop, it would make working with pure PyQt code (like QNetworkReply or QDialog) a bit easier.

I made an experimental branch at https://github.com/Wesmania/quamash/tree/non-compliant-stuff that cuts quamash down to a small, non-compliant event loop with support for awaiting on signals. There's still some stuff to be worked out (cleaning up references to awaited-on signals at cancel, wrapping slots in call_soon to avoid growing the stack too much, custom future with "done" signal), but it can serve as a proof-of-concept.

How can I set the `loop` variable to global ?

Hello

I have a problem in using.

In my case:
I have two files. main.py and mainwindow.py

# main.py

if __name__ == "__main__":
   app = QApplication(sys.argv)
   loop = QEventLoop(app)
   asyncio.set_event_loop(loop)
   w = MainWindow()
   w.show()
   loop.run_forever()
# mainwindow.py
class MainWindow():
    ...
    # I want to access the variable "loop" here
    # I have tried "global" and "nonlocal" keywords, but it did no use

my question is that how can i use the variable in mainwindow.py ?
Can you help me ? thanks ~

easycallback doctest is broken ?

When I run pytest, I get :

2015-12-10 20:42:18,690 - DEBUG - quamash.QEventLoop - Adding reader callback for file descriptor 10
2015-12-10 20:42:18,690 - DEBUG - quamash.QEventLoop - Running <generator object coro at 0x7f76c782b5a0> until complete
2015-12-10 20:42:18,690 - DEBUG - quamash.QEventLoop - Registering callback <bound method Task._step of <Task pending coro=<coro() running at /home/inso/.pyenv/versions/3.4.3/lib/python3.4/asyncio/coroutines.py:139>>> to be invoked with arguments () after 0 second(s)
2015-12-10 20:42:18,691 - DEBUG - quamash.QEventLoop - Adding callback <Handle Task._step()> with delay 0
2015-12-10 20:42:18,691 - DEBUG - quamash.QEventLoop - Starting Qt event loop
2015-12-10 20:42:18,691 - DEBUG - quamash.QEventLoop - Callback timer fired, calling <Handle Task._step()>
Traceback (most recent call last):
  File "/home/inso/code/quamash/quamash/__init__.py", line 214, in <lambda>
    signaler.signal.connect(lambda self, args, kwargs: fn(self, *args, **kwargs))
  File "<doctest quamash._easycallback[5]>", line 6, in mycallback
AssertionError: assert <PyQt5.QtCore.QThread object at 0x7f76c7c74dc8> is not global_thread
[1]    14537 abort (core dumped)  py.test -s tests/test_qeventloop.py

Differences between quamash and asyncio event loop + processEvents

Hello,

I was wondering what would be the implication of using the asyncio event loops for a Qt application instead of quamash Event loop.

We can use asyncio with Qt with the following simple code. The app must be killed to be stopped but you get the point :

    async def process_events(qapp):
        while True:
            await asyncio.sleep(0)
            qapp.processEvents()

    qapp = QApplication(sys.argv)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(process_events(qapp))

So what does Quamash brings in terms of compatibility and stability with the Qt system compared to asyncio event loop ? Or is it only about a proof of concept ?

The first thing I can see is that asyncio + modal dialogs does not working easiliy. But I wonder if there are more things to know that I'm not aware of ?

Thanks

Non-ASCII Charactor

I'm current't using OSX and trying to install quamash using

pip install quamash

However I kept getting this

Collecting quamash
  Using cached Quamash-0.5.5.zip
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/private/var/folders/xc/w91zg1p97dd4v2gzrlrp7t440000gn/T/pip-build-VDDZTx/quamash/setup.py", line 2, in <module>
        import quamash
      File "/private/var/folders/xc/w91zg1p97dd4v2gzrlrp7t440000gn/T/pip-build-VDDZTx/quamash/quamash/__init__.py", line 1
    SyntaxError: Non-ASCII character '\xc2' in file /private/var/folders/xc/w91zg1p97dd4v2gzrlrp7t440000gn/T/pip-build-VDDZTx/quamash/quamash/__init__.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

python 3.6?

Any efforts going on to support python 3.6? Are you accepting PRs?

Windows Errors

The PyQt4 and PyQt5 tests on appveyor are passing, but I get this:

Exception ignored in: <bound method _ProactorSocketTransport.__del__ of <_ProactorSocketTransport closing fd=-1 read=<_OverlappedFuture cancelled>>>
Traceback (most recent call last):
  File "C:\Python34\lib\asyncio\proactor_events.py", line 86, in __del__
    self.close()
  File "C:\Python34\lib\asyncio\proactor_events.py", line 74, in close
    self._loop.call_soon(self._call_connection_lost, None)
  File "C:\projects\quamash\quamash\__init__.py", line 365, in call_soon
    return self.call_later(0, callback, *args)
  File "C:\projects\quamash\quamash\__init__.py", line 345, in call_later
    return self._add_callback(asyncio.Handle(callback, args, self), delay)
  File "C:\projects\quamash\quamash\__init__.py", line 359, in _add_callback
    self.__timers.append(timer)
AttributeError: 'NoneType' object has no attribute 'append'
Exception ignored in: <bound method _ProactorSocketTransport.__del__ of <_ProactorSocketTransport closing fd=-1 read=<_OverlappedFuture cancelled>>>
Traceback (most recent call last):
  File "C:\Python34\lib\asyncio\proactor_events.py", line 86, in __del__
    self.close()
  File "C:\Python34\lib\asyncio\proactor_events.py", line 74, in close
    self._loop.call_soon(self._call_connection_lost, None)
  File "C:\projects\quamash\quamash\__init__.py", line 365, in call_soon
    return self.call_later(0, callback, *args)
  File "C:\projects\quamash\quamash\__init__.py", line 345, in call_later
    return self._add_callback(asyncio.Handle(callback, args, self), delay)
  File "C:\projects\quamash\quamash\__init__.py", line 359, in _add_callback
    self.__timers.append(timer)
AttributeError: 'NoneType' object has no attribute 'append'
Exception ignored in: <bound method _ProactorSocketTransport.__del__ of <_ProactorSocketTransport closing fd=-1 read=<_OverlappedFuture cancelled>>>
Traceback (most recent call last):
  File "C:\Python34\lib\asyncio\proactor_events.py", line 86, in __del__
    self.close()
  File "C:\Python34\lib\asyncio\proactor_events.py", line 74, in close
    self._loop.call_soon(self._call_connection_lost, None)
  File "C:\projects\quamash\quamash\__init__.py", line 365, in call_soon
    return self.call_later(0, callback, *args)
  File "C:\projects\quamash\quamash\__init__.py", line 345, in call_later
    return self._add_callback(asyncio.Handle(callback, args, self), delay)
  File "C:\projects\quamash\quamash\__init__.py", line 359, in _add_callback
    self.__timers.append(timer)
AttributeError: 'NoneType' object has no attribute 'append'

may be related to #34

PySide tests give off a similar error, in addition to:

QObject::startTimer: QTimer can only be used with threads started with QThread
QObject::startTimer: QTimer can only be used with threads started with QThread
QObject::startTimer: QTimer can only be used with threads started with QThread

but fail, however, the PySide tests have been failing for awhile for no reason on windows (like the tests all pass, but the exit code of py.test is non-zero)

Debug output appears to indicate default executor even when default isn't used

The user's program can run the following line to enable debug output on stderr/stdout:

logging.basicConfig(level=logging.DEBUG)

The debug output states the following message, apparently unconditionally, when user code runs .run_in_executor():

DEBUG:quamash.QEventLoop:Using default executor

... and the source code seems to confirm this [init.py starting at line 480, run_in_executor() method].

Hopefully the logic can be updated to print the mentioned message only when the default executor is being used.

Quamash and pyzmq with asyncio

Hello,

I'm attempting to make a GUI client that asynchronously communicates to a server via zeromq. Pyzmq has support for asyncio (i.e. some of the blocking functions return futures). I wrote a naive server/client example based on some pyzmq examples, and I'm not sure if it doesn't work because I'm using something incorrectly, or if there's a fundamental reason that these two won't work together.

Server:

import asyncio
import zmq.asyncio
from zmq.utils.win32 import allow_interrupt

ctx = zmq.asyncio.Context()
loop = zmq.asyncio.ZMQEventLoop()
asyncio.set_event_loop(loop)

url = 'tcp://127.0.0.1:5555'

@asyncio.coroutine
def async_process(msg):
    print(msg)
    return msg

@asyncio.coroutine
def recv_and_process():
    sock = ctx.socket(zmq.REP)
    sock.bind(url)

    while True:
        print("waiting for client...")
        msg = yield from sock.recv_multipart()
        reply = yield from async_process(msg)
        print("processed! now sending...")
        yield from sock.send_multipart(reply)

loop.run_until_complete(recv_and_process())

Client:

import sys
import asyncio
import zmq
import zmq.asyncio

from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLineEdit
from quamash import QEventLoop

app = QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)

url = 'tcp://127.0.0.1:5555'

ctx = zmq.asyncio.Context()

class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.button = QPushButton('Send', self)
        self.button.clicked.connect(self.handleButton)
        self.path = QLineEdit()
        self.path.move(20, 20)
        self.path.resize(280,40)
        layout = QVBoxLayout(self)
        layout.addWidget(self.button)
        layout.addWidget(self.path)

    def handleButton(self):
        print('Sending text:', self.path.text())
        asyncio.ensure_future(get(self.path.text()), loop=loop)

window = Window()
window.show()

@asyncio.coroutine
def get(path):
    socket = ctx.socket(zmq.REQ)
    socket.connect(url)
    socket.send_multipart([path.encode('ascii')])
#    yield from asyncio.sleep(1)
    reply = yield from socket.recv_multipart()
    print(reply)
    socket.close()


with loop:
    loop.run_forever()

I'm using Python 3.4 here, since I'm not sure PyQt5 is supported in Python 3.5 yet.

The server basically just replies the same message it receives. The client has a textbox. Clicking the "Send" button sends the textbox's text to the server. When doing this, I receive the following error:

  File "/.../site-packages/quamash/__init__.py", line 377, in add_reader
    notifier = QtCore.QSocketNotifier(fd, QtCore.QSocketNotifier.Read)
TypeError: QSocketNotifier(sip.voidptr, QSocketNotifier.Type, parent: QObject = None): argument 1 has unexpected type 'Socket'

The code works fine upon uncommenting the asyncio.sleep line. I assume this assures enough time such that a future is no longer returned.

It's worth pointing out that pyzmq uses its own event loop (see: http://pyzmq.readthedocs.io/en/latest/api/zmq.asyncio.html) called ZMQEventLoop(), as used in the server. I was hoping that the client wouldn't need to use this event loop.

Is there any simple way to integrate zmq.asyncio with quamash, or is this a much larger endeavor?

Thanks!

P.S. Zeromq seems to be mentioned on line 462 of that __init__.py file. What's this in reference to?

Support / Development real-time communication platform

I propose that this project obtains a real-time communication platform.

If this proposal gets accepted, I suggest that we use IRC or XMPP. With respect to IRC, the freenode and OFTC networks seem to be commonly used for open source projects. Currently, #quamash on freenode is unused.

Use cases would for instance be:

  • Support for users, also from user-to-user, not only dev-to-user
  • Discuss the validity of small issues before placing an issue on github.

What are your thoughts? @harvimt @aknuds1

SSL handshakes crashes quamash

Hello,

The following test :

import sys
import unittest
import asyncio
import aiohttp
import logging
import quamash
from quamash import QApplication


class Bug(unittest.TestCase):
    def setUp(self):
        self.qapplication = QApplication([])
        self.lp = quamash.QEventLoop(self.qapplication)
        asyncio.set_event_loop(self.lp)
        self.except_raised = False
        self.lp.set_exception_handler(lambda loop, context: self.exception_handler(loop, context))

    def exception_handler(self, loop, context):
        message = context.get('message')
        if not message:
            message = 'Unhandled exception in event loop'

        try:
            exception = context['exception']
        except KeyError:
            exc_info = False
        else:
            exc_info = (type(exception), exception, exception.__traceback__)

        log_lines = [message]
        for key in [k for k in sorted(context) if k not in {'message', 'exception'}]:
            log_lines.append('{}: {!r}'.format(key, context[key]))

        self.fail('\n'.join(log_lines))

    def test_bug(self):
        @asyncio.coroutine
        def request():
            response = yield from aiohttp.get("https://google.fr")
            self.assertEqual(response.status, 200)
            json = yield from response.json()
            self.assertTrue('+1' in json)

        @asyncio.coroutine
        def waiting():
            tasks = []
            task = asyncio.async(request())
            tasks.append(task)
            yield from asyncio.wait(tasks)

        self.lp.run_until_complete(request())
        try:
            self.lp.close()
        finally:
            asyncio.set_event_loop(None)


if __name__ == '__main__':
    logging.basicConfig(stream=sys.stderr)
    logging.getLogger().setLevel(logging.DEBUG)
    unittest.main()

Crashes quamash with the following error :

AssertionError: Exception in callback QEventLoop.__notifier_cb_wrapper({10: <PyQt5.QtCore...x7f6c96974a68>, 22: <PyQt5.QtCore...x7f6c88437708>}, <PyQt5.QtCore...x7f6c884375e8>, 22, <bound method..., bufsize=0>>>, (None,))
handle: <Handle QEventLoop.__notifier_cb_wrapper({10: <PyQt5.QtCore...x7f6c96974a68>, 22: <PyQt5.QtCore...x7f6c88437708>}, <PyQt5.QtCore...x7f6c884375e8>, 22, <bound method..., bufsize=0>>>, (None,))>
Unhandled error in custom exception handler
context: {'message': 'Exception in callback QEventLoop.__notifier_cb_wrapper({10: <PyQt5.QtCore...x7f6c96974a68>, 22: <PyQt5.QtCore...x7f6c88437c18>}, <PyQt5.QtCore...x7f6c88437708>, 22, <bound method..., bufsize=0>>>, (None,))', 'exception': TypeError("disconnect() failed between 'activated' and all its connections",), 'handle': <Handle QEventLoop.__notifier_cb_wrapper({10: <PyQt5.QtCore...x7f6c96974a68>, 22: <PyQt5.QtCore...x7f6c88437c18>}, <PyQt5.QtCore...x7f6c88437708>, 22, <bound method..., bufsize=0>>>, (None,))>}
Traceback (most recent call last):
  File "/usr/lib/python3.4/asyncio/events.py", line 120, in _run
    self._callback(*self._args)
  File "/usr/lib/python3.4/site-packages/quamash/__init__.py", line 458, in __notifier_cb_wrapper
    notifier.activated.disconnect()
TypeError: disconnect() failed between 'activated' and all its connections

Proposition for a second example

I was playing with your lib trying to make it works with wamp and surprisingly it worked ! It's really interesting because wamp makes message passing and RPC with a backend painless.
You need a wamp router, autobahn python and your lib to make these examples run.

These example are intentionally a bit complex, I wanted to test everything before rewriting a medium sized PyQT5 app to use wamp. I can make them simpler if you find them interesting.
simple_wamp_backend.py
gui_wamp_client.py

Here is the part that launch gui_wamp_client.py file:

if __name__ == "__main__":
    QT_app = QApplication(sys.argv)

    loop = QEventLoop(QT_app)
    asyncio.set_event_loop(loop)

    runner = ApplicationRunner(url="ws://127.0.0.1:8080/ws", realm="realm1")
    runner.run(MainWindow)

have a good day :-)

Control logging

There's a lot of log statements coming from this library (which I like) but how do I disable these (loggers)?

e.g.

2016-11-23 00:35:43,837 [DEBUG] Running <generator object EmailManager.send_mail.<locals>.send_message at 0x7fa8f4faf518> until complete
2016-11-23 00:35:43,837 [DEBUG] Registering callback <bound method Task._step of <Task pending coro=<EmailManager.send_mail.<locals>.send_message() running at /usr/local/lib/python3.5/asyncio/coroutines.py:204>>> to be invoked with arguments () after 0 second(s)
2016-11-23 00:35:43,837 [DEBUG] Adding callback <Handle Task._step()> with delay 0
2016-11-23 00:35:43,837 [DEBUG] Starting Qt event loop
2016-11-23 00:35:43,839 [DEBUG] Callback timer fired, calling <Handle Task._step()>
2016-11-23 00:35:43,933 [INFO] Email sent!
2016-11-23 00:35:43,933 [DEBUG] Registering callback <function QEventLoop.run_until_complete.<locals>.stop at 0x7fa8f4fbd0d0> to be invoked with arguments (<Task finished coro=<EmailManager.send_mail.<locals>.send_message() done, defined at /usr/local/lib/python3.5/asyncio/coroutines.py:204> result=None>,) after 0 second(s)
2016-11-23 00:35:43,934 [DEBUG] Adding callback <Handle QEventLoop.run_until_complete.<locals>.stop(<Task finishe...> result=None>) at /home/thijs/.virtualenvs/foo/lib/python3.5/site-packages/quamash/__init__.py:262> with delay 0
2016-11-23 00:35:43,934 [DEBUG] Callback timer fired, calling <Handle QEventLoop.run_until_complete.<locals>.stop(<Task finishe...> result=None>) at /home/thijs/.virtualenvs/foo/lib/python3.5/site-packages/quamash/__init__.py:262>
2016-11-23 00:35:43,934 [DEBUG] Stopping event loop...
2016-11-23 00:35:43,934 [DEBUG] Stopped event loop
2016-11-23 00:35:43,934 [DEBUG] Qt event loop ended with result 0
2016-11-23 00:35:43,934 [DEBUG] Future <Task finished coro=<EmailManager.send_mail.<locals>.send_message() done, defined at /usr/local/lib/python3.5/asyncio/coroutines.py:204> result=None> finished running

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.