How to package xlwings codes with pyinstaller? - python

I just want to keep excel as a UI and allow user call python instead of VBA from the spreadsheet. Also the python files need to be packaged into one .exe file.
Without any tutorials found, this is what i tried:
test.py:
from xlwings import Book
import xlwings as xw
def test():
sh = xw.Book.caller().sheets['a']
sh.range('A1').value = 'hello'
if __name__ == '__main__':
test()
Then I use pyinstaller:
pyinstaller test.py -F
I copied the spreadsheet test.xlsm to the same directory as the test.exe
The vba codes from test.xlsm:
Sub callpython()
RunFrozenPython ("test.exe")
End Sub
Eventually i got: ---------------------------
Error
'test.exe' is not recognized as an internal or external command, operable program or batch file.
What's more annoying is that if I import pandas in python, pyinstaller won't even compiler due to "maximum recursion depth exceeded".
Can anyone provide an example of how to make these two things work together? I don't even have to use xlwings or pyinstaller, as long as it can achieve making python codes into one executable file and run it from Excel.
=======================
Update:
I finally fixed them by:
uninstall pyinstaller and replace it with pyinstaller development version (v3.3)
manually modify xlwings.bas code in VBA. It seems that PYTHON_FROZEN searches executable with a hard coded path:
PYTHON_FROZEN = ThisWorkbook.Path & "\build\exe.win32-2.7
Hope xlwings team can replace the logic of finding the .exe file with a more robust one.

Related

Python Pyinstaller build fails using win32com package [duplicate]

I am trying to convert my .py file to an .exe file and I have tried all methods (auto-py-to-exe, pyinstaller, cz_freeze) and it does create the exe file but it always gives an error or the window opens and closes as soon as I double click the file.
It is a SpeechRecognition AI project coded in python. And it works just fine in the IDLE but once I create the .exe and try to run it the window pops up and shut down immediately after. (I use the cx_freeze and setup.py method for this)
If I try to convert .py to .exe using pyinstaller it gives me several different kinds of error messages.
As a .py file it works just fine but it doesn't work as an exe.
This is the error I get when using pyinstaller or auto-py-to-exe: Failed to execute script 'pyi_rth_win32comgenpy' due to unhandled exception: Module 'pythoncom' isn't in frozen sys.path
Module 'pythoncom' isn't in frozen sys.path
I tried several things but nothing seems to work. I was previously using Python3.10 so I uninstalled it and downgraded to Python3.8 and reinstalled all the modules so technically it should work. I tried to create .exe files of another project and it worked just fine.
Another issue I come across is ModuleNotFoundError: No module named 'pyttsx3.drivers' I compiled the .exe using cx_freeze and it did create an .exe but it gives me this error.
Could someone please help me out with this?
(PS: This is the list of imports I am using for this project:
screenshot of all imports
import speech_recognition as sr
import pyttsx3
import datetime
import wikipedia
import wikipediaapi
import webbrowser
import os
import time
import subprocess
import wolframalpha
import json
import requests
from newsapi import NewsApiClient)
I just solved this for my project, which is using none of the direct imports your project is, but it appears the same low level library is causing an issue.
In my case, the single import is:
from pywinauto.application import Application
The solution is to tell PyInstaller to bundle the missing .DLL, which in this case is pythoncomxx.dll where xx is your python version. 39 in my case.
Here is the call that eventually worked for me.
pyinstaller --onefile --add-binary ".venv/Lib/site-packages/pywin32_system32/pythoncom39.dll;." autoTest.py
More generally: pyinstaller --onefile --add-binary "[path to dll];." file.py
Note, I'm on Windows. If you are on mac/linux, the ; character in the --add-binary argument would be :. See note in the documentation here
Discussion
This clicked for me when I used ProcMon to profile the file access of my initial version that was failing. It was looking for this .DLL in a bunch of different folders, then quitting.
The answers to this question were helpful. But I didn't want to settle for copying the DLL to output manually. And consequently, having to use a directory output versus a single executable file.
Answers on this question also gave the hint about using the --add-binary flag, but ultimately I had to provide the specific path to the missing DLL instead of just referencing by name as these answers showed. It probably works to specify the DLL by name if it is accessible on your PATH.
How to locate this DLL in the first place? Do a search on your site-packages folder.

Python EXE file creation

I have this code which i need to create it as a python exe file, where in user has to click the workflow done.
My Sample Project
import os
import pandas as pd
import sys
import csv
path = os.getcwd()
v1 = pd.read_csv(r"path\V1.tsv", delimiter = '\t')
v1.to_csv(r"path\v2.csv", index=False)
I used Pyinstaller to create a .exe file but it didnt help me achieve what I want. Can some one suggest me?
Depending on what disappointed you about PyInstaller, (speed? size? too many files in directory?), you may either want to try:
PyInstaller's --onefile flag, which will compile everything into one .exe file but will take forever to run
cx_Freeze. This can generate .exe files like PyInstaller, though performance won't be much better. What I find most useful is to compile the files into an installer by calling py setup.py bdist_msi (Windows) or py setup.py bdist_dmg (Linux). People can use the installer to add the .exe to their machines. Installer-created .exe files will run very quickly.
Have your tried using the --onefile flag to specify that you only want 1 exe file to be created for that script.
For example use the cmd: pyinstaller --onefile file_name.py
If this does not help can you specify the issue that is occurring.

