I created a test tool to check if there are any modules that do not work with pyinstaller so I can work them out before using pyinstaller on my main program.
When I try to interact with files paths in my script it looks like the program that pyinstaller created can not find the paths I have tried to hard code into the script such as "Z:\mkb\crew\mark_conrad\pictures\psd_tool_test_files\test.psd". I decided to use a simply os.path.exists() to debug this mystery but with no luck. When I run my debug program from python console it works just fine so what is going wrong here?
How I generated the exe:
pyinstaller "Z:\mkb\programing\python\util\pyinstaller_library_tester.py"
Python version: 2.7.15
PyInstaller version: 3.3.1
Consul output:
Testing: Z:\mkb\crew\mark_conrad\pictures\psd_tool_test_files\test.psd
>>> This path does not exsist.
Path Results: False
Testing: Z:\\mkb\\crew\\mark_conrad\\pictures\\psd_tool_test_files\\test.psd
>>> This path does not exsist.
Path Results: False
Testing: Z:/mkb/crew/mark_conrad/pictures/psd_tool_test_files/test.psd
>>> This path does not exsist.
Path Results: False
Testing: Z://mkb//crew//mark_conrad//pictures//psd_tool_test_files//test.psd
>>> This path does not exsist.
Path Results: False
Debug program Code:
def checkingPaths(path,btn):
import os
if os.path.exists(path):
print '>>> Found a working path use this for your formats for paths'
print 'Path Results:',os.path.exists(path)
btn.configure(bg='#00cc30')
else:
print '>>> This path does not exsist.'
print 'Path Results:',os.path.exists(path)
btn.configure(bg='#ff0000')
def osTest(btn):
print r'Testing: Z:\mkb\crew\mark_conrad\pictures\psd_tool_test_files\test.psd'
checkingPaths("Z:\mkb\crew\mark_conrad\pictures\psd_tool_test_files\test.psd",btn)
print r'Testing: Z:\\mkb\\crew\\mark_conrad\\pictures\\psd_tool_test_files\\test.psd'
checkingPaths("Z:\\mkb\\crew\\mark_conrad\\pictures\\psd_tool_test_files\\test.psd",btn)
print r'Testing: Z:/mkb/crew/mark_conrad/pictures/psd_tool_test_files/test.psd'
checkingPaths("Z:/mkb/crew/mark_conrad/pictures/psd_tool_test_files/test.psd",btn)
print r'Testing: Z://mkb//crew//mark_conrad//pictures//psd_tool_test_files//test.psd'
checkingPaths("Z://mkb//crew//mark_conrad//pictures//psd_tool_test_files//test.psd",btn)
def tkinterTest():
import Tkinter as tk
root = tk.Tk()
osBtn = tk.Button(root,text='os Test',command =lambda: osTest(osBtn))
osBtn.pack(padx=10,pady=2,fill='x')
root.mainloop()
tkinterTest()
It creates a new path you have to use when "compiled" under sys._MEIPASS. I generally make a function that resolves the relative resource path depending on whether running in python or when "compiled", like so:
def get_correct_path(relative_path):
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
Also ensure you properly include the files in your spec file.
Related
I am working on a project on path D:/code/project.
project.py
import os
import argparse
def create(path):
if os.path.exists(path):
os.chdir(path)
app = open("app.py", "w+")
app.write("print(\"Hello world!\")")
else:
path_list = path.split("/")
for i in path_list:
try:
os.mkdir(i)
except FileExistsError:
pass
except FileNotFoundError:
print("Invalid path")
exit()
os.chdir(i)
app = open("app.py", "w+")
app.write("print(\"Hello world!\")")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
create_parser = parser.add_subparsers().add_parser("create")
create_parser.add_argument("path", nargs="?", default=".", metavar="path", type=str)
args = parser.parse_args()
create(vars(args)["path"])
Basically, it has a custom command called create which takes path as an argument. When it detects that path already exists, it will create a app.py at the directory specified, and if it does not, it will try and create the path and app.py.
However, when I run
D:/code/project> python project.py create D:/newpath
Instead of creating a new directory newpath under D:, it creates newpath under my current directory (D:/code/project).
How do I change it such that changing directory to a root directory will actually switch correctly?
Your issue is with this line:
path_list = path.split("/")
On windows, that doesn't correctly split the path. It leaves the drive letter 'D:' as a fragment all by itself, but when you try to change directory to that path, it does nothing (assuming the current directory was on D: somewhere). It is the same behavior you get with the cd command on a command prompt. Drive letters in paths are pretty weird, they don't work like normal path prefixes.
To correctly split the path, use os.path.split(path). It will correctly use 'D:/' as the first element of the path, which when you change to it will put you on the root folder of your drive.
If you're using a recent version of Python (3.4+), you could also try using the pathlib module for a better, more object oriented way of manipulating paths:
from pathlib import Path
def create(path_str):
path = Path(path_str)
path.mkdir(parents=True, exist_ok=True) # creates parent folders as needed
with open(path / 'app.py', 'w') as app: # / operator joins path fragments
app.write('print("Hello world!")')
import os
def rename_file():
#function definition
file_name = os.listdir(r"C:\pyscripts\prank")
path = os.getcwd()
print(path)
rename_file() # function calling
*How does the directory is printed as 'C:\pyscripts' instead of
C:\pyscripts\prank
*
getcwd() function returns the current working directory for the python script, same as pwd command (Unix). So if you need the working directory to be C:\pyscripts\prank, then you should do:
os.chdir("C:\pyscripts\prank")
This works similar to the cd command.
I have data file which is required to be loaded during program execution. I am using following function to access my data file:-
def resource_path(relativePath):
try:
# PyInstaller stores data files in a tmp folder refered to as _MEIPASS
basePath = sys._MEIPASS
except Exception:
try:
if os.path.exists(os.path.join(os.path.dirname(__file__)), relativePath):
basePath = os.path.join(os.path.dirname(__file__), "multibootusb")
elif os.path.exists(os.path.join(sys.prefix, "multibootusb"), relativePath):
print os.path.join(sys.prefix, "multibootusb")
except Exception:
basePath = '.'
path = os.path.join(basePath, relativePath)
if not os.path.exists(path):
return None
return path
This works absolutely fine when running from IDE and after distributing as executable using pyinstaller. However, problem exist when my application installed using setup.py. here is a sample code I use for distributing data file usinf setup.py:-
data_files = [("/usr/share/applications",["data/multibootusb.desktop"]),
('/usr/share/pixmaps',["data/multibootusb.png"]),
(os.path.join(sys.prefix,"multibootusb", "tools"),["tools/checking.gif"])])
I had to use sys.prefix as path is different on various distros.
If you are running a frozen python script (frozen using py2exe) from a directory and drive different from where the script is present, what is the best way to determine the path of the executing script?
Few solutions I have tried
inspect.getfile(inspect.currentframe())
Problem: Does not return the full path. It only returns the script name.
os.path.abspath( __file__ )
Problem: Doesn't work on Windows
os.path.dirname(sys.argv[0])
Problem: Returns empty string.
os.path.abspath(inspect.getsourcefile(way3))
Will not work if the drive is different from the pwd
os.path.dirname(os.path.realpath(sys.argv[0]))
Will not work if the drive is different from the pwd
Here is a minimal not-working example
D:\>path
PATH=c:\Python27\;c:\Users\abhibhat\Desktop\ToBeRemoved\spam\dist\;c:\gnuwin32\bin
D:\>cat c:\Users\abhibhat\Desktop\ToBeRemoved\spam\eggs.py
import os, inspect, sys
def way1():
return os.path.dirname(sys.argv[0])
def way2():
return inspect.getfile(inspect.currentframe())
def way3():
return os.path.dirname(os.path.realpath(sys.argv[0]))
def way4():
try:
return os.path.abspath( __file__ )
except NameError:
return "Not Found"
def way5():
return os.path.abspath(inspect.getsourcefile(way3))
if __name__ == '__main__':
print "Path to this script is",way1()
print "Path to this script is",way2()
print "Path to this script is",way3()
print "Path to this script is",way4()
print "Path to this script is",way5()
D:\>eggs
Path to this script is
Path to this script is eggs.py
Path to this script is D:\
Path to this script is Not Found
Related Questions:
How to know the path of the running script in Python?
How do I get the path and name of the file that is currently executing?
python, path of script [closed]
Note
#Fenikso's solution will work if the script resides on the same drive where you are executing but when its on a different drive, it will not work
Another approach which works with cxFreeze when running from another drive even using PATH:
import sys
if hasattr(sys, 'frozen'):
print(sys.executable)
else:
print(sys.argv[0])
From Python:
H:\Python\Examples\cxfreeze\pwdme.py
From command line:
D:\>h:\Python\Examples\cxfreeze\dist\pwdme.exe
h:\Python\Examples\cxfreeze\dist\pwdme.exe
Using PATH:
D:\>pwdme.exe
h:\Python\Examples\cxfreeze\dist\pwdme.exe
IMHO, code that acts differently depending from absolute paths is not a good solution.
It will be probably better a relative path solution. Use dirname to know the relative directory and os.sep for cross platform compatibility.
if hasattr(sys, "frozen"):
main_dir = os.path.dirname(sys.executable)
full_real_path = os.path.realpath(sys.executable)
else:
script_dir = os.path.dirname(__file__)
main_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
full_real_path = os.path.realpath(sys.argv[0])
the frozen attribute is python standard.
Take a look also at Esky :
http://pypi.python.org/pypi/esky
Try this:
WD = os.path.dirname(os.path.realpath(sys.argv[0]))
That is what I use with cx_Freeze to get the directory from where the .exe is really running.
How do I get the current file's directory path?
I tried:
>>> os.path.abspath(__file__)
'C:\\python27\\test.py'
But I want:
'C:\\python27\\'
The special variable __file__ contains the path to the current file. From that we can get the directory using either pathlib or the os.path module.
Python 3
For the directory of the script being run:
import pathlib
pathlib.Path(__file__).parent.resolve()
For the current working directory:
import pathlib
pathlib.Path().resolve()
Python 2 and 3
For the directory of the script being run:
import os
os.path.dirname(os.path.abspath(__file__))
If you mean the current working directory:
import os
os.path.abspath(os.getcwd())
Note that before and after file is two underscores, not just one.
Also note that if you are running interactively or have loaded code from something other than a file (eg: a database or online resource), __file__ may not be set since there is no notion of "current file". The above answer assumes the most common scenario of running a python script that is in a file.
References
pathlib in the python documentation.
os.path - Python 2.7, os.path - Python 3
os.getcwd - Python 2.7, os.getcwd - Python 3
what does the __file__ variable mean/do?
Using Path from pathlib is the recommended way since Python 3:
from pathlib import Path
print("File Path:", Path(__file__).absolute())
print("Directory Path:", Path().absolute()) # Directory of current working directory, not __file__
Note: If using Jupyter Notebook, __file__ doesn't return expected value, so Path().absolute() has to be used.
In Python 3.x I do:
from pathlib import Path
path = Path(__file__).parent.absolute()
Explanation:
Path(__file__) is the path to the current file.
.parent gives you the directory the file is in.
.absolute() gives you the full absolute path to it.
Using pathlib is the modern way to work with paths. If you need it as a string later for some reason, just do str(path).
Try this:
import os
dir_path = os.path.dirname(os.path.realpath(__file__))
import os
print(os.path.dirname(__file__))
I found the following commands return the full path of the parent directory of a Python 3 script.
Python 3 Script:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pathlib import Path
#Get the absolute path of a Python3.6 and above script.
dir1 = Path().resolve() #Make the path absolute, resolving any symlinks.
dir2 = Path().absolute() #See #RonKalian answer
dir3 = Path(__file__).parent.absolute() #See #Arminius answer
dir4 = Path(__file__).parent
print(f'dir1={dir1}\ndir2={dir2}\ndir3={dir3}\ndir4={dir4}')
REMARKS !!!!
dir1 and dir2 works only when running a script located in the current working directory, but will break in any other case.
Given that Path(__file__).is_absolute() is True, the use of the .absolute() method in dir3 appears redundant.
The shortest command that works is dir4.
Explanation links: .resolve(), .absolute(), Path(file).parent().absolute()
USEFUL PATH PROPERTIES IN PYTHON:
from pathlib import Path
#Returns the path of the current directory
mypath = Path().absolute()
print('Absolute path : {}'.format(mypath))
#if you want to go to any other file inside the subdirectories of the directory path got from above method
filePath = mypath/'data'/'fuel_econ.csv'
print('File path : {}'.format(filePath))
#To check if file present in that directory or Not
isfileExist = filePath.exists()
print('isfileExist : {}'.format(isfileExist))
#To check if the path is a directory or a File
isadirectory = filePath.is_dir()
print('isadirectory : {}'.format(isadirectory))
#To get the extension of the file
fileExtension = mypath/'data'/'fuel_econ.csv'
print('File extension : {}'.format(filePath.suffix))
OUTPUT:
ABSOLUTE PATH IS THE PATH WHERE YOUR PYTHON FILE IS PLACED
Absolute path : D:\Study\Machine Learning\Jupitor Notebook\JupytorNotebookTest2\Udacity_Scripts\Matplotlib and seaborn Part2
File path : D:\Study\Machine Learning\Jupitor Notebook\JupytorNotebookTest2\Udacity_Scripts\Matplotlib and seaborn Part2\data\fuel_econ.csv
isfileExist : True
isadirectory : False
File extension : .csv
works also if __file__ is not available (jupyter notebooks)
import sys
from pathlib import Path
path_file = Path(sys.path[0])
print(path_file)
Also uses pathlib, which is the object oriented way of handling paths in python 3.
IPython has a magic command %pwd to get the present working directory. It can be used in following way:
from IPython.terminal.embed import InteractiveShellEmbed
ip_shell = InteractiveShellEmbed()
present_working_directory = ip_shell.magic("%pwd")
On IPython Jupyter Notebook %pwd can be used directly as following:
present_working_directory = %pwd
I have made a function to use when running python under IIS in CGI in order to get the current folder:
import os
def getLocalFolder():
path=str(os.path.dirname(os.path.abspath(__file__))).split(os.sep)
return path[len(path)-1]
Python 2 and 3
You can simply also do:
from os import sep
print(__file__.rsplit(sep, 1)[0] + sep)
Which outputs something like:
C:\my_folder\sub_folder\
This can be done without a module.
def get_path():
return (__file__.replace(f"<your script name>.py", ""))
print(get_path())