Run Python script when opened via VBA or .bat - python

I am trying to open a py script via VBA Excel.
The script is to interact with engineering software which undertakes finite elements analysis. The script can run directly from the py editor.
They prepared a Python library I have to import at the beginning of the script which also requires some password and log in credentials for the script to interact with that specific software.
I can open simple py scripts (such as the classic Hello World) via the Shell in VBA.
The script that I have prepared is more complex. When opening my script via VBA using the shell it flashes the cmd window and nothing happens.
Below is the subroutine I have coded in VBA to open the Python interpreter and Python script, for illustration: it returns error message 2.
Sub RunPythonScript()
Dim wsh As Object
Dim PythonExe, PythoScript As String
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
Dim errorCode As Long
Dim pth As String
PythonExe = """C:\ProgramData\Bentley\Geotechnical\PLAXIS 2D CONNECT Edition V20\python\python.exe"""
PythoScript = """C:\Users\ukjfv001\Desktop\MyPython\MyAnalysis.py"""
pth = PythonExe & PythoScript
Set wsh = VBA.CreateObject("WScript.Shell")
errorCode = wsh.Run(pth, windowStyle, waitOnReturn)
If errorCode = 0 Then
MsgBox "Done! No error to report."
Else
MsgBox "Program exited with error code " & errorCode & "."
End If
End Sub
There is a lot of information online on how to run Python scripts.
In this forum: How to call python script on excel vba?. I have also created a bat file which I could open via VBA but, got the following error message:
C:\Users\ukjfv001\Desktop\MyPython>"C:\Users\ukjfv001\Anaconda3\python.exe" ""C:\Users\ukjfv001\Desktop\MyPython\MyAnalysis.py""
start
Traceback (most recent call last):
File "C:\Users\ukjfv001\Desktop\MyPython\MyAnalysis.py", line 16, in
from plxscripting.easy import * #call Plaxis scritping library
ModuleNotFoundError: No module named 'plxscripting'
Below is a bit of the Python code which I have to place at the top of the script in the SciTE editor (which comes with the engineering software).
From what I can see in the error message (above) and the bit of code below from plxscripting.easy import there is something I am not doing.
I am new to Python so usually I need practical examples to understand what is to be done.
from plxscripting.easy import * #callS engineering scritping library
inputport = 8888888
plaxispw = some_password
plaxis_path = C:\Users\ukjfv001\... #to here the software is intalled
plaxis_input = Plaxis.exe #software executable
if not process_exists(plaxis_input): #checkS if software is alreayd running
# first launch software
args = [os.path.join(plaxis_path, plaxis_input),"--AppServerPort={}".format(inputport),"--AppServerPassWord={}".format(plaxispw)]
inputprocess = subprocess.Popen(args)
# Initialize new_server with waiting time
s_i, g_i = new_server('localhost', inputport, password=plaxispw, timeout=10.0)
s_i.new()#starts a new Project
#after this point is where I have my Python script...```

I had a similar problem where I got an error running a python script from a scheduler (via running a file) even though it ran in my IDE. I also had to run it from a batch file to see the error, otherwise nothing happened. The issue was that python could not find the path to my custom libraries (which may be your issue, since the error is a library import). I think this can happen if you set your Python Path to custom libraries in your IDE and the environmental variables/ path are not also set (that is what you need to synchronize).
In Spyder, you just go to Tools: Python Path Manager in the menu and hit synchronize. I don't know what IDE you are using, but probably it also has a Python Path Manager if it isn't Spyder.

Related

Python logging doesn't work when script is called from another program

I have a python script that I use with LibreOffice Calc to do some more advanced macros. I need to debug this script and I'm trying to use logging for this. Logging works fine when the script is called from the command line, but it doesn't work at all when the script is called by LibreOffice.
Here is my logging test code:
import logging
logging.basicConfig(filename='test.log', level=logging.INFO)
logging.warning('test')
As requested, here is the LibreOffice Basic script that calls the Python script (this was mostly just a copy/paste from a guide on how to call Python scripts from LO):
function cev(a as String) as double
Dim scriptPro As Object, myScript As Object
Dim a1(1), b1(0), c1(0) as variant
a1(0) = ThisComponent
a1(1) = a
scriptPro = ThisComponent.getScriptProvider()
myScript = scriptPro.getScript( _
"vnd.sun.star.script:Cell_Functions.py$calcEffectValue?language=Python&location=user")
cev = myScript.invoke(a1, b1, c1)
end function
The basic script is called on a single cell using CEV(cellAddress), which passes the contents of the cell through to the Python script as a string.
Well, I updated to LibreOffice 7 and this started working. The Python version in LO 7 is 3.8 instead of 3.5, so maybe that made the difference.
Maybe it is working but you just don't know where test.log file is getting placed when it runs from LibreOffice. Try providing an absolute file path for test.log, like let's say C:/test.log.

