pyinstaller is not attaching my image when I create an executable - python

How can i make an executable that can load image, and that my friends don't depend on downloading the executable and image or a heavy folder?
I'm trying to create an executable for my python program, but when I try to open its executable, I get this error:
Traceback (most recent call last):
File "main.py", line 49, in <module>
File "tkinter\__init__.py", line 4103, in __init__
File "tkinter\__init__.py", line 4048, in __init__
_tkinter.TclError: couldn't open "logo.png": no such file or directory
The code I'm using to compile is this:
pyinstaller --onefile --windowed --add-data "logo.png;." main.py
Is there any other compilation method or other way to make an executable with the logo attached? I tried some methods like:
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
But to no avail, and my complete code is this:
from pytube import Playlist, YouTube
from tkinter import *
from moviepy import *
import os
import re
if os.name == "nt":
downfolder = f"{os.getenv('USERPROFILE')}\\Downloads"
else:
downfolder = f"{os.getenv('HOME')}/Downloads"
def playlist_audio():
get_link = link_field.get()
p = Playlist(get_link)
p._video_regex = re.compile(r"\"url\":\"(/watch\?v=[\w-]*)")
for video in p.videos:
screen.title('downloading.')
mp3_audio = video.streams.filter(only_audio=True).first().download(downfolder)
audioconvert(mp3_audio)
#
screen.title('completed')
def video_mp3():
get_link = link_field.get()
screen.title('downloading.')
mp3_audio = YouTube(get_link).streams.filter(only_audio=True).first().download(downfolder)
audioconvert(mp3_audio)
#
screen.title('completed')
def audioconvert(mp3_audio):
try:
base, ext = os.path.splitext(mp3_audio)
new_file = base + '.mp3'
os.rename(mp3_audio , new_file)
except WindowsError:
os.remove(new_file)
os.rename(mp3_audio , new_file)
screen = Tk()
title = screen.title('Python mp3')
screen.resizable(False, False)
Canvas = Canvas(screen, width=400, height=200)
Canvas.pack()
logoimg = PhotoImage(file='logo.png')
logo_img = logoimg.subsample(2, 2)
Canvas.create_image(215, 25, image=logo_img)
link_field = Entry(screen, width=50)
link_label = Label(screen, text="Enter the song/playlist URL.")
Canvas.create_window(200, 90, window=link_field)
Canvas.create_window(200, 70, window=link_label)
def convert():
try:
video_mp3()
return True
except:
screen.title("wait a few seconds")
try:
playlist_audio()
return False
except:
screen.title("unknown error, try again")
download = Button(screen, text="download", bg='green', padx='20', pady='5',font=('Arial', 12), fg='#fff', command=convert)
Canvas.create_window(200, 140, window=download)
screen.mainloop()

I was able to get this to work.
In your python code add this to access your image from the MEI directory
photopath = os.path.join(os.path.dirname(__file__), 'logo.png')
logoimg = PhotoImage(file=photopath)
Here are the steps I took.
create empty folder; cd into it; copy the logo.png an script(main.py)
py -m venv venv && venv\Scripts\activate
py -m pip install --upgrade pip pyinstaller moviepy pytube
pyinstaller -F main.py
Then in the spec file add on line 11 (i think) edit datas=[('logo.png','.')],
You can make other adjustments in the spec file as well like setting console=False for it to work in windowed mode and changing the name of the output executable file and other stuff.
pyinstaller main.spec
Thats it... the executable should work fine and load your photo and all.

Related

Problem in copying file by Shutil in python

I want, when the user clicks on my executable file, the clicked file will be copied to a folder in C drive
I get the file name with its path by the following code:
Get_the_file_name = os.path.abspath(__file__)
And I intend to transfer the clicked file to the following address:
copy_path = 'C:/Users/joli/newfolder/copedfile.exe'
The entire program command
import shutil , os
try:
Get_the_file_name = os.path.abspath(__file__)
os.makedirs('C:/Users/ز/newfolder') #create Folder
copy_path = 'C:/Users/joli/newfolder/copedfile.exe'
shutil.copy(Get_the_file_name, copy_path)
except Exception as aa:
asass=open('C:/Users/rambod/Desktop/Vemv/eyefour/Error.txt' , 'w').write(str(aa))
No problem occurs when the above command is executed in the pycharm environment. However, after converting this command by Pyinstaller, the program encounters error 2.
Error text
[Errno 2] No such file or directory: 'C:\Users\joli\AppData\Local\Temp\_MEI88082\client.exe'
** ---> client.exe The name of the file has been clicked
import shutil , os
try:
Get_the_file_name = os.path.abspath(__file__)
os.makedirs('C:/Users/ز/newfolder') #create Folder
copy_path = 'C:/Users/joli/newfolder/copedfile.exe'
shutil.copy(Get_the_file_name, copy_path)
except Exception as aa:
asass=open('C:/Users/rambod/Desktop/Vemv/eyefour/Error.txt' , 'w').write(str(aa))

