Running a Python script from Access VBA - python

I'm having trouble finding many resources, but I'm trying to get vba to run a python script
Const pyScript = "C:\Test\Weekend_Exceptions\Weekend_Exception.py"
Dim dblRetVal As Double
dblRetVal = Shell("C:\Python34\python.exe " & pyScript)
I know my python script works and should output a file, but its not. Additionally the vba is not tirggering a debug flag so I'm not sure where I am wrong. Any advice would be appreciated.

You don't give too much details so i'll make some assumptions
Probably your python script read some local file this will cause your script to raise a FileNotFoundError and exit
To make the test copy the entire arg string to Shell, in your case "C:\Python34\python.exe C:\Test\Weekend_Exceptions\Weekend_Exception.py", open a cmd with Win+r , paste and run, not being in the right directory should raise the same error.
If this is the problem, make a makestuff.bat file with the code
#echo off
#cd C:\Test\Weekend_Exceptions\
#C:\Python34\python.exe Weekend_Exception.py
#echo on
Then call the bat from Shell("C:\Place\of\your\bat\makestuff.bat")
Return with more details to we work on a solution

Here is how I did:
I created a File1.bat to open the File2.py. The code in File1.bat is:
#echo off
#h:
#cd H:\Path\Cronus\Rangers
#C:\Python3\python.exe File2.py
#echo on
Note that File2.py is inside H:\Path\Cronus\Rangers folder. That's why we need to open it before.
I created a function in VBA to open a .bat file:
Option Compare Database
Function MacroPythonSARH()
On Error GoTo MacroPythonSARH_Err
Call Shell("H:\Path\Cronus\Rangers\File1.bat", 1)
MacroPythonSARH_Exit:
Exit Function
MacroPythonSARH_Err:
MsgBox Error$
Resume MacroPythonSARH_Exit
End Function

Related

how to pass an argument from python code to bash script?

I have a python code in which at the beginning it takes a string variable let say "element_name" from user and build some sub-folders based on this string and also some output files created by this code move to those folders.
On the other hand, I have a bash script in which some codes should be running in the sub-folders made in python code.
Any help how to introduce those folders in bash? How to pass the "element_name" from python to bash?
In python code "a.py" I tried
first = subprocess.Popen(['/bin/echo', element_name], stdout=subprocess.PIPE)
second = subprocess.Popen(['bash', 'path/to/script', '--args'], stdin=first.stdout)
and then in bash
source a.py
echo $element_name
but it doesn't work.
It's not clear from your question what is in your scripts, but I guess
subprocess.run(['/bin/bash', 'path/to/script', '--args', element_name])
is doing what you intend to do, passing the value of element_name to script as an argument.
I found a way. What I did is to pass the argument in a bash file and import this bash file as a source to my main bash file. Now everything works well.

Running .vbs scipt inside Python doesn't do anything

Idea
Basically, what my script does is checking C:/SOURCE for .txt files and add a timestamp to it. To replicate it you can basically make that folder and put some txt files in there. Then, it's supposed to run a .vbs file, which then runs a .bat files with some rclone commands which don't matter here. I did it like this because there wont be a CMD window opening when running the rclone command through the .vbs file.
Python code
import time, os, subprocess
while True:
print("Beginning checkup")
print("=================")
timestamp = time.strftime('%d_%m_%H_%M') # only underscores: no naming issues
the_dir = "C:/SOURCE"
for fname in os.listdir(the_dir):
if fname.lower().endswith(".txt"):
print("found " + fname)
time.sleep(0.1)
new_name = "{}-{}.txt".format(os.path.splitext(fname)[0], timestamp)
os.rename(os.path.join(the_dir, fname), os.path.join(the_dir, new_name))
time.sleep(0.5)
else:
subprocess.call(['cscript.exe', "copy.vbs"])
time.sleep(60)
VBScript code
Set WshShell = CreateObject("WScript.Shell" )
WshShell.Run Chr(34) & "copy.bat" & Chr(34), 0
Set WshShell = Nothing
The only important part for the Python script is below the very last else, where the subprocess.call() is supposed to run the .vbs file. What happens when running the script is it shows the first two lines that always come up when running CMD, but then nothing.
How could I fix that? I tried:
subprocess.call("cscript copy.vbs")
subprocess.call("cmd /c copy.vbs")
both with the same outcome, it doesn't do anything.
Anyone have an idea?
Why are you invoking a VBScript to invoke a batch script from Python? You should be able to simple run whatever the batch script is doing directly from your Python code. But even if you wanted to keep the batch script, something like this should do just fine without VBScript as an intermediary.
subprocess.call(['cmd', '/c', 'copy.bat'])
You may want to give the full path of the batch file, though, to avoid issues like the working directory not being what you think it is.
If your batch script resides in the same directory as the Python script, you can build the path with something like this:
import os
import subprocess
scriptdir = os.path.dirname(__file__)
batchfile = os.path.join(scriptdir, 'copy.bat')
subprocess.call(['cmd', '/c', os.path.realpath(batchfile)])
It seems there is no such an operation that could not be done using plain Python. Scan a directory, copy a file -- Python has it all in the standard library. See os.path and shutil modules.
Adding VB scripts and launching subprocesses make your code complex and difficult to debug.

Why batch file is not working if executed from python script or if executed by double clicking it?

