Search code examples
pythonseleniumpyautogui

Python, pyautogui: how to explicitly for os to find required file/dir?


I am writing Selenium tests and faced an issue when I need to upload an image, but the input I want to interact with is hidden from view and doesn't have a 'value' attribute. So, I decided to use pyautogui to find and attach image 'manually'.

The problem is that I need to use two functions:

pyautogui.write()
pyautogui.press('enter')

The last one doesn't wait for the OS to find the needed dir/file. The question: how to make pyautogui.press('enter') function wait until the file is found by the OS? Currently it is somehow achieved by time.sleep(), but I don't like this aproach.

ONLY THE LAST BLOCK OF CODE MATTERS, so you can skip the rest

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.edge.service import Service
from selenium.webdriver.common.by import By
import pyautogui
import os
from time import sleep

# set up 
chrome_service = Service(executable_path=ChromeDriverManager().install())
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option("detach", True)

# find the required element
driver = webdriver.Chrome(service=chrome_service, options=chrome_options)
driver.get("https://www.online-image-editor.com/")
element = driver.find_element(By.CSS_SELECTOR, ".btn_upload > span")
element.click() # This opens the windows file selector

# find image on my pc like "home/uploads/test_image.jpeg"
JPEG = os.path.abspath(os.path.join(os.getcwd(), "uploads/test_image.jpeg"))

# split path to make it word by word like ["home", "uploads", "test_image.jpeg"]
path = JPEG.split("/")

for word in path:
   sleep(0.2)
   pyautogui.write(word)
   sleep(0.2)
   pyautogui.press("enter")

So here if your remove the sleeps, pyautogui.press("enter") doesn't wait unitl the OS finds 'uploads' and just presses enter, which makes the test fail.


Solution

  • You can try this solution on Windows:

    while True:
        try:
            pyautogui.getWindowsWithTitle("Open")[0]
            break
        except IndexError:
            pass
    pyautogui.write(JPEG)
    pyautogui.press("enter")
    

    "Open" here is a name of window with file selection

    retry library can be used instead of while True loop. You can have a look on retry.retry_call function

    For Linux you can try this one:

    from selenium import webdriver
    from webdriver_manager.chrome import ChromeDriverManager
    from selenium.webdriver.edge.service import Service
    from selenium.webdriver.common.by import By
    import pyautogui
    import os
    from time import sleep
    
    import sys
    import subprocess
    import re
    
    def get_active_window_title():
        root = subprocess.Popen(['xprop', '-root', '_NET_ACTIVE_WINDOW'], stdout=subprocess.PIPE)
        stdout, stderr = root.communicate()
    
        m = re.search(b'^_NET_ACTIVE_WINDOW.* ([\w]+)$', stdout)
        if m != None:
            window_id = m.group(1)
            window = subprocess.Popen(['xprop', '-id', window_id, 'WM_NAME'], stdout=subprocess.PIPE)
            stdout, stderr = window.communicate()
        else:
            return None
    
        match = re.match(b"WM_NAME\(\w+\) = (?P<name>.+)$", stdout)
        if match != None:
            return match.group("name").strip(b'"')
    
        return None
    
    
    
    # set up
    chrome_service = Service(executable_path=ChromeDriverManager().install())
    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_experimental_option("detach", True)
    
    # find the required element
    driver = webdriver.Chrome(service=chrome_service, options=chrome_options)
    driver.get("https://www.online-image-editor.com/")
    element = driver.find_element(By.CSS_SELECTOR, ".btn_upload > span")
    element.click() # This opens the windows file selector
    
    # find image on my pc like "home/uploads/test_image.jpeg"
    JPEG = os.path.abspath(os.path.join(os.getcwd(), "uploads/test_image.jpeg"))
    
    while True:
        try:
            assert b"Open Files" in get_active_window_title()
            break
        except AssertionError:
            pass
    pyautogui.write(JPEG)
    pyautogui.press("enter")
    

    Source