Setting working direction to direction of the script in Python (pyinstaller) - python

I have a pretty simple script that takes data from some .csv or .db files, performs manipulations and saves output in the similar files. I am working from Spyder with the parameter "Run in the directory of the file", so when I run the file my wd is set to file's directory automatically. SO that I put all files in one folder and do not mess with paths (e.g. using always open("data.csv")). And my files are stored like:
/Users/username/docs/script.py
/Users/username/docs/data.cv
/Users/username/docs/database.db
I've tried to use pyinstaller to that colleagues could you the script easily as well, but any time they would run it, it would set the working directory to /Users/username/ and all relative paths are getting broken.
How could I preserve this issue, so that the script (pyinstaller shell script) would be taking as working directory the folder with its location, like Spyder is doing?

Instead of using plain open('data.csv'), you should use a snippet like the following:
import os
import sys
if getattr(sys, 'frozen', False):
base_dir = sys._MEIPASS
else:
base_dir = os.path.abspath(os.path.dirname(__file__))
file = open(os.path.join(base_dir, 'data.csv'))
Then, when building you include your data files with --add-data=data.csv;.. Please use a colon (:) instead of a semi-colon (;) when not on Windows. If you're on Windows and using PowerShell, then escape the semi-colon with a backtick (`).

You can use the getcwd() function in os module to get the location of the current working directory. Then open the files like this.
open(os.getcwd()+'/data.csv')

Related

Python cx-freeze and missing files due to exe path

I did an application in Python using Pygame, then I did the exe using cx-freeze with build_msi option. The result is that the folder where I install the application contains in its root all files needed to run (apart the libs created by cx-freeze). So running my app from the folder where is installed or clicking its link on the desktop it works. Instead if I tr to start the application from a different folder using the console it does not start because it does not find some files, but it does not search for them in the folder where they are installed... so... the problem is that I need to start the application also from a different folder and I can not use a bat file where I could change to the folder and then run the application. Is there a way so that the Python application may know where are the files without fix their path on it (because in this case I would have a lot of problems during development)? I tryed to access them trough something like os.getcwd() + fileName but it does not work anyway.
The problem here is with the working directory because if you open the file from it's folder then the working directory will be correct but if you open the file from another place the working directory will be different and you will be looking for something that doesn't exist. os.getcwd() returns the working directory. but os.path.dirname(__file__) returns the directory to the folder that the running script is in. so you can do that:
import os
projectFolder = os.path.dirname(__file__)
os.path.join(projectFolder, fileName)

Set working directory in Python / Spyder so that it's reproducible

Coming from R, using setwd to change the directory is a big no-no against reproducibility because others do not have the same directory structure as mine. Hence, it's recommended to use relative path from the location of the script.
IDEs slightly complicate this because they set their own working directory. In Rstudio, I can easily get around this problem with Rstudio's projects, setting the project's directory to be my script folder.
With Python and Spyder, there doesn't seem to be any solution. Spyder does not have a feature like Rstudio's project. Setting the directory to the script's location does not work while doing interactive analysis (since __file__ is not available).
What to do so that the working directory in Python / Spyder is reproducible?
To do this automatically, put this at the beginning of your script:
from os import chdir, getcwd
wd=getcwd()
chdir(wd)
In the interim, you can use os.chdir
import os
os.chdir('C:\Users\me\Documents')
It appears they did consider this as a feature in Spyder based on this GitHub ticket, but it is still waiting implementation as of mid-May:
We could add an option to the Run dialog to automatically set the
working directory to the one your script is being ran.
However, someone else will have to implement it. We're pretty busy
with other things at the moment, sorry.
https://github.com/spyder-ide/spyder/issues/3154
#ccordoba12 ccordoba12 added this to the wishlist milestone on May 14
as I wrote here, Mark8888 pointed out to run the whole script (run file (F5)) instead of just pieces of the script
this way multiple approaches should work to get the script file location and change the current working directory
import os
# directory of script file
print(os.path.abspath(os.path.dirname(__file__)))
# change current working directory
os.chdir(os.path.abspath(os.path.dirname(__file__)))
# current working directory
print(os.getcwd())
also
import os
import sys
# directory of script file
print(os.path.abspath(os.path.dirname(sys.argv[0])))
# change current working directory
os.chdir(os.path.abspath(os.path.dirname(sys.argv[0])))
# current working directory
print(os.getcwd())
Well, there are a lot of things that you can try!
1. Change the directory to the current directory in the toolbar.
2. Change the Global directory to the current directory in Preferences>Global Working Directory. Click 'the current file directory' radio button.
Hope it helps!
I tried this and it works.
import os
abspath = os.path.abspath('') ## String which contains absolute path to the script file
os.chdir(abspath) ## Setting up working directory