Pyinstaller Question about icons and writing to bundled files

I am using Python 3.6.8 and Linux Ubuntu
I have an icon.ico image, and i want to embed it into the exe file in Pyinstaller.
I have tried
pyinstaller -F -i= 'icon.ico' main.py and
pyinstaller -F --icon= 'icon.ico:.' main.py
i tried all sorts of ways and i cant get it to work...
I basically have a tkinter app that i want to make an exe from...and i have created a png file turned it into icon and try to load it, but i am not sure it can be done,....is there a way to assign image.ico to apps? or change them, i know there is a way from the .desktop ...how do software do it that you download?
This is the internal code i am using:
import os, sys
from con import * # this is just a configuration file that has g='play' in it.
import subprocess
def resource_path(relative_path):
if getattr(sys, 'frozen', False):
bundle_dir = sys._MEIPASS # for --onefile
# bundle_dir = path.dirname(path.abspath(sys.executable)) # for --onedir
else:
bundle_dir = os.path.dirname(os.path.abspath(__file__))
return os.path.join(bundle_dir, relative_path)
resource_path('data/bitbud.ico')
basedir = getattr(sys, "_MEIPASS", os.path.realpath(os.path.dirname(__file__)))
file=os.path.join(basedir, 'data/bell.mp3')
file2=os.path.join(basedir, 'data/testfile2.txt')
file3=os.path.join(basedir, 'data/bitbud.ico')
f=open('testfile1','w')
f.write('This has worked')
f.close()
f=open(file2,'a')
f.write('append also works')
f.close()
#if 'play' == g:
try:
subprocess.call(['/usr/bin/cvlc',file],timeout=6)
except:
pass
f1=open(file2,'r')
f=open('testfile3','w')
readit='The app has inside it:' +f1.read()
f.write(readit)
f.close()
f1.close()
Some line for you :D
Get file in bundled
def resource_path(relative_path):
if getattr(sys, 'frozen', False):
bundle_dir = sys._MEIPASS # for --onefile
# bundle_dir = path.dirname(path.abspath(sys.executable)) # for --onedir
else:
bundle_dir = path.dirname(path.abspath(__file__))
return path.join(bundle_dir, relative_path)
---
resource_path('assets/file.jpg')
Edit some.spec file after run Pyinstaller first time, add params like below:
a = Analysis(
...
datas=[('path/to/file.jpg', 'assets')]
...
...
exe = EXE(
...
icon='path/to/icon.ico')

Best way to call subprocess scripts in a Python exe

I'm currently trying to make a cross-platform Python exe file that relies on calling other Python and R scripts. One issue I was facing was that my exe file expected my script files to be in the root directory as opposed to the directory where my exe file is. I've managed to fix this by doing the following
if getattr(sys, 'frozen', False):
PROJECT_ROOT = sys.executable
else:
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
pwd = os.path.dirname(PROJECT_ROOT)
# messagebox is for the tkinter based GUI
messagebox.showinfo('Info', 'Please wait a moment')
subprocess.call(['python', pwd + '/Customs.py'], shell = False)
subprocess.call(['Rscript', pwd + '/r_script.R'], shell=False)
subprocess.call(['python', pwd + '/by_month.py'], shell = False)
messagebox.showinfo('Info', 'Processing completed)
I'm wondering if there is a cleaner/ more reliable way of doing this to decrease the potential of an error occurring that might break the software.
I should also mention that I've read something about turning the other scripts into an exe file first and I would like to hear your opinion on this.
Thanks
First I suggest you use a function that returns the current path of your file when it is running as a frozen script or running normally to make testing of your code easy.
Second, if you want to bundle your script files you need to first bundle your files with executable as a DATA file. Next prepare the path for that file when using them with the said function.
def app_path():
if getattr(sys, 'frozen', False):
app_path = os.path.dirname(sys.executable)
elif __file__:
app_path = os.path.dirname(__file__)
return app_path
def resource_path(relative_path):
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)
# messagebox is for the tkinter based GUI
messagebox.showinfo('Info', 'Please wait a moment')
subprocess.call(['python', resource_path('Customs.py')], shell=False)
subprocess.call(['Rscript', resource_path('r_script.R')], shell=False)
subprocess.call(['python', resource_path('by_month.py')], shell=False)
messagebox.showinfo('Info', 'Processing completed)
And your command to build your app would be something like this:
pyinstaller -F --add-data "Customs.py;." --add-data "r_script.R;." --add-data "by_month.py;." myscript.py
When your app runs, the data files Customs.py, r_script.R, etc would be extracted to a temp folder and resource_path would return the exact path for each file. But remember that if you want to load some files from your current directory (Where the exe file located) you can use app_path function.

tkinter PhotoImage doesn't exist?

from tkinter import *
root = Tk()
photo = PhotoImage(file='blueface.png')
label = Label(root, image=photo)
label.pack()
root.mainloop()
The image face.png is in the same directory as this .py script, but when I run it, I get the following error:
line 5, in <module>
photo = PhotoImage(file='blueface.png')
line 3539, in __init__
Image.__init__(self, 'photo', name, cnf, master, **kw)
line 3495, in __init__
self.tk.call(('image', 'create', imgtype, name,) + options)
_tkinter.TclError: couldn't open "face.png": no such file or directory
It doesn't matter very much that the image is in the same folder as the script, when you call the file like that without a path python assumes it's in the same folder that you were working on when you started the script. For example, if both the script and the image are in temp folder, and you started your script like this:
python temp/script.py
The interpreter doesn't realize that blueface.png is also in temp and looks for it in the folder that you were in, in this case the parent of temp
What you should do, is either use absolute paths, or use the __file__ to get the full script address first. For example:
photo = PhotoImage(file='/absolute/path/to/image/blueface.png')
Or using the current script's location to build the image's path:
import os
base_folder = os.path.dirname(__file__)
image_path = os.path.join(base_folder, 'blueface.png')
photo = PhotoImage(file=image_path)
Older versions of tkinter can not handle .png's that well. Try making the file a .gif. Or use the PhotoImage from PIL:
import tkinter as tk
from PIL import Image, ImageTk
root = tk.Tk()
photo = ImageTk.PhotoImage(Image.open('blueface.png'))
label = tk.Label(root, image=photo)
label.pack()
root.mainloop()

Python cx_Freeze name __file__ is not defined

I have a python script which gets an image from the internet, downloads it, sets as desktop background and updates after on minute. The problem is most likely cx_Freeze not including the os module, as the same code with absolute paths works fine. My code also works perfectly, until it goes through freezing. It works before it is frozen when I load throught the console, run from IDLE or double-click on it. Whenever i run the frozen file I get the error (If i use setup.py or cxfreeze file.py:
C:\Python33\Scripts>C:\Python33\Scripts\dist\desktopchanger.exe
Traceback (most recent call last):
File "C:\Python33\lib\site-packages\cx_Freeze\initscripts\Console3.py", line 2
7, in <module>
exec(code, m.__dict__)
File "C:\Python33\desktopchanger.pyw", line 7, in <module>
dir = path.dirname(__file__)
NameError: name '__file__' is not defined
My Code
import pythoncom
from urllib import request
from win32com.shell import shell, shellcon
from time import sleep
from os import path
dir = path.dirname(__file__) #get dierctory script is in
startpath = str(path.join(dir+'/bg/bg.jpg')) #add /bg/bg.jpg to path of script
pathtoimg=[]
for char in startpath:
if char != "/":
pathtoimg.append(char) #replace / with \, necessary for setting bg
else:
pathtoimg.append("\\")
newpath = "".join(pathtoimg)
def get_image():
f = open(newpath, 'wb') #open .....\bg\bg.jpg
f.write(request.urlopen('http://blablabl.com/totale.jpg? i=0.387725243344903').read()) #get image from web and write over previous file
f.close()
while 1:
get_image()
#sets background below
iad = pythoncom.CoCreateInstance(shell.CLSID_ActiveDesktop, None,
pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IActiveDesktop)
iad.SetWallpaper(newpath, 0)
iad.ApplyChanges(shellcon.AD_APPLY_ALL)
sleep(60)
setup.py
from cx_Freeze import setup, Executable
exe=Executable(
script="desktop_changer_with_url2.py",
base="Win32Gui",
icon="icon.ico"
)
includes = ["os","urllib","time","pythoncom","win32com.shell"]
setup(
name = "Heindl Webcam als Desktop" ,
version = "1",
description = "eowjbadpoaäbaaplabipösdbjosdobsaboösac bjcaähpdaöbökabidsidsöds.",
executables = [exe],
)
Source:
http://cx-freeze.readthedocs.org/en/latest/faq.html
Your old line:
dir = path.dirname(__file__)
Substitute this with the following lines to run your script both frozen or unfrozen:
if getattr(sys, 'frozen', False):
# frozen
dir_ = os.path.dirname(sys.executable)
else:
# unfrozen
dir_ = os.path.dirname(os.path.realpath(__file__))
Tested with python 3.3.4. on win32
upd.: changed in accordance with the comment

Categories