Search code examples
pythonpyinstaller

Generate an output csv file outside the exe file made using Pyinstaller


Problem

I'm using PyInstaller on Windows to make an .exe file of my project, basically my projects generates a csv file as output and the name of the csv file is dependent on the current time so the program generates unique file each time it is ran

I couldn't find any resource online that could help me with this problem


PyInstaller Command that I used: (data.csv file added is supposed to be bundled with exe so no issue there)

pyinstaller src\main.py -F --name "Attendance_System" --add-data "src\data.csv;data" --add-data "C:\Users\Darshit Shah\OneDrive\Desktop\TCET\Att_Sys\att_sys\Lib\site-packages\customtkinter;customtkinter" --clean

code block where the file is generated:

    except KeyboardInterrupt:
        timer.cancel()
        endTime = str(dt.datetime.now().time())

        op_file = f"{app.currdate}_{app.startTime[0:-7]}_{endTime[0:-7]}.csv".replace(":","-")
        app.getList().to_csv(f"{op_file}")
        print("O/P File generated")

        sys.exit()

Basically the code generates the file in the folder where my main.py is located but after bundling it with PyInstaller i cant seem to achieve that


Project Structure

my_proj
|
|--build
|
|--dist <--- "This is Where i want my output file to generate"
|  `--my_proj.exe
|
|--proj_venv
|  |--Include
|  |--Lib
|  |--Scripts
|  `--pyvenv.cfg
|
`--src <--- "Folder where my output file would normally generate without .exe"
   |--classes.py
   |--interface.py
   |--main.py
   `--data.csv

Solution

  • Explanation of Problem

    I echo @mrblue6's statement, but through past coding, believe that the line

    app.getList().to_csv(f"{op_file}")
    

    is the problem here. This would appear to generate the file in (most probably) the %TEMP%\_MEIXXXX folder (under the local AppData folder). This is because a compiled program uses a subdirectory of %TEMP% as its working directory (on Windows at least)

    EDIT:

    After posting, I remembered that as long as the output csv is in the same folder as your exe, you could do something like the following:

    op_path = os.path.join(os.path.dirname(sys.executable), op_file)
    

    As sys.executable holds the full path to the exe when compiled. This seems like a more robust solution than what I previously suggested. This would make:

    import os
    import sys  # if you haven't already
    
    op_file = f"{app.currdate}_{app.startTime[0:-7]}_{endTime[0:-7]}.csv".replace(":","-")
    op_path = os.path.join(os.path.dirname(sys.executable), op_file)
    app.getList().to_csv(f"{op_path}")
    print("O/P File generated")
    

    OLD:

    I would try to change the name output to have an absolute path instead of just a file name, something like:

    app.getList().to_csv(f"C:\users\dcs_2002\path\to\my_proj\dist\{op_file}")
    

    for basic usage. If you want this is work elsewhere, it depends on the actual location of your my_proj folder, but I would do something like the following (assuming my_proj is in your home directory:

    op_path = os.path.expanduser(f"~\\path\\to\\my_proj\\dist\\{op_file}")
    # OR
    op_path = os.path.join(os.path.expanduser("~"), "path", "to", "my_proj", "dist", op_file)
    

    Both of these would work as os.path.expanduser() expands any leading ~'s to the path of your home directory. You could also use os.path.expandvars() to expand more complex percent-enclosed variables (ie `os.path.expandvars("%LOCALAPPDATA%\rest\of\path"). Obviously modify the paths to suit your needs, just make sure to replace any backslashes with a double backslash (to escape Python). All together this would be:

    import os  # if you haven't already
    
    op_file = f"{app.currdate}_{app.startTime[0:-7]}_{endTime[0:-7]}.csv".replace(":","-")
    op_path = os.path.expanduser(f"~\\path\\to\\my_proj\\dist\\{op_file}")
    app.getList().to_csv(f"{op_path}")
    print("O/P File generated")