Openpyxl with python2.7

I wanted to open excel file on python with using this code.
import openpyxl
wb= openpyxl.load_workbook('testfile.xlsx')
Error:No such file or directory: 'testfile.xlsx'
Where should I locate this file?
I am using Python2.7 on Spyder
Make sure that there is that file in the folder... Try this command to list the files in that folder just to make sure that python atleast recognizes or reads the files.
import os
print (os.listdir('your path'))
Try giving an absolute path. I mean give a leading slash which means an absolute path, or a path that starts at the root of your filesystem. No leading slash makes the path relative to your working directory.... I guess thats why it ain't working.
Lets say your file in downloads(as said in the comments)...
wb= openpyxl.load_workbook('/Users/name/Downloads/your_file')

python FileNotFoundError

I was writing a program that accesses a .txt file at the start of the program with the open() function. It ran without any errors on the IDE and I was also able to read the text file when running from the IDE without any issues. Although when I ran from the Python Launcher it threw a "FileNotFoundError"
Here's my code:
directions_object = open('warcards_directions.txt','r')
Further to Dan D's comment.. try putting this on the line in front of your open() call:
from os.path import abspath
print(abspath('warcards_directions.txt'))
You'll see that python looks in different places depending on where you run it from .. because it looks for files relative to the current working directory, which changes depending on how you run python.
This is a common problem for new comers. See here How to import files in python using sys.path.append? for some solutions (note the underlying problem in that post is the same as this one.. the fact that they're trying to import a file, and here we're trying to open one is not too important).
Also I'll add that I often reference things relative to the script itself... like this:
from os.path import abspath, join, dirname
script_dir = dirname(__file__)
txt_path = abspath(join(script_dir, "..", "path", "to", "warcards_directions.txt"))
This works if your txt file and your python script stay in the same place relative to each other (but might be installed in different places).
E.g. above assumes your script lives in C:\Foo\scripts\script.py and your text file lives in C:\Foo\path\to\warcards_directions.txt. The method above will work fine where ever you run the script from and it'll work if you move or rename the C:\Foo dir (e.g. to C:\Program Files\Bar). But it'll break if you decide to move scripts.py down a directory into C:\Foo (at which point you change the way txt_path is initialized to fix).
When you said "python launcher", do you mean the command line?
python myScript.py
If you, you will need to cd into the directory where the file is at before you can execute the script. Otherwise, provide the full path to the txt file in your script.

Opening/running Excel file from python

I need to start excel and open a file directly from python. Currently I am using:
import os
os.system('start excel.exe file.xls')
However I do not get desired result. I want to open a file from local destination (file is in the same folder with program), but this code open's the file with same name in my home (user) directory and not from my program directory.
The problem is that the directory where the program is located is not used. The current working directory is. So you have to find out which directory your program is located in, which python conveniently prepared for you in:
sys.path[0]
and either change directory to it:
os.chdir(sys.path[0])
or give full path for the file you want to open
os.system('start excel.exe "%s\\file.xls"' % (sys.path[0], ))
Note, that while Windows generally accept forward slash as directory separator, the command shell (cmd.exe) does not, so backslash has to be used here. start is Windows-specific, so it's not big problem to hardcode it here. More importantly note that Windows don't allow " in file-names, so the quoting here is actually going to work (quoting is needed, because the path is quite likely to contain space on Windows), but it's bad idea to quote like this in general!
You can also define the directory, where the python should operate.
import os
os.chdir('C:\\my_folder\\subfolder')
os.system('start excel.exe my_workbook.xlsx')
Don't forget to use backslashes in your path and there must be two of them everytime.
my_workbook.xlxs - here will be the name of your file
That file must be in that folder :)

Categories