How to execute Python script through excel VBA - python

I am trying to run a Python Script through Excel VBA
I have tried the following code, but nothing happened:
Here is the VBA code:
RetVal = Shell("C:\Program Files\Python37\python.exe C:\Users\kailung\Desktop\kai\VBA\june_Longchen\test\VBA.py")
My python script is just renaming files within a folder (I've tested it in Python IDLE, it is fine):
import os, sys
dir_path = os.path.dirname(os.path.realpath(__file__))
# Open a file
dirs = os.listdir(dir_path)
i=1
# This would print all the files and directories
for file in dirs:
if file!='VBA.xlsm' and file!='VBA.py' and file!='~$VBA.xlsm':
print(file) #print all the files
i=str(i) #change to string for file name
i=i + '.xls' #add extension
os.rename(file,i) #rename the file
size=len(i)
i=i[0:size-4] #remove the extension
i=int(i) #change back to numerical
i=i+1 #new numerical name

Convert your .py file to .exe file using pyinstaller and run the .exe program directly from VBA code.
How to use pyinstaller?

Related

No such file or directory but all files in the same folder

I'm getting a
No such file or directory: 'SnP1000_TICKR.csv' error but all my files are in the following folder:
and I'm calling the file here
which is running on this piece of code:
def finVizEngine(input,output):
import chromedriver_autoinstaller
chromedriver_autoinstaller.install() # Check if the current version of chromedriver exists
# and if it doesn't exist, download it automatically,
# then add chromedriver to path
driver = webdriver.Chrome()
ipo_df = pd.DataFrame({})
openFinViz()
with open(input, 'r') as IPO_List:
csv_reader = reader(IPO_List)
This was running before, but then I uploaded files to Github and started running the files from vscode instead of pycharm and started to get a load of errors, but honestly don't understand what is wrong. Any help would be amazing,
Best Joao
First check in which folder it runs code
import os
print( os.getcwd() )
cwd means Current Working Directory.
If it runs in different folder then you have script then it also search csv in different folder.
The simplest method is to use "/full/path/to/SnP1000_TICKR.csv".
But more useful method is to get path to folder with script - like this
BASE = os.path.abspath(os.path.dirname(__file__))
and use it to create full path to file csv
input_full_path = os.path.join(BASE, "SnP1000_TICKR.csv")
output_full_path = os.path.join(BASE, "SnP1000_DATA.csv")
finVizEngine(input_full_path, output_full_path)
BTW:
If you will keep csv in subfolder data then you will need
input_full_path = os.path.join(BASE, "data", SnP1000_TICKR.csv")

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])

Python executable running files with associated extension

I have compiled my python program with cx_Freeze with the lines
import sys
print(sys.argv[0])
to get the name of the extension file that runs my application.
I want to be able to double click on a file named Foo.bas and then my compiled executable starts and it can open the file and read its contents. So I want to get the extension path and file name and read its contents like this
with open(file, "r") as f:
data = f.read()
# do things with contents
where file would be the extension path and name
So how would I do that?
sys.argv[0] gives you the first entry of the command used to run your script, which is the script name itself. If you double-click on a file whose extension is associated with your script or frozen application, the name of this file becomes the second argument of the command, which is available through sys.argv[1]. See for example sys.argv[1] meaning in script.
So try with the following script:
import os
import sys
if len(sys.argv) > 1:
filename = sys.argv[1]
print('Trying with', filename)
if os.path.isfile(filename):
with open(filename, 'r') as f:
data = f.read()
# do things with contents
else:
print('No arguments provided.')
input('Press Enter to end')
This works both as unfrozen script and as executable frozen with cx_Freeze. On Windows you can drag and drop your Foo.bas file onto the icon of your script or executable, or right-click on Foo.bas, chose Open with and select your script or executable as application.

Python: Looping through files in a different directory and scanning data

I am having a hard time looping through files in a directory that is different from the directory where the script was written. I also ideally would want my script through go to through all files that start with sasa. There are a couple of files in the folder such as sasa.1, sasa.2 etc... as well as other files such as doc1.pdf, doc2.pdf
I use Python Version 2.7 with windows Powershell
Locations of Everything
1) Python Script Location ex: C:Users\user\python_project
2) Main_Directory ex: C:Users\user\Desktop\Data
3) Current_Working_Directory ex: C:Users\user\python_project
Main directory contains 100 folders (folder A, B, C, D etc..)
Each of these folders contains many files including the sasa files of interest.
Attempts at running script
For 1 file the following works:
Script is run the following way: python script1.py
file_path = 'C:Users\user\Desktop\Data\A\sasa.1
def writing_function(file_path):
with open(file_path) as file_object:
lines = file_object.readlines()
for line in lines:
print(lines)
writing_function(file_path)
However, the following does not work
Script is run the following way: python script1.py A sasa.1
import os
import sys
from os.path import join
dr = sys.argv[1]
file_name = sys.argv[2]
file_path = 'C:Users\user\Desktop\Data'
new_file_path = os.path.join(file_path, dr)
new_file_path2 = os.path.join(new_file_path, file_name)
def writing_function(paths):
with open(paths) as file_object:
lines = file_object.readlines()
for line in lines:
print(line)
writing_function(new_file_path2)
I get the following error:
with open(paths) as file_object:
IO Error: [Errno 2] No such file or directory:
'C:Users\\user\\Desktop\\A\\sasa.1'
Please note right now I am just working on one file, I want to be able to loop through all of the sasa files in the folder.
It can be something in the line of:
import os
from os.path import join
def function_exec(file):
code to execute on each file
for root, dirs, files in os.walk('path/to/your/files'): # from your argv[1]
for f in files:
filename = join(root, f)
function_exec(filename)
Avoid using the variable dir. it is a python keyword. Try print(dir(os))
dir_ = argv[1] # is preferable
No one mentioned glob so far, so:
https://docs.python.org/3/library/glob.html
I think you can solve your problem using its ** magic:
If recursive is true, the pattern “**” will match any files and zero
or more directories and subdirectories. If the pattern is followed by
an os.sep, only directories and subdirectories match.
Also note you can change directory location using
os.chdir(path)

glob.iglob Remove path from filename

I am trying to get the most recent file added to a directory using python 2.7 os and glob modules.
import os
import glob
path = "files/"
newestFile = max(glob.iglob(path + '*.txt'), key=os.path.getctime)
print newestFile
When I print the newestFile variable I get the path included i.e.
files\file.txt
I just want the filename but my .txt file and .py script are not in the same directory. The text file is one directory down under the files directory. How do I refer to the directory and get the newest .txt file added to that directory.
You can use os.path.basename to just get the filename:
newestFile = os.path.basename(max(glob.iglob(path + '*.txt'), key=os.path.getctime))
os.path.getctime is going to need the full path so one way or another you would have to use the full path.

Categories