Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot retrieve Future from python on Windows #116

Open
vSLG opened this issue Jul 14, 2020 · 2 comments
Open

Cannot retrieve Future from python on Windows #116

vSLG opened this issue Jul 14, 2020 · 2 comments

Comments

@vSLG
Copy link

vSLG commented Jul 14, 2020

Description

Python.call() does not receive anything if the called function returns asyncio.Future, only on Windows platform.

Environment 1

  • OS: Windows 8.1
  • Architecture: x86_64
  • pyotherside compiled manually in a MSYS2 environment
  • C compiler: MinGW-w64 (GCC 10.1.0), obtained from MSYS2 repository
  • QT version: 5.15, obtained from MSYS2 repository (shared lib version)
  • Python version: 3.8.3, obtained from MSYS2 repository

Environment 2

  • OS: Void Linux, kernel 5.6.18
  • Architecture: x86_64
  • pyotherside compiled manually
  • C compiler: GCC 9.3.0
  • QT version: 5.15
  • Python version: 3.8.3

Steps to reproduce (Environment 1)

  1. Write a python function that returns an asyncio.Future
  2. Run it on QML by using Python.call()
  3. Returned object by python function is blank

Programs used

main.py

import pyotherside
import sys
import asyncio as aio

from threading import Thread

class QMLTest:
    def __init__(self) -> None:
        # This is needed, else an exception is thrown on aio.get_event_loop()
        if sys.platform == "win32" and sys.version_info >= (3, 8, 0):
            aio.set_event_loop_policy(
                aio.WindowsSelectorEventLoopPolicy(),
            )
        
        try:
            self._loop = aio.get_event_loop()
        except RuntimeError:
            self._loop = aio.new_event_loop()
            aio.set_event_loop(self._loop)

        Thread(target=self._start_asyncio_loop).start()

    def _start_asyncio_loop(self) -> None:
        aio.set_event_loop(self._loop)
        self._loop.run_forever()

    async def testfunc(self) -> None:
        pass

    def test(self) -> aio.Future:
        future = aio.run_coroutine_threadsafe(self.testfunc(), self._loop)
        print("Python future: " + str(future))
        return future

print("sys.pratform: " + sys.platform)
print("Python: " + sys.version)
print("Using pyotherside version " + pyotherside.version)
QMLTEST = QMLTest()

main.qml

import QtQuick 2.15
import io.thp.pyotherside 1.5

Rectangle {
    color: 'grey'
    width: 400
    height: 400

    Python {
        id: py

        Component.onCompleted: {
            // Add the directory of this .qml file to the search path
            addImportPath(Qt.resolvedUrl('.'));
            importNames("main", ["QMLTEST"], () => {
                call("QMLTEST.test", [], pyFuture => {
                    print(`future: ${pyFuture}`)
                })
            })
        }
    }
}

Output

Environment 1 (Windows)

$ qml.exe main.qml
sys.pratform: win32
Python: 3.8.3 (default, Jun 17 2020, 06:11:06)  [GCC 10.1.0 64 bit (AMD64)]
Using pyotherside version 1.5.9
Python future: <Future at 0x6bbaf10 state=pending>
qml: future:

Environment 2 (Linux)

$ qml main.qml
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-j'
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-j'
Got library name:  "/usr/lib/qt5/qml/io/thp/pyotherside/libpyothersideplugin.so"
sys.pratform: linux
Python: 3.8.3 (default, Jul  3 2020, 22:42:34) 
[GCC 9.3.0]
Using pyotherside version 1.5.9
Python future: <Future at 0x7efc057e10d0 state=pending>
qml: future: QVariant(PyObjectRef, )

Expected behavior

It is expected that on a Windows system we may be able to get the Future object on QML. It is expected that Environment 1 have the same behavior as on Environment 2.

@thp
Copy link
Owner

thp commented Jul 15, 2020 via email

@vSLG
Copy link
Author

vSLG commented Jul 15, 2020

Added this function to QMLTest Python:

def print_future(self, future: aio.Future) -> None:
        print("QMLTEST.print_future(): " + str(future))
        print("QMLTEST.print_future(): type(future) = " + str(type(future)))

And on QML:

Component.onCompleted: {
    // Add the directory of this .qml file to the search path
    addImportPath(Qt.resolvedUrl('.'));
    importNames("main", ["QMLTEST"], () => {
        call("QMLTEST.test", [], pyFuture => {
            print(`future: ${pyFuture}`)
            
            call("QMLTEST.print_future", [pyFuture], null)
        })
    })
}

Output

Environment 1 (Windows)

$ qml main.qml
sys.pratform: win32
Python: 3.8.3 (default, Jun 17 2020, 06:11:06)  [GCC 10.1.0 64 bit (AMD64)]
Using pyotherside version 1.5.9
Python future: <Future at 0x6b9bf40 state=pending>
qml: future:
QMLTEST.print_future(): []
QMLTEST.print_future(): type(future) = <class 'list'>

Environment 2 (Linux)

$ qml main.qml
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-j'
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-j'
Got library name:  "/usr/lib/qt5/qml/io/thp/pyotherside/libpyothersideplugin.so"
sys.pratform: linux
Python: 3.8.3 (default, Jul  3 2020, 22:42:34) 
[GCC 9.3.0]
Using pyotherside version 1.5.9
Python future: <Future at 0x7f6caf3e90d0 state=pending>
qml: future: QVariant(PyObjectRef, )
QMLTEST.print_future(): <Future at 0x7f6caf3e90d0 state=finished returned NoneType>
QMLTEST.print_future(): type(future) = <class 'concurrent.futures._base.Future'>

mirukana added a commit to mirukana/mirage that referenced this issue Sep 29, 2020
Returning a Future doesn't work on Windows for some reason
(thp/pyotherside#116).

Instead of using these objects from QML to cancel running coroutines,
call a Python QMLBridge function that takes a coroutine UUID and will
take care of the cancelling.
mirukana added a commit to mirukana/mirage that referenced this issue Jan 4, 2021
Returning a Future doesn't work on Windows for some reason
(thp/pyotherside#116).

Instead of using these objects from QML to cancel running coroutines,
call a Python QMLBridge function that takes a coroutine UUID and will
take care of the cancelling.
mirukana added a commit to mirukana/mirage that referenced this issue Mar 3, 2021
Returning a Future doesn't work on Windows for some reason
(thp/pyotherside#116).

Instead of using these objects from QML to cancel running coroutines,
call a Python QMLBridge function that takes a coroutine UUID and will
take care of the cancelling.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants