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

ImageGrab gives OSError randomly #7133

Closed
siteng98 opened this issue May 4, 2023 · 6 comments · Fixed by #7141
Closed

ImageGrab gives OSError randomly #7133

siteng98 opened this issue May 4, 2023 · 6 comments · Fixed by #7141
Labels

Comments

@siteng98
Copy link

siteng98 commented May 4, 2023

What did you do?

I am using the following code snippet to copy the image from clipboard whenever the application (built using FastAPI) receives a request to do so.

from PIL import ImageGrab

im = ImageGrab.grabclipboard()

What did you expect to happen?

For it to get the image currently copied in the clipboard.

What actually happened?

It works fine most of the time, however it will randomly give the following error

Traceback (most recent call last):
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\uvicorn\protocols\http\httptools_impl.py", line 436, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\fastapi\applications.py", line 271, in __call__
    await super().__call__(scope, receive, send)
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\starlette\applications.py", line 118, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\starlette\middleware\errors.py", line 184, in __call__
    raise exc
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\starlette\middleware\errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\starlette\middleware\cors.py", line 84, in __call__
    await self.app(scope, receive, send)
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\starlette\middleware\exceptions.py", line 79, in __call__
    raise exc
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\starlette\middleware\exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 21, in __call__
    raise e
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\starlette\routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\starlette\routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\starlette\routing.py", line 66, in app
    response = await func(request)
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\fastapi\routing.py", line 237, in app
    raw_response = await run_endpoint_function(
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\fastapi\routing.py", line 163, in run_endpoint_function
    return await dependant.call(**values)
  File "C:\Users\M.user\Documents\GitHub\technical_alert\main.py", line 126, in get
    im = ImageGrab.grabclipboard()
  File "C:\Users\M.user\Documents\GitHub\technical_alert\alert\lib\site-packages\PIL\ImageGrab.py", line 112, in grabclipboard
    fmt, data = Image.core.grabclipboard_win32()
OSError: failed to open clipboard

What are your OS, Python and Pillow versions?

  • OS: Windows 10 Pro 21H2
  • Python: 3.9.16
  • Pillow: 9.5.0
@radarhere
Copy link
Member

Could you estimate how often the error occurs? 1 out of every 10 attempts? 1 out of every 100?

Does the error happen without FastAPI? In other words, if you just run ImageGrab.grabclipboard() from the command line, does the error still occur sometimes?

@radarhere
Copy link
Member

The error is occurring at

Pillow/src/display.c

Lines 439 to 440 in 2467db4

if (!OpenClipboard(NULL)) {
PyErr_SetString(PyExc_OSError, "failed to open clipboard");

https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-openclipboard states

OpenClipboard fails if another window has the clipboard open.

You're sure there's no pattern you can discern to the error? No clipboard operations you're running sometimes and not others? If you copy something, and then try grabbing the clipboard repeatedly afterwards, does it pass every time? In other words, once there is a failure, does ImageGrab.grabclipboard() keep failing until you copy something new?

@siteng98
Copy link
Author

siteng98 commented May 4, 2023

There is no clear frequency of occurrence, sometimes it occurs twice in a row while other times it could run perfectly for many attempts.

I have yet to find any pattern, it fails sometimes when I am not doing anything else on the laptop at all except for the program. I have tried making multiple requests quickly, repeatedly grabbing the clipboard, copying something else into the clipboard beforehand etc. It does seem to have a higher rate of occurrence when I make multiple requests very quickly, but not any pattern I can find. Also when it fails, I usually just need to retry and it will work, even if I retry within 1 second of failure, so it might be that the clipboard is just being used in the background by other windows processes very momentarily.

@radarhere
Copy link
Member

So if we were to adjust Pillow to pause for a moment after failure and then try again, do you think that would be sufficient to resolve this?

@siteng98
Copy link
Author

siteng98 commented May 8, 2023

I think that would! It is what I am currently doing for my program, to try until it works for a certain number of iterations

@radarhere
Copy link
Member

Ok, I've created PR #7141 to resolve this. If you could test it and confirm, that would be helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants