Closed Bob1011941 closed 3 years ago
Thank you for your contribution!
I have never experienced this error, but upon inspection of serialized_image
, I noticed that the file handle was never closed.
I have pushed a fix to fixup-fd-leak. Would you mind testing it for your use-case?
I installed a fresh virtual environment of python 3.6. I downloaded a zip of your fixed library and used pip to install it to the new environment. I then used this code.
from PIL import Image, ImageDraw, ImageFont
import pystray
font = ImageFont.truetype(r"C:\Windows\Fonts\Calibri.ttf", 61)
def createImage(val):
image = Image.new('RGBA', (64, 64), (128, 0, 0, 0))
draw = ImageDraw.Draw(image)
draw.text((0, 0), str(val), font=font)
return image
def callback(icon):
hello = 0
while True:
icon.icon = createImage(hello)
print("Hello " + str(hello))
hello += 1
icon.visible = True
ico = pystray.Icon("My System Tray")
ico.run(setup=callback)
It then spat this out when I tried to run it.
(venv) D:\PystrayTest>python Main.py
Hello 0
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Python_Interpreters\Python36\lib\threading.py", line 916, in _bootstrap_inner
self.run()
File "C:\Python_Interpreters\Python36\lib\threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "D:\PystrayTest\venv\lib\site-packages\pystray\_base.py", line 186, in setup_handler
setup(self)
File "Main.py", line 21, in callback
icon.visible = True
File "D:\PystrayTest\venv\lib\site-packages\pystray\_base.py", line 161, in visible
self._update_icon()
File "D:\PystrayTest\venv\lib\site-packages\pystray\_win32.py", line 81, in _update_icon
self._assert_icon_handle()
File "D:\PystrayTest\venv\lib\site-packages\pystray\_win32.py", line 342, in _assert_icon_handle
win32.LR_DEFAULTSIZE | win32.LR_LOADFROMFILE)
File "C:\Python_Interpreters\Python36\lib\contextlib.py", line 88, in __exit__
next(self.gen)
File "D:\PystrayTest\venv\lib\site-packages\pystray\_util\__init__.py", line 47, in serialized_image
os.close(fd)
OSError: [Errno 9] Bad file descriptor
I get the same thing on a python 3.9 environment.
Here is the process I went through to install it.
(venv) D:\PystrayTest>python -m pip install pystray-fixup-fd-leak.zip
Processing d:\pystraytest\pystray-fixup-fd-leak.zip
Collecting Pillow (from pystray==0.17.1)
Using cached https://files.pythonhosted.org/packages/c6/ab/6a1d607a245cd878bc0f939314b56ffd9e978170583bc5b62f4c418a9a60/Pillow-8.0.1-cp36-cp36m-win_amd64.whl
Collecting six (from pystray==0.17.1)
Using cached https://files.pythonhosted.org/packages/ee/ff/48bde5c0f013094d729fe4b0316ba2a24774b3ff1c52d924a8a4cb04078a/six-1.15.0-py2.py3-none-any.whl
Installing collected packages: Pillow, six, pystray
Running setup.py install for pystray ... done
Successfully installed Pillow-8.0.1 pystray-0.17.1 six-1.15.0
Oh, sorry about that.
I did a thorough dive through the Windows backend, and discovered that the icons loaded are never released, so the process will eventually run out of GDI resources.
After adding the relevant code, your code, modified to not use a modified icon, runs without crashing. I have merged these changes and released pystray 0.17.2.
This is my first time contributing to any git hub so I apologize if this is not the right place to put this. I came up with a solution that doesn't crash and I thought I'd share.
My goal for my project was to update an image frequently. A temperature reading. The documentation says to use
icon.icon
to change the image but I found that after exactly 3332 calls, it would hang up and stop working.I think the problem has to do with
_update_icon()
calling_assert_icon_handle()
._assert_icon_handle()
seems to create a new ico image, set that to_icon_handle
then_update_icon()
updates the actual icon on the task bar. The creating of that ico image seems to become unstable after 3332 calls. Why? I have no idea but here is my work around.I redefined
_update_icon()
to not call_assert_icon_handle()
, changed_assert_icon_handle()
to return the created ico and now usesetIcon(value)
where value is that returned ico.In my example, I create a list of ico's that are pictures of numbers from 0 to 99 and in the call back function, use
icon.setIcon(imageList[i])
to set the value to the already created ico. This avoids creating an unnecessary amount of ico files which I think was causing problems.I'm happy to provide more info if needed. :)