I’m trying to use an asynchronous function in python-3, but it’s giving error

Asked

Viewed 199 times

0

Error:

Warning (from warnings module):
  File "C:\Users\tiago.pereira\Desktop\python\kivy\kivy_teste.py", line 43
    pythoncom.PumpMessages()
RuntimeWarning: coroutine 'Keyboard' was never awaited
TypeError: an integer is required (got type coroutine)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\tiago.pereira\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pyHook\HookManager.py", line 348, in KeyboardSwitch
    event = KeyboardEvent(msg, vk_code, scan_code, ascii, flags, time, hwnd, win_name)
SystemError: <class 'pyHook.HookManager.KeyboardEvent'> returned a result with an error set


Code:

import pythoncom,pyHook
import threading
import ctypes,sys,asyncio
import cv2
import tkinter as tk
from tkinter import *


#kivy.require('1.9.0')



#def popup():
 #   popup = Popup(content=Label(text="I am popup"))s
  #  popup.open()

first = True

async def Keyboard(event):    
    print(event.GetKey())


    if event.GetKey() == 'Lcontrol':
        ctypes.windll.user32.LockWorkStation()
    elif event.GetKey() == 'Next': 
        sys.exit(0)
    else:
        await picture
        return False

async def picture():
    cap = cv2.VideoCapture(0)    
    ret,frame = cap.read()  # return a single frame in variable `frame`
    cv2.imwrite('C:/Users/tiago.pereira/desktop/c1.png',frame)    
    cap.release()    


hm = pyHook.HookManager()
hm.KeyDown = Keyboard
#hm.MouseAll = Mouse
hm.HookKeyboard()
#hm.HookMouse()
pythoncom.PumpMessages()
  • And the HookManager.KeyDown supports a function async?

  • https://stackoverflow.com/questions/3673769/pyhook-pythoncom-stop-working-after-too-much-keys-pressed-python so I read yes

  • 1

    I didn’t see where this question refers to coroutines (async). There thread is used, which is a completely different concept. I recommend that you review the module documentation.

2 answers

3

In particular, the question you quoted in the comments is from 2010 - the Python async as it is today didn’t even exist yet (neither the syntax nor the concept). Surely this module does not support asynchronous functions.

The obvious solution there is simply to make your Keyboard function a normal function, without being asynchronous. The only asynchronous thing she does is actually in the other function - picture

which, by the way, is called wrong - should be await picture(). And ai If the Pythonhook framework worked with Python’s Asyncio, the function itself Keyboard would be suspended until the picture be ready. Hardly seems to be what you really want.

What you would like there is - whether Keyboard can be asynchronous or not - is to process the pressed key as quickly as possible, if any of the keys has a long process, then you fire it as a separate asynchronous task - and end the Keyboard function, getting "ready for the next key". That is: the Keyboard function does not need to be asynchronous - it needs to create tasks based on keystrokes.

The way to create a new asynchronous task is with the method create_task event loop. (is new in Python 3.7. In 3.5 and 3.6 it did not exist and must be used ensure_future).

Even in an asynchronous function, if you do not need the return value of another asynchronous function at the point where you are in the code, you should use the create_task, instead of the await. The await makes the your function wait for the other to be completed. Python’s entire async mechanism makes it possible for other tasks and functions to continue to perform, but the function that has the await is paused waiting for the answer of the sub-task, of the same form that in synchronous code.

That is, your code will work - at least that part, if your Keyboard function is written as:

def Keyboard(event):    
    print(event.GetKey())


    if event.GetKey() == 'Lcontrol':
        ctypes.windll.user32.LockWorkStation()
    elif event.GetKey() == 'Next': 
        sys.exit(0)
    else:
        loop = asyncio.get_event_loop()
        loop.create_task(picture())
    return False  # Fora do "if": também retorna False quando o sistema sair do "LockWorkStation" acima

async def picture():
   ...

Of course, for this to work it will depend on the rest of the code starting an asyncio Event-loop that is working normally - it is not the default kiwi to work with asyncio.

  • Obg I think tmb would be a viable option

0


I found the solution:

t = threading.Thread(target=picture) #added to queue
t.start()
  • Hello @Tiago. Mark your reply as valid!

  • 1

    Yes, as I explained - you don’t have to use asyncio. Multi-threaded code requires no change in functions, just a few precautions not to change the same data structure in parallel - and in this case there is no risk of having too many threads running at the same time. (in a server code the recommendation is to have a threadpool, and then it gets a little more complex)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.