Python script called from VBA called from Python is not working

I maintain an Excel with macro's that download some data from the internet. The downloading is done within Python (I will call this Python A), stored intermediately, and picked up by the Excel again. This Python flow is triggered by a macro within that Excel. Because I have to do this at specific times I wanted to automatize this by using another Python scheduler. The scheduler opens a
Nothing fancy, did that before, at least so I thought. The problem I am currently facing is that Python A is not running correctly when triggered from Python B. The Excel macro is running fine. I know that because some files are being exported, which is also done within a macro.
What I have tried so far:
Running the macro's manually is all fine
Setting all paths absolute, but that was already the case, so nothing to be improved there.
Calling the Python B flow from a bat file. This does work (?!)
Calling the bat from the scheduled flow does not work
Code in VBA:
cmdLine = "python ""path_with_spaces_to_file"" "
lngResult = ShellAndWait(cmdLine, 0, vbNormalFocus, AbandonWait)
Code in Python B to call Macro:
import win32com.client
def func():
filename_excel = r"filename_to_excel_with_spaces.xlsm"
xl = win32com.client.DispatchEx('Excel.Application')
xl.Visible = False
xl.Workbooks.Open(Filename=filename_excel, ReadOnly=1)
sheet = xl.ActiveWorkbook.Sheets("Sheetname")
xl.Application.Run("Macroname")
xl.DisplayAlerts = False
xl.Application.Quit()
How I call this function from the scheduler:
subprocess.run(["python3_location.bat", "-c", 'from python_B_file import func; func()'],
stdout=subprocess.PIPE,
cwd=r"path_to_python_B_file",
universal_newlines=True,
timeout=60)
I see an extra cmd window popping up, but there is no new file downloaded. I cannot see an error message
Trying out different things, I found out that in the normal namespace the command python refers to the system defaults Python 2.7 installation, while the Python B is 3.7. Python A code was not Python 3 compatible (something with urllib, easily solved to something working in both Python versions). Calling the Excel macro from Python B changed the namespace somehow, and the ShellAndWait command referred to Python 3.7.

Trying to call a Python script from vba, but it is returning a number series instead of the desired output

I have been trying to call a Python script from vba, but it is returning a number series instead of the desired output.
Here is the python script:
def hello():
df = pd.DataFrame(data=[2,2])
df.to_excel("hello_output.xlsx")
return "Hello"
hello()
I have tried to implement the vba scripts from the following stackoverflow posts and YT videos:
How to call python script on excel vba?
Run and execute a python script from VBA
https://www.youtube.com/watch?v=rlHcrAb2_fs&t=1s
https://www.youtube.com/watch?v=Z4SC53VZh-w
Here is my VBA script(I have tried with both one and two bakcslashes):
Sub RunPythonScript()
PythonExe = """C:\\Users\\username\\anaconda3\\python.exe"""
PythonScript = """C:\\Users\\username\\all scripts\\hello.py"""
retval = Shell(PythonExe & " " & PythonScript)
Worksheets("Sheet1").Range("D15").Value = retval
MsgBox (retval)
End Sub()
The file "hello_output.xlsx" is not created.
The MsgBox outputs a number series(probably some kind of process ID) instead of the string "Hello".
For your information I do have two python interpreters installed, and I have tried providing the file path to both of them. The anaconda python interpreter has the following error message when opening it manually:
"This Python interpreter is in a conda environment, but the environment has
not been activated. Libraries may fail to load. To activate this environment
please see https://conda.io/activation"
I have written my python code in Spyder.
Any suggestions on how to fix this would be highly appreciated.

Calling Python script in excel as executable

