py2exe access 'other_resources' - python

So with py2exe you can add additional data inside the library zip file, now I was wondering, how do you access this data, do you need to read it out from the zipfile or can you just access it like any other file ? or perhaps there's another way to access it.

I personally never used the zipfile. Instead, I pass the data files my program used in the setup method and use the bundle_files option (as described at the bottom of this page). For instance, the program I create using this call
setup(name = "Urban Planning",
windows = [{'script': "main.py", "dest_base": "Urban_Planning"}],
options = opts, # Dictionary of options
zipfile = None, # Don't create zip file
data_files = Mydata_files) # Add list of data files to folder
also has a piece before it where a config file and some images for the user interface are added like this
Mydata_files = [] # List of data files to include
# Get the images from the [script root]/ui/images/ folder
for files in os.listdir(sys.path[0] + '/ui/images/'):
f1 = sys.path[0] + '/ui/images/' + files
if os.path.isfile(f1): # This will skip directories
f2 = 'ui/images', [f1]
Mydata_files.append(f2)
# Get the config file from the [script root]/Configs folder
Mydata_files.append(('Configs', [sys.path[0] + '/Configs/defaults.cfg']))
This way I can call my config file just like I would while running the script using idle or command prompt and my UI images display correctly.

Related

Save file in a specific folder

