1

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
dcs_2002
  • 35
  • 3
  • 1
    What is the program doing now that it is an .exe? Does it output the file at all, or output somewhere else? – mrblue6 Feb 16 '23 at 17:56
  • @mrblue6 The program confirms that the output file is generated without throwing any error but the file is nowhere to be seen – dcs_2002 Feb 17 '23 at 03:23

1 Answers1

1

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")
  • 1
    Thank you, that worked exactly like i wanted it to – dcs_2002 Feb 17 '23 at 03:45
  • Glad to help! Path resolution is always annoying – Cornelius-Figgle Feb 17 '23 at 08:15
  • @dcs_2002 https://stackoverflow.com/a/13790741/18505884 This post has a function, resource_path() which I've used before. This should also fix your problem, in a maybe slightly easier way. You call this function on any path you use and it will get the actual path instead of the TEMP path. I mostly used this for assets included with my .exe but I noticed I also used it for paths where I want to create files. – mrblue6 Feb 17 '23 at 16:01
  • That post seems to reference a function to get the path of the `%TEMP%` folder, however OP wanted to move the file into their project folder, not just access it – Cornelius-Figgle Feb 18 '23 at 08:39