I am currently developing a tool for a client that interfaces with both python 2.7 and excel 2013 and as a result running into a problem.
As background, I have a python code I want to run as a executable. The client doesn't have python on their computers so it's vital that the exe runs without .py. I've converted the script from a .py to a .exe with py2exe. Then I am trying to call that .exe with VBA. When the macro runs it looks like it pulls up the command prompt for a second but it doesn't run the .exe. When I go into the directory and double click the .exe however, it runs fine and outputs what I want it to.
Below is my code in VBA:
Dim folderPath As String
folderPath = Application.ActiveWorkbook.Path
ChDir folderPath
Dim stAppName As String
stAppName = folderPath & "\dist\MAT.exe"
Call Shell(stAppName, 1)
Not sure if my Shell needs any other inputs
Any help would be appreciated!
this is an indirect answer more to help you figure out what might be wrong
in your main file put your program in a main function (you dont have to call it main... you can call it whatever)
def main():
#do whatever
then when you run it if its main do this
if __name__ == "__main__":
try:
main()
finally:
raw_input("Hit enter To Close...")
this will guarantee your window to stay open even if there is an uncaught error

Qualcomm's QPST Automation Server in Python 2.7 using win32com module

Python newbie here. So, please excuse if this has been asked before in a different format.
I am trying to replicate the following perl snippet in Python using the win32com module. This snippet is provided by Qualcomm for easier automation of their tools.
use Win32::OLE;
use Win32::OLE::Variant;
$prod_id = "QPSTAtmnServer.Application"; # AppId for the Automation server.
eval{ $qpst = Win32::OLE->GetActiveObject($prod_id)}; # Attempt to use a running instance.
die "$prod_id not installed" if $#;
unless (defined $qpst) { $qpst = Win32::OLE->new($prod_id, sub {$_[0]->Quit;}) or die "Cannot start $prod_id";} # Start a new instance. Call Quit when $qpst set to undef or script exits.
if (defined $qpst)
{
$port = $qpst->GetPort("COM30001");
}
The block of python code I have till now is as follows:
import win32com.client
import time
import os
cmd = 'cls'
os.system(cmd)
cmd = 'start C:\\LAB\\exe\\pskill.exe QPSTConfig'
os.system(cmd)
cmd = 'start C:\\LAB\\exe\\pskill.exe QPSTServer'
os.system(cmd)
cmd = 'start C:\\LAB\\exe\\pskill.exe AtmnServer'
os.system(cmd)
time.sleep(2)
_path = os.getcwd()
qpst = win32com.client.Dispatch('QPSTAtmnServer.Application')
time.sleep(5)
if (qpst is None):
print('Darn!')
else:
port = qpst.GetPort('30001')
print(port)
and it throws the following error:
Traceback (most recent call last):
File "xxxx.py", line 20, in module
port = qpst.GetPort('30001')
TypeError: 'NoneType' object is not callable
After reading a couple of posts it seems like the method (GetPort) is not registering as a method after all.
Is that correct analysis?
If yes, how do I make Python interpret it as a method?
If not, what is going on here with the error?
Thanks in advance for the help!
It looks like I had to do couple of things to solve the issue.
Use the makepy command on the "AtmnServer" OLE TypeLibrary file to create a *.py file in:
...\Python27\Lib\site-packages\win32com\gen_py\
Add an extra line to actually interpret the required Method as a method (instead of as a property/attribute or something) :
qpst._FlagAsMethod("GetPort")
before the line:
port = qpst.GetPort("COM30001")
Thanks again for offering to help!
Correct, it is saying that GetPort does not exist. Have you checked that the Perl version works? If you don't have Perl, you could try through Excel's VBA (open its VBA console -- you may have to enable it by following the steps here). If you can dispath the QPST from Excel VBA and do the GetPort, then something is very odd.
It could be that QPST COM interface changed since this script was written. You could try
qpst = win32com.client.gencache.EnsureDispatch(
'QPSTAtmnServer.Application')
which will attempt to create the type library for QPST. Sometimes it finds extra objects, but if not at very least you can then browse the QPST COM from python using combrowse.py (which is part of pywin32) and try to find where that function is. Combrowse is a basic COM browser, just run \Lib\site-packages\win32com\client\combrowse.py, if need more powerful the one from visual studio is probably better.

Categories