I would like to save a CSV file in a specific folder, but I can't find anywhere how to do it...
this is the code
# Writing on a CSV FILE
fileToWrite = open(f"{userfinder}-{month}-{year}.csv', "a")
fileToWrite.write('Subject,Start Date,Start Time,End Date,End Time,All Day Event,Description\n')
fileToWrite.write(f'{string1}{tagesinfo2},{soup_datum},{soup_dienstbegin},{soup_datum},{soup_dienstende},,Kommentar: {soup_kommentar} Schiff: {b} Funktion: {soup_funktion} Schichtdauer: {soup_schichtdauer} Bezahlte Zeit: {soup_bezahltezeit} Mannschaft: {crew_list2}\n')
fileToWrite.close()
print(f'Datum: {soup_datum} Dienst: {string1}{tagesinfo2} --> Mannschaft: {crew_list2} --> OK')
You just have to change the working directory with os.chdir(path):
import os
path = '/Users/user/folder/example sub folder'
os.chdir(path)
#your code here
or, as mentioned in the comments, you can use:
myfolder = "c:/foo/bar/"
fileToWrite = open(f"{myfolder}/{userfinder}-{month}-{year}.csv", "a")
#in this case the path is "{myfolder}/{userfinder}-{month}-{year}"
This option includes the path when opening (only affects the one file) whereas os.chdir() changes the directory for everything (what I use personally for all of my projects, which are small).
If you don't want to change your folder for all files created and read, use the second option; but when you want a python file to affect every file in a distant location I would use os.chdir().

How to load resources file without giving entire path in Python

I want to read the properties file in Python without giving the entire path. Because if my code is deployed somewhere else then my package would fail if I pass the hardcore value. So below is my code to read the properties file by giving the entire path:
import configparser
config = configparser.RawConfigParser()
config.read('C:\\Users\\s\\IdeaProjects\\PysparkETL\\src\\main\\resources\\configs.properties')
dbname = config['DB']['dbname']
username=config['DB']['user']
password=config['DB']['password']
table=config['DB']['tablename']
driver=config['DB']['driver']
print(dbname)
and below is my configs.properties file:
[DB]
dbname=ourdb
user=root
password=root
tablename=loadtable
driver=com.mysql.cj.jdbc.Driver
I tried different ways like ConfigParser instead of RawConfigParser but didn't work. Is there any way to load files from the classpath?
Also, I tried different ways from this link but it didn't help. All I need is a path to pass it to config.read method but it should not be hardcoded as I did it in the code.
Below is my project structure:
Also, as suggested I tried below code and passed the URL to the config.read method but it's not working.
props = os.path.join(
os.path.dirname("resources"), # folder where the python file is
'src/main/resources/configs.properties'
)
config.read(props)
I get below error:
raise KeyError(key)
KeyError: 'DB'
if the file will always be in the same place relative to your python file, you can do the following:
props = os.path.join(
os.path.dirname(__name__), # folder where the python file is
'relative/path/to/configs.properties'
)

Pyinstaller single exe does not work properly and apparently, there are many people having problems that go unsolved

I have two files, one bell.mp3 one main.py file, that plays back bell.mp3 via subprocess.
If I do:
pyinstaller main.py
the Dist file ends up correctly, and everything works fine, The program runs in a directory.
This is the code for my file which i call pyinst_tester.py
it creates a text file, and plays a bell.mp3 file
#
from con import * # this is just a configuration file that has g='play' in it.
import subprocess
f=open(r'/home/godzilla/Desktop/Pyinstaller testing/testfile1','w')
f.write('This has worked')
f.close()
file='/home/godzilla/Desktop/Pyinstaller testing/data/bell.mp3'
if 'play' == g:
subprocess.call(['/usr/bin/cvlc',file])
a single file is created, but if I delete the bell.mp3 file it doesn't work. In a single file isn't the bell.mp3 zipped inside the main.exe ? therefore, redundant as a separate file ?
What Is the point having a single file exe, if you need an adjacent file with all the mp3s inside?
Pyinstaller has many features and if you want to include non python files (for example mp3 files) you have to do so explicitly with the --add-binary switch.
In one file mode the executable will be unpacked into a temporary directory prior to execution of the python code.
So how to write your code to access these data files.
You might want to look at the pyinstaller documention at following sections:
https://pyinstaller.readthedocs.io/en/stable/runtime-information.html#run-time-information
https://pyinstaller.readthedocs.io/en/stable/runtime-information.html#using-sys-executable-and-sys-argv-0
I personally place all my files in a separate directory. e.g. data.
If you place the file bell.mp3 in the directory data, then you had to call pyinstaller with the option --add-binary data:data
in the one file mode the executable is extracted into a temporary directory
whose path you get get from the variable sys._MEIPASS
Your data directory will bi in the sub directory data of sys._MEIPASS
In my example I create a function, that will be able to locate the data files in normal python mode and in pyinstaller one file or one directory mode.
Just try it out it should be self explaining
simple example:
minitst.py
import os, sys
import time
is_frozen = getattr(sys, "frozen", False)
MYDIR = os.path.realpath(os.path.dirname(__file__))
def data_fname(fname):
if is_frozen:
return os.path.join(sys._MEIPASS, "data", fname)
else:
return os.path.join(MYDIR, "data", fname)
def main():
print("This application is %s frozen" %
("" if is_frozen else "not"))
print("executable =", sys.executable,
"File =", __file__,
"mydir =", MYDIR)
if is_frozen:
print("MEIPASS", sys._MEIPASS)
fname = data_fname("tst.txt")
print("will open", fname)
with open(fname) as fin:
print(fin.read())
time.sleep(5) # this shall allow to view the console e.g. on windows if clicking on the executable.
if __name__ == "__main__":
main()
now create a directory data and place a file "tst.txt"
data/tst.txt
Hello world
Now call
pyinstaller -F minitst.py --add-binary data:data -c
and call dist/minitst from a console.
The output should look like:
This application is frozen
executable = /home/gelonida/so/pyinst/dist/minitst File = minitst.py mydir = /home/gelonida/so/pyinst
MEIPASS /tmp/_MEIKGqah9
will open /tmp/_MEIKGqah9/data/tst.txt
Hello
Now concerning your code.
I compacted the code to determine the datadir a little, but it is the same logic as in the upper example
import os, sys
from con import * # this is just a configuration file that has g='play' in it.
import subprocess
basedir = getattr(sys, "_MEIPASS", os.path.realpath(os.path.dirname(__file__)))
f=open('testfile1','w')
f.write('This has worked')
f.close()
file=os.path.join(basedir, 'data/bell.mp3')
if 'play' == g:
subprocess.call(['/usr/bin/cvlc',file])

Can I create directories with dynamic names on run time using os.mkdir()?

I have to download files from the web over several requests. The downloaded files for each request have to be put in a folder with the same name as the request number.
For example:
My script is now running to download files for request number 87665. So all the downloaded files are to be put in the destination folder Current Download\Attachment87665. So how do I do that?
What I have tried so far:
my_dir = "D:\Current Download"
my_dir = os.path.expanduser(my_dir)
if not os.path.exists(my_dir):
os.makedirs(my_dir)
But it doesn't meet my original requirement. Any idea how to achieve this?
Just create a path beforehand, via os.path.join:
request_number = 82673
# base dir
_dir = "D:\Current Download"
# create dynamic name, like "D:\Current Download\Attachment82673"
_dir = os.path.join(_dir, 'Attachment%s' % request_number)
# create 'dynamic' dir, if it does not exist
if not os.path.exists(_dir):
os.makedirs(_dir)

How to get the path of the posted file in Python

I am getting a file posting from a file:
file = request.post['ufile']
I want to get the path. How can I get it?
You have to use the request.FILES dictionary.
Check out the official documentation about the UploadedFile object, you can use the UploadedFile.temporary_file_path attribute, but beware that only files uploaded to disk expose it (that is, normally, when using the TemporaryFileUploadHandler uploads handler).
upload = request.FILES['ufile']
path = upload.temporary_file_path
In the normal case, though, you would like to use the file handler directly:
upload = request.FILES['ufile']
content = upload.read() # For small files
# ... or ...
for chunk in upload.chunks():
do_somthing_with_chunk(chunk) # For bigger files
You should use request.FILES['ufile'].file.name
you will get like this /var/folders/v7/1dtcydw51_s1ydkmypx1fggh0000gn/T/tmpKGp4mX.upload
and use file.name, your upload file have to bigger than 2.5M.
if you want to change this , see File Upload Settings
We cannot get the file path from the post request, only the filename, because flask doesn't has the file system access. If you need to get the file and perform some operations on it then you can try creating a temp directory save the file there, you can also get the path.
import tempfile
import shutil
dirpath = tempfile.mkdtemp()
# perform some operations if needed
shutil.rmtree(dirpath) # remove the temp directory

Categories