asweigart / pyautogui

A cross-platform GUI automation Python module for human beings. Used to programmatically control the mouse & keyboard.
BSD 3-Clause "New" or "Revised" License
10.5k stars 1.27k forks source link

Test failures with KeyError: 'DISPLAY' #585

Open odidev opened 3 years ago

odidev commented 3 years ago

I have been working on installing and testing the pyautogui package locally on an x86_64 machine. I followed the docs and installed all the dependencies successfully, While testing it failed for the command tox -e py37, Please find below the error details:

(venv37) x64_server@x_server_embedded:~/Odidev/pyautogui$ sudo python3.7 -m tox -e py37
GLOB sdist-make: /home/x64_server/Odidev/pyautogui/setup.py
py37 recreate: /home/x64_server/Odidev/pyautogui/.tox/py37
py37 installdeps: pymsgbox, pillow, pytest, pytweening, pyscreeze
py37 inst: /home/x64_server/Odidev/pyautogui/.tox/.tmp/package/1/PyAutoGUI-0.9.52.zip
py37 installed: WARNING: The directory '/home/x64_server/.cache/pip' or its parent directory is not owned or is not writable by the current user. The cache has been disabled. Check the permissions and owner of that directory. If executing pip with sudo, you should use sudo's -H flag.,attrs==21.2.0,importlib-metadata==4.5.0,iniconfig==1.1.1,MouseInfo==0.1.3,packaging==20.9,Pillow==8.2.0,pluggy==0.13.1,py==1.10.0,PyAutoGUI @ file:///home/x64_server/Odidev/pyautogui/.tox/.tmp/package/1/PyAutoGUI-0.9.52.zip,PyGetWindow==0.0.9,PyMsgBox==1.0.9,pyparsing==2.4.7,pyperclip==1.8.2,PyRect==0.1.4,PyScreeze==0.1.27,pytest==6.2.4,python3-xlib==0.15,PyTweening==1.0.3,toml==0.10.2,typing-extensions==3.10.0.0,zipp==3.4.1
py37 run-test-pre: PYTHONHASHSEED='2160134332'
py37 runtests: commands[0] | python tests/test_pyautogui.py
Traceback (most recent call last):
  File "tests/test_pyautogui.py", line 12, in <module>
    import pyautogui
  File "/home/x64_server/Odidev/pyautogui/.tox/py37/lib/python3.7/site-packages/pyautogui/__init__.py", line 249, in <module>
    import mouseinfo
  File "/home/x64_server/Odidev/pyautogui/.tox/py37/lib/python3.7/site-packages/mouseinfo/__init__.py", line 223, in <module>
    _display = Display(os.environ['DISPLAY'])
  File "/usr/local/lib/python3.7/os.py", line 681, in __getitem__
    raise KeyError(key) from None
KeyError: 'DISPLAY''

It would be really helpful if you could share some pointers on how to resolve the above issue.

Environment detail: PyAutoGUI v0.9.52 Python 3.7.10 pip 20.1.1 Pytest 6.2.4

asweigart commented 3 years ago

You're on Linux right? Can you give me the distro and version? Is this a headless machine without a monitor?

(Note for my future self: I need to look into the DISPLAY environment variable and when it isn't set. This page has some more info: https://askubuntu.com/questions/432255/what-is-the-display-environment-variable )

s-weigand commented 3 years ago

The problem is that pyautogui initializes the code needed for the display interaction at import time. Even if you don't test the GUI interaction or even use any part of pyautogui, when you import something from a module that also imports pyautogui your headless CI will crash if you don't have some kind of virtual display available.

This is my drone CI pipeline which can also run with modules that import pyautogui.


kind: pipeline
type: docker
name: tests

trigger:
  branch:
    - main
  event:
    - push
    - pull_request

steps:
  - name: Install dependencies and run tests
    image: python:3.8-buster
    commands:
      - apt update
      - apt install -y xvfb xserver-xephyr xauth
      - touch ~/.Xauthority
      - python -m pip install pytest-xvfb
      # all the above is only needed for the CI an has nothing to do with the tests themselves
      - python -m pip install -r requirements_dev.txt
      - python -m pip install .
      - python -m pytest

For Linux you can install xvfb as virtual display and set it as the display to be used (that is what pytest-xvfb does in my example pipeline). As a side note if you import from modules that also import pyautogui in you conftest.py you need to wrap those imports inside of functions/classes, so the import happens at runtime and not at import time, because pytest-xvfb isn't fully initialized at that time.

Hope this helps someone 😄

odidev commented 2 years ago

Thanks @s-weigand for your response.

As suggested, I installed xvfb but still got the same DISPLAY error for tox command, also it is giving the same error with MobaXterm.

While using pytest, I got 11 failures with different errors:

Test_using_pytest: pyautogui_pytest_result.txt Test_using_tox: pyautogui_tox_result.txt

odidev commented 2 years ago

@asweigart Is there any update for the above issue ?

s-weigand commented 2 years ago

@odidev The tox error is because you run your test script directly with python and not with pytest and pytest-xvfb (pytest-xvfb set up all the env vars when fixtures get initialized). The pytest errors look mostly like usage errors to me:

        elif secondArg is None and firstArg is not None:
>           return Point(int(firstArg), int(position()[1]))
E           TypeError: int() argument must be a string, a bytes-like object or a number, not 'list'

Where firstArg = [0, 0], secondArg = None

odidev commented 2 years ago

Hi @s-weigand After installation of pytest-xvfb ran the test script with pytest still getting the same above error.

s-weigand commented 2 years ago

@odidev As I said that error looks like a usage error to me, since you try to cast the list firstArg = [0, 0] to an int.

Judging from the docstring:

firstArg and secondArg can be integers, a sequence of integers, or a string representing an image filename to find on the screen (and return the center coordinates of).

You need to do more checks than just checking if those values are None, since the code will break for all cases but int (or strings which can be cast to int). Thus your error is unrelated to pyautogui

BackMountainDevil commented 1 year ago

I write a code and I can run it with vs code or by myself. I try to run the code as a service on my linux. And it got such error

7月 17 08:55:53 hp python[62308]:     import pyautogui
7月 17 08:55:53 hp python[62308]:   File "/home/mifen/.conda/envs/310/lib/python3.10/site-packages/pyautogui/__init__.py", line 246, in <module>
7月 17 08:55:53 hp python[62308]:     import mouseinfo
7月 17 08:55:53 hp python[62308]:   File "/home/mifen/.conda/envs/310/lib/python3.10/site-packages/mouseinfo/__init__.py", line 223, in <module>
7月 17 08:55:53 hp python[62308]:     _display = Display(os.environ['DISPLAY'])
7月 17 08:55:53 hp python[62308]:   File "/home/mifen/.conda/envs/310/lib/python3.10/os.py", line 680, in __getitem__
7月 17 08:55:54 hp python[62308]:     raise KeyError(key) from None
7月 17 08:55:54 hp python[62308]: KeyError: 'DISPLAY'

just like @ s-weigand said, in system service, there is no display.