pyotherside icon indicating copy to clipboard operation
pyotherside copied to clipboard

Cannot retrieve `Future` from python on Windows

Open vSLG opened this issue 5 years ago • 2 comments

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.

vSLG avatar Jul 14 '20 18:07 vSLG

Have you checked if you pass it back to the Python environment (e.g. as a parameter to another call ()) and print it there, what is the value of it?

vSLG [email protected] schrieb am Di., 14. Juli 2020, 20:25:

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 pyothersideimport sysimport 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.15import 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.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/thp/pyotherside/issues/116, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABBASJVL6BWC2GBNJNZEPTR3SPKLANCNFSM4OZY4R5A .

thp avatar Jul 15 '20 06:07 thp

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'>

vSLG avatar Jul 15 '20 16:07 vSLG