I have a batch script which is generating a configuration file after its execution, the configuration file generated has some data inside it. When i execute it from command prompt as follows i get the desired output :
C:/> start.bat
but if i try to execute from python script as follows or even if i double click and execute it i do get the configuration file but it does not contain any required data it just have '0' inside it:
import subprocess as sp
p= sp.Popen("C:/pathtobatch/start.bat",stdin=sp.PIPE, stdout = sp.PIPE, stderr=sp.PIPE)
Inside the batch script(start.bat) i am actually executing a python script and retrieving its data to a configuration file as follows:
python C:\inetpub\ftproot\sample.py > log.txt
set myvar =< log.txt
del log.txt
echo %errorlevel% %myvar% >C:\inetpub\ftproot\config.txt
I need to execute the batch(start.bat) from the python script and generate the config.txt file having the required data. So, how shall i do that.
Why the start.bat is not working fine if i double click it and why is it working fine if i am executing it from command prompt.
Is it possible that you get '0' as it is the value of %errorlevel%?
I found two issues in your case:
1) batch file - can you please update your batch file to something like:
for /f %%i in ('python C:\inetpub\ftproot\sample.py') do set myvar=%%i
echo %errorlevel% %myvar% >C:\inetpub\ftproot\config.txt
Credit for the idea of setting variable: https://stackoverflow.com/a/2340018/5088142
2) python script - can you please update your python script to be:
import os
os.system("C:/pathtobatch/start.bat")

Calling an executable in VBA using command prompt with dynamic file path naming

I currently have a macro that calls a python executable. However when I run the macro it doesnt seem to run. I know it's not a problem with the executable because when I double click on it it runs fine. I also don't think its a problem with the filepath.
What other possible problems could there be.
I've been working on this for the past 8 hours.
Relevant Code:
folderPath = Application.ActiveWorkbook.Path
Dim stAppName As String
stAppName = folderPath & "\dist\MCM_MAT2.exe"
Call Shell(stAppName, 1)
It sounds like your working directory needs to be set before you call the shell.
' Go to the desired startup directory.
ChDir folderPath

Why are os.system and subprocess.call spawning so many processes?

import os
import subprocess
import sys
import re
## fname_ext=sys.argv[1]
fname_ext=r"C:\mine\.cs\test.cs"
exe=os.path.splitext(fname_ext)[0]+".exe" # Executable
fdir=os.path.split(fname_ext)[0]
fcontent=open(fname_ext).read()
p_using=re.compile("\s*using\s+((\w+[.]*)+)")
p_namespace=re.compile("\s*namespace\s+(\w+)")
usings=p_using.findall(fcontent)
usings=[x[0] for x in usings]
references=[]
for i in os.listdir(fdir):
path=fdir+"\\"+i
try:
if os.path.isdir(path) or (not path.endswith('cs')):continue
with open(path) as fp:
content=fp.read()
namespaces=p_namespace.findall(content)
for n in namespaces:
if n in usings and 'System' not in n:
references+=[path]
except:
pass
command="csc /nologo "+" ".join(references)+" "+fname_ext
## command=" ".join(references)
#~ ---------------------------------------------------------
# Build:
option=1
if option==0:
# using os.system
print ">>",command
if os.system(command)==0:
os.system(exe)
else:
#~ Using subprocess module
## print type(references)
command=['csc']
## print command,references
command.extend(["/nologo","/out:"+exe])
command.extend(references)
command.append(fname_ext)
## print command
if subprocess.call(command,shell=True)==0:
## print "running %s"%exe
subprocess.call([exe],shell=True)
else:
pass
## print "Failed to run"
#~ ---------------------------------------------------------
I have this code above that is supposed to run a Csharp program from SciTE. It searches
every .cs file in the directory and finds the file with the namespace that the current
file has included. The command to run the file in SciTE is:
command.go.*.cs=python C:\mine\.py\csc.py $(FilePath)
command.go.subsystem.*.cs=0
That program logic part is okay.
The issue is that when hit F5 with sample Csharp code like this:
using System;
using System.Collections;
using MyNamespace;
class Test{
public static void Main(String[] args){
MyObject inst=new MyObject();
MyObject.self_destruct(inst);
}
}
it runs ok. But when I uncomment the second fname_ext and comment the first one
and run the csc.py file, a window opens and keeps running, printing command(this happens
using the os.system option). When you use the subprocess.call option, the same thing
happens but this time only when shell=True. It ran for only 15 seconds and there were 800+
cmd.exe and python.exe processes.I had to wait almost 5 minutes after killing cmd.exe
for the mouse to start responding and 2 minutes more for desktop peek to work.
When shell=False, it runs ok, the same way as when you hit the F5 key from the file.
What is happening here?
What is shell=True doing that makes it behave that way?
The problem is that your sys.argv looks something like this:
['python', r'C:\mine\.py\csc.py', 'whatever.cs']
So, with the fname_ext line uncommented, you set fname_ext to r'C:\mine\.py\csc.py'. Which means your script ends up just running itself—which again runs itself, etc., as fast as possible until your system chokes.
The reason it doesn't happen with shell=False is that you can't actually exec a Python script. Ultimately you end up calling CreateProcess with your script, which tries to interpret it as a .exe file, fails, and returns an error. But with shell=True, you pass your script to cmd.exe to run as a program, and it does the same thing an interactive prompt or Explorer would do: finds the right mapping to execute .py files and uses it. (And os.system does effectively the same thing as shell=True, but with a couple extra layers tossed in for good measure.)
Okay, I'll take a stab at this. If I understand the situation, this script is called csc.py and you want to call the csc c# compiler. When you run csc /nologo (etc...) through cmd.exe, it starts looking for something called 'csc' with a known extension. It finds csc.py in the current directory and since .py is a registered extension, that's what gets executed.
The solution is to rename your python file or call out 'csc.exe' explicitly.

Categories

Resources