Generate an executable file in python

I have proceeded to generate an executable file using pyinstaller, once it has finished the corresponding files are generated, then:
In my windows console I apply this command: pyinstaller --onefile program_with_excel.py
I use this command to compile everything into a single.exe file, so that I can use it on another pc.
Once this is done, I open my executable located in the 'dist' folder and when doing so I have detected several problems:
My executable file 'program_with_excel.exe' is too heavy for what I am trying to do, a few simple calculations. (317,948 KB)
When I open it, the following error appears and then my application closes:
I suspect it is because to run my program I use an excel sheet using 'pandas' where I place data and they are calculated with my program. How could this be resolved?
What would be the solution for this problem and be able to work with my executable?
I also attach a rar with my program and my excel sheet: RAR_EXAMPLE
Best regards.
The exe needs to have access to all its dependencies, just like the python script. If you moved it then it may not have that access. It appears from the error that this is the problem. A common way these exe files are transported is by putting it and each dependency in a zipped folder and using NSIS.

pyinstaller exe without any dependencies?

So I'm using pyinstaller with python27, and my exe works great so long as it's in the same directory as the build folder. I need it to be a completely standalone exe, without any dependencies, is there a way to bundle the important things from the build folder into one file? Neither -F nor --onefile seems to do this.
Edit: as I explain in my answer below, I thought pyinstaller was the problem because the exe would only run in the dist folder, so I assumed it had dependencies there, but in reality, it was running and then instantly crashing due to a bug that only triggered when the exe was on the desktop.
I figured out that the reason it wasn't working had nothing to do with pyinstaller or dlls. The exe was opening, and and trying to input powershell commands via python like it was supposed to. Unfortunately I had a line of code that said this:
subprocess.check_output('schtasks /create /sc minute /mo ' + str(time) + ' /tn "test_process_to_run_every_'+str(time)+'_min" /tr //'+sys.argv[0],shell=True)
#set this exe to run every X minutes in windows scheduled tasks
the problem was that sys.argv[0] changed when I put the exe on the desktop, and ended up being a path that looked like C://Users/John Smith/Desktop. The space in between John and Smith made powershell mad and crashed the program, so I escaped it using this line of code:
path = sys.argv[0].replace(" ","^")
and then I replaced sys.argv[0] with my new path variable. Hope this helps anyone in the future trying to do the same thing.
after pyinstaller has converted your script into .exe, than you need to add the executable to path, otherwise you have to open the command line in the directory that the file is in. pyinstaller just puts your script and py interpretor into a single file. same goes for linux.
for dependency side, look here.
there are other options you can try to bbFreeze, py2exe, cx_Freeze
to use pyinstaller in a simple way:
pyinstaller --onefile your_file.py
now you should see couple of files build, dist(exe in here).
NOTE: that --onefile flag doesn't necessarily get rid of the need for it to have link with certain libraries, it will still need those in order to run.
prepare for distribution, first need to get a spec file:
to get a spec file:
pyinstaller --noconsole your_file.py
than you can get the exe file for distribution like so:
pyinstaller your_file.spec
for more info and tutorial look here
see if nuitka works for you, it might sound scary but it is not. it compiles your code to executable binary format. Be aware that under the hood first it converts to c++ API calls.
if you dont like that for closed source program use Cython, and for no dependency use py2exe

PyInstaller: using data files and subprocess

I have successfully bundled several of my python scripts into exe files using pyinstaller. However, I have hit a problem with a different python script that uses local data files. Using this question and answer PyInstaller 2.0 bundle file as --onefile I have got the script using my local files however I get an error.
I have a master python script called "translate.py" in it I have several subprocesses that call a different python script call "loader.py" which takes a variety of arguments. So my normal subprocess looks like this
python.exe loader.py loader.config src_dir=data out_dir=sql tmp_dir=temp
In my pyinstaller version I have used the answer from the above question to have the following subprocess call
python.exe C:\Users\AppData\Local\Temp\_MEI70922\loader.py C:\Users\AppData\Local\Temp\_MEI70922\loader.config src_dir=dat
a out_dir=sql tmp_dir=temp
However this fails to run the subprocess and I get the following error
no module named site
So I am wondering if pyinstaller is not including all the modules I may need?
I have tweaked the spec file to analyse all the python scripts like this
a = Analysis(['c:\\temp\\translate.py','c:\\temp\\loader.py','c:\\temp\\prep.py','c:\\temp\\prep2.py'],
pathex=['C:\\Temp\\pyinstaller-2.0\\pyinstaller-2.0'],
hiddenimports=[],
hookspath=None)
But again I get the no module named site.
I know my code could be better but I am stuck as someone else wrote the loader.py and I wrote the translate.py and now I need to bundle it all into a simple exe file.
thanks for anyone's help

Categories