BoboTiG / python-mss

An ultra fast cross-platform multiple screenshots module in pure Python using ctypes.
https://pypi.org/project/mss/
MIT License
987 stars 88 forks source link

AttributeError: '_thread._local' object has no attribute 'data' #261

Closed qeWait closed 1 year ago

qeWait commented 1 year ago

General information:

Description of the warning/error

just do steps like here: https://stackoverflow.com/questions/76298989/attributeerror-while-trying-to-use-threading-with-the-mss-library

but with mss.grab()

Full message

Traceback (most recent call last):
  File "", line 30, in __func
  File "mss\base.py", line 90, in grab
  File "mss\windows.py", line 250, in _grab_impl
AttributeError: '_thread._local' object has no attribute 'data'

Other details

More information, if you think it is needed.

BoboTiG commented 1 year ago

Can you try again with the latest version (9.0.1 at the time)?

BoboTiG commented 1 year ago

It works if we adapt Vision:

class Vision:
    def __init__(self, mon):
        self.mon = mon

    def image_tracker(self, top, left, width, height, window_name):
        with mss.mss() as sct:
            mon = sct.monitors[self.mon]
            coordinates = {'top': mon['top'] + top, 'left': mon['left'] + left, 'width': width, 'height': height}

            while True:
                img = np.asarray(sct.grab(coordinates))
                cv2.imshow(f'{window_name}', img)
                if cv2.waitKey(25) & 0xFF == ord('q'):
                    cv2.destroyAllWindows()
                    break
qeWait commented 1 year ago

Traceback (most recent call last): File "", line 29, in __func File "venv\lib\site-packages\mss\base.py", line 90, in grab screenshot = self._grab_impl(monitor) File "venv\lib\site-packages\mss\windows.py", line 250, in _grab_impl bits = gdi.GetDIBits(memdc, self._handles.bmp, 0, height, self._handles.data, self._handles.bmi, DIB_RGB_COLORS) AttributeError: '_thread._local' object has no attribute 'data'

ms = mss() code:

    def __func(self) -> None:
            t = np.array(ms.grab(self.monitor))

result with latest version

qeWait commented 1 year ago

without threads it work, but in thread, it doesn't work

qeWait commented 1 year ago

same error with this:

    def __func(self) -> None:
            with mss() as ms:
                t = np.array(ms.grab(self.monitor))
BoboTiG commented 1 year ago

Please share the complete code.

qeWait commented 1 year ago

i tried to recreate error using easy example, but got another error:

Exception in thread Thread-1 (scnd_trd): Traceback (most recent call last): File "Python310-32\lib\threading.py", line 1009, in _bootstrap_inner self.run() File "Python310-32\lib\threading.py", line 946, in run self._target(*self._args, **self._kwargs) File "mmm.py", line 9, in scnd_trd exec("class Name:\n\tdef init(self):\n\t\tself.monitor = {'top': 100,'left': 100,'width': 20,'height': 20}\n\tdef func(self):\n\t\tt = np.array(ms.grab(self.monitor))\n\tdef start(self) -> None:\n\t\tself.func()\nx = Name()\nx.start()") File "", line 9, in File "", line 7, in start File "", line 5, in __func File "venv\lib\site-packages\mss\base.py", line 90, in grab screenshot = self._grab_impl(monitor) File "venv\lib\site-packages\mss\windows.py", line 235, in _grab_impl srcdc, memdc = self._handles.srcdc, self._handles.memdc AttributeError: '_thread._local' object has no attribute 'srcdc'

import mss
import numpy as np
import threading

ms = mss.mss()

def scnd_trd():
    exec("class Name:\n\tdef init(self):\n\t\tself.monitor = {'top': 100,'left': 100,'width': 20,'height': 20}\n\tdef __func(self):\n\t\tt = np.array(ms.grab(self.monitor))\n\tdef start(self) -> None:\n\t\tself.__func()\nx = Name()\nx.start()")

s_t = threading.Thread(target=scnd_trd)
s_t.start()

this example fully shows what I need

BoboTiG commented 1 year ago

You can't use ms = mss.mss() like that. It must be declared inside the same thread.

I reformated to be able to work on it more easily:

import mss
import numpy as np
import threading

def scnd_trd():
    class Name:
        def __init__(self):
            self.ms = mss.mss()
            self.monitor = {'top': 100,'left': 100,'width': 20,'height': 20}

        def func(self):
            np.array(self.ms.grab(self.monitor))

        def start(self) -> None:
            self.func()

    x = Name()
    x.start()

s_t = threading.Thread(target=scnd_trd)
s_t.start()

Here I moved the MSS instantiation into __init__().

That would work for you?

qeWait commented 1 year ago

AttributeError: '_thread._local' object has no attribute 'srcdc' solved.

There are 0 errors in the example. I used your advice in my code, but the error is still there :( the example and my code designed 1 to 1, idk, I will double-check the whole code tomorrow and let you know the result

qeWait commented 1 year ago

OK, I checked all the code of my program, the error was that the new system on the server returned null values for monitor

{ 'left': 0, 'top': 0, 'width': 0, 'height': 0} that is, the reason was the lack of size to capture part of the screen, I hope this issue will help someone in the future to quickly fix the problem