Search code examples
python-3.xseleniumselenium-chromedriverpyinstaller

Chromedriver Manager download doesn't work after .exe conversion via PyInstaller


Dear Stackoverflow community,

I am using Selenium and Python to automate a task. When my program runs as myscript.py, it works seamlessly. I am converting myscript.py to myscript.exe using:

PyInstaller --onefile --windowed --icon="icon.ico" --add-data "icon.ico;." myscript.py

The resulting myscript.exe file does not work, giving the following error:

Traceback (most recent call last):
File "myscript.py", line 155, in <module>
File "myscipt.py", line 32, in main
File "webdriver_manager\chrome.py", line 39, in install
File "webdriver_manager\core\manager.py", line 30, in _get_driver_path
File "webdriver_manager\core\download_manager.py", line 28, in download_file
File "webdriver_manager\core\http.py", line 35, in get
File "webdriver_manager\core\utils.py", line 289, in show_download_progress
File "tqdm\std.py", line 1109, in __init__
File "tqdm\std.py", line 1361, in refresh
File "tqdm\std.py", line 1509, in display
File "tqdm\std.py", line 350, in print_status
File "tqdm\std.py", line 343, in fp_write
File "tqdm\utils.py", line 89, in __getattr__
AttributeError: 'NoneType' object has no attribute 'write'

Line 32 in main is:

driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), options=options)

I am probably missing something fundamental. Any help from the community is greatly appreciated.


Solution

  • The issue is that webdriver_manager uses tqdm to show a progress bar in the terminal during the show_download_progress function, however since you are using the --windowed option with pyinstaller your program isn't run with a terminal. So when tqdm tries to show the progress bar there is nothing to write to, which is why it says NoneType object has no attribute 'write'.

    This can be typically be solved by explicitly setting stdout and stderr to an object with a write method near the entrypoint to your application so they are set before any other code attempts to write to them.

    For example:

    import io
    import sys
    
    buffer = io.StringIO()
    sys.stdout = buffer
    sys.stderr = buffer