Technical Articles
How to use SAP GUI Scripting inside Python Programming Language
The programming language Python offers many possibilities. Also it supports with py32win ActiveX automation, and therefore SAP GUI Scripting. The following example shows, how easy it is to take the recorded VBScript code and to use it inside Python.
In the comment lines you see the recorded VBScript code as a direct comparison. Here an example which opens TAC SE16, enters table TADIR and execute the TAC:
#-Begin-----------------------------------------------------------------
#-Includes--------------------------------------------------------------
import sys, win32com.client
#-Sub Main--------------------------------------------------------------
def Main():
try:
SapGuiAuto = win32com.client.GetObject("SAPGUI")
if not type(SapGuiAuto) == win32com.client.CDispatch:
return
application = SapGuiAuto.GetScriptingEngine
if not type(application) == win32com.client.CDispatch:
SapGuiAuto = None
return
connection = application.Children(0)
if not type(connection) == win32com.client.CDispatch:
application = None
SapGuiAuto = None
return
session = connection.Children(1)
if not type(session) == win32com.client.CDispatch:
connection = None
application = None
SapGuiAuto = None
return
#session.findById("wnd[0]").resizeWorkingPane 173, 36, 0
session.findById("wnd[0]").resizeWorkingPane(173, 36, 0)
#session.findById("wnd[0]/tbar[0]/okcd").text = "/nse16"
session.findById("wnd[0]/tbar[0]/okcd").text = "/nse16"
#session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]").sendVKey(0)
#session.findById("wnd[0]/usr/ctxtDATABROWSE-TABLENAME").text = "TADIR"
session.findById("wnd[0]/usr/ctxtDATABROWSE-TABLENAME").text = "TADIR"
#session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]").sendVKey(0)
#session.findById("wnd[0]/tbar[1]/btn[8]").press
session.findById("wnd[0]/tbar[1]/btn[8]").press()
except:
print(sys.exc_info()[0])
finally:
session = None
connection = None
application = None
SapGuiAuto = None
#-Main------------------------------------------------------------------
if __name__ == "__main__":
Main()
#-End-------------------------------------------------------------------
And after all we see that it is very easy to use SAP GUI Scripting inside Python. The recorded VBScript code can use almost always unchanged, sometimes it is necessary to set some brackets.
As IDE I use VS Code with Python extension, here a look at it:
Hi Stefan,
Awesome to see some Python pop up here on the SAP community! Just some suggestions - if you wanted to follow the PEP 8 convention you should keep function names lowercased. You could also simplify your code a bit if you just used "Duck Typing" on the variables you declare, rather than checking of types.
Great stuff though - keep it coming!
Hello William,
thank you very much for your reply and for your interesting suggestions. As you can see I am newbie at Python. I build this bridge in the context of test automation, here in combination with the Robot Framework.
Best regards
Stefan
I’m not familiar with the Robot Framework, but you may find some value in looking at Python’s built-in unittest module which can help consolidate a lot of setup and teardown actions across your test cases. To get you started, I’ve refactored your code above to fit that framework.
Note that this is just taking your code as is. I’m not too familiar with the COM SDK but I think you might need to find an explicit close method to call for your session object rather than just setting it to None as you do above. Also, there could be some opportunity to simplify a lot of your “findById” calls if you create the window object as a variable, and have your calls work relative to that rather than always starting back with the session object as its root.
I’m on a Mac and can’t test any of this, but feel free to ping me back if you have any issues or questions ?
Hi William/Stefan,
I tried to run your code but couldn't make it work. Would you be able to extend your support in fixing this? Please find the below error details(NameError: name 'gui' is not defined) for your reference.
Post that, I made some tweaks in the existing code to make it work but I'm still getting the control id error. I'm using Spyder IDE.
Best
Rohit
======================================================================
ERROR: setUpClass (__main__.SapGuiTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\O59380\lowHangingAutomation\dataTransformation.py", line 13, in setUpClass
cls.sess.findById("wnd[0]").resizeWorkingPane(173, 36, 0)
File "<COMObject <unknown>>", line 2, in findById
pywintypes.com_error: (-2147352567, 'Exception occurred.', (619, 'saplogon', 'The control could not be found by id.', 'C:\\Program Files (x86)\\SAP\\FrontEnd\\SAPgui\\saplogon.HLP', 393215, 0), None)
----------------------------------------------------------------------
Ran 0 tests in 0.017s
FAILED (errors=1)
======================================================================
ERROR: setUpClass (__main__.SapGuiTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\O59380\lowHangingAutomation\dataTransformation.py", line 10, in setUpClass
cls.app = gui.GetScriptingEngine
NameError: name 'gui' is not defined
----------------------------------------------------------------------
Ran 0 tests in 0.004s
FAILED (errors=1)
UPDATED CODE
import unittest
import win32com.client
class SapGuiTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
'''This runs once when the class is instantiated'''
cls.gui = win32com.client.GetObject("SAPGUI")
cls.app = cls.gui.GetScriptingEngine
cls.conn = cls.app.Children(0)
cls.sess = cls.app.Children(0)
cls.sess.findById("wnd[0]").resizeWorkingPane(173, 36, 0)
@classmethod
def tearDownClass(cls):
'''This runs once when the class is being destroyed'''
# Close out any sessions or applications here
...
def setUp(self):
'''This runs before each test case'''
# Start back at the home screen
self.sess.findById("wnd[0]/tbar[0]/okcd").text = "/n"
self.sess.findById("wnd[0]").sendVKey(0)
def tearDown(self):
'''This runs after each test case'''
...
def test_tadir(self):
'''Test that we can access the TADIR table in SE16'''
self.sess.findById("wnd[0]/tbar[0]/okcd").text = "/nse16"
self.sess.findById("wnd[0]").sendVKey(0)
self.sess.findById("wnd[0]/usr/ctxtDATABROWSE-TABLENAME").text = "TADIR"
self.sess.findById("wnd[0]").sendVKey(0)
self.sess.findById("wnd[0]/tbar[1]/btn[8]").press()
if __name__=='__main__':
unittest.main()
William/Stefen - Never mind, I've resolved the issue. Thanks!
Updated Code
import unittest
import win32com.client
class SapGuiTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
'''This runs once when the class is instantiated'''
cls.SapGuiAuto = win32com.client.GetObject("SAPGUI")
cls.application = cls.SapGuiAuto.GetScriptingEngine
cls.connection = cls.application.Children(0)
cls.session = cls.connection.Children(0)
cls.session.findById("wnd[0]").resizeWorkingPane(173, 36, 0)
@classmethod
def tearDownClass(cls):
'''This runs once when the class is being destroyed'''
# Close out any sessions or applications here
...
def setUp(self):
'''This runs before each test case'''
# Start back at the home screen
self.session.findById("wnd[0]/tbar[0]/okcd").text = "/n"
self.session.findById("wnd[0]").sendVKey(0)
def tearDown(self):
'''This runs after each test case'''
...
def test_tadir(self):
'''Test that we can access the TADIR table in SE16'''
self.session.findById("wnd[0]/tbar[0]/okcd").text = "/nymem62"
self.session.findById("wnd[0]").sendVKey(0)
if __name__=='__main__':
unittest.main()
How can I connect the SAP GUI with SapGuiLibrary in the Robot Framework?
Hello Francisco,
you can very easy use Python code in the Robot Framework via test libraries. On this way you can use this approach also, I assume.
Best regards
Stefan
Hi Stefan, It’s a little hard to tell if this is still an active blog, given the dates of the posts.
I posted this question below to your Scripting Tracker thread, but this seems to be a more up-to-date blog.
But I have successfully used scripting tracker to run and play back AutoIT scripts (from scripting Tracker only); What I am having difficulty with is running these scripts from AutoIT, Powershell, or another tool, because the $session variable value is not included or set in the script. I am particularly needing the Python scripts to work, as I want to integrate with Robot Framework. If anyone has solved this, and can post script or links, I would appreciate it.
Many Thanks!
Hi Stefan,
I am newbie to Python and Robot Framwork . I am currently in the process of automating some of the SAP business flows . By using only Robot Framework via SAPLibrary I was able to automate login to SAP and executing a custom program using SE38 and Validating the IDocs created in Tcode WE02 . It was in this step I came across SAP GUIShell with tree & grid which I was unable to automate because the SAP GUI scripting tracker.exe does not capture much details like going thru each node of tree or finding the correct row in the grid.
Do I need to create the logic using python and how to I start ? I am using VS Code editor for coding.
Regards,
Sobin
Hello Stefan,
Have been following your suggestions to automate SAP Gui using python and have successfully automated many sap processes. Currently we are trying to use Robot framework sapguilibrary for automation. In cases where we have to press enter for recurring warning type status bar messages, we dont have support in Robot framework Could you kindly suggest an alternative.
Thanks
Akhila
I have the below python script working to open SAP and then it also runs a t-code after opening.
For some reason I am able to execute a t-code but I'm not able to access the elements by Id using the FindById(). Any solutions? I think the problem is with the window ID or the session ID.
import win32com.client
from win32com import *
from win32api import *
from win32com.client import *
SAPguiAPP = win32com.client.Dispatch("Sapgui.ScriptingCtrl.1")
Connection = SAPguiAPP.OpenConnection("System_Name_QA",1)
Session = SAPguiAPP.ActiveSession
Session.SendCommand(Command="/nSE16")
Interestingly, this format does not cause any error but it does not act upon the Id and transfer a value to the screen either.
Session.SendCommand("Session.FindById('wnd[0]/usr/ctxtRP50G-PERNR').text='9999999'")
Hello Mason,
Session.SendCommand("/nse16") sets in the command field combo box the TAC SE16 and execute it. Your examples should not work in my opinion.
If I try this:
I get the result that the transaction 0 doesn't exists.
And if I try this:
I get an error message.
Best regards
Stefan
Hi Stefan,
I have included a more complete code example and indicated the line where it is failing.
I would like to create the python equivalent of the VBA code below. The problem seems to be the reference to translate the vba Dim SAPguiAPP As SAPFEWSELib.GuiApplication.
How can I call SAPFEWSELib.GuiApplication from the ocx file in python? There are python ctype method to call dlls.
#Start of python code
import win32com.client
from win32com import *
from win32api import *
from win32com.client import *
SAPguiAPP = win32com.client.Dispatch("Sapgui.ScriptingCtrl.1")
Connection = SAPguiAPP.OpenConnection("75 - NSP - Production Simple SAP Access",1)
session1 = SAPguiAPP.ActiveSession
print(help(session1)) # proves the FindByID method is now available in the print out
session1.StartTransaction("PA20") # This line works perfectly
session1.FindById("wnd[0]/usr/ctxtRP50G-PERNR").text = '999999' # This line fails without error
#End of python code
"""
''Start of vba example"
Sub Log_Sap_VBA()
'''references C:\Program Files (x86)\SAP\FrontEnd\SAPgui\sapfewse.ocx
Dim SAPguiAPP As SAPFEWSELib.GuiApplication
Dim Connection As SAPFEWSELib.GuiConnection
Dim Session As SAPFEWSELib.GuiSession
Dim info As SAPFEWSELib.GuiSessionInfo
If SAPguiAPP Is Nothing Then
Set SAPguiAPP = CreateObject("Sapgui.ScriptingCtrl.1")
End If
If Connection Is Nothing Then
Set Connection = SAPguiAPP.OpenConnection("75 - NSP - Production Simple SAP Access",1)
End If
If Session Is Nothing Then
Set Session = Connection.Children(0)
MsgBox x
End If
End Sub
''End of VBA example
"""
Hello Mason,
in my case is in TAC PA20 the GuiCTextField RP50G-PERNR wrapped by a GuiSimpleContainer. If you don't use the complete path to your object the access fails, as in your case.
Please check your path and let us know your result.
Cheers
Stefan
Hi Stefan,
On my SAP, it does not appear to be a wrapped element. I have still not been able to get it to transfer a value to the screen. I included my tracking image below.
import win32com.client
from win32com import *
from win32api import *
from win32com.client import *
SAPguiAPP = win32com.client.Dispatch("Sapgui.ScriptingCtrl.1")
Connection = SAPguiAPP.OpenConnection(“75 – NSP – Production Simple SAP Access”,1)
Session1 = SAPguiAPP.ActiveSession
Session1.StartTransaction("PA20") # This works
Session1 = SAPguiAPP.ActiveSession
Session1.FindById("wnd[0]/usr/lblRP50G-PERNR").text = '999999' # This does not work
Hello Mason,
you open a new connection so you can use this to solve your problem:
Cheers
Stefan
Hi Stefan,
The last script that you posted works perfectly now! I discovered the issue is that it will not work in python 3.6 but it does work in 32-bit python 2.7 with the 32-bit pywin32 package!
The following are the collection of errors that I found in python 3.6 with pywin32 for 3.6.
#Session1 = SAPguiAPP.ActiveSession # Works for the Start Transaction but does not work for FindById
Session1 = Connection.Children(0) # TypeError: 'GuiComponentCollection' object is not callable
#Session1 = Connection.Children(Index=0) # TypeError: 'GuiComponentCollection' object is not callable
#Session1 = Connection.Children # object has no attribute 'StartTransaction'
#Session1 = Connection.Children.Item(0) #object has no attribute 'StartTransaction'
#Session1 = Connection.Children[0] # TypeError: 'GuiComponentCollection' object does not support indexing
#Session1 = Connection.Children['ses[0]'] # 'GuiComponentCollection' object is not subscriptable
#Session1 = SAPguiAPP.ActiveSession.Children(0) #TypeError: 'GuiComponentCollection' object is not callable
#Session1 = Connection.Children() # TypeError: 'GuiComponentCollection' object is not callable
#Session1 = Connection.Children "0" # Invalid Syntax
#Session1 = Connection.Children 0 # Invalid Syntax
#Session1 = Connection.Children # Sets Session1 = to <win32com.gen_py.None.GuiComponentCollection> does not work
#print(len(Dispatch(SAPguiAPP.Children)))
#Session1 = len(Dispatch(SAPguiAPP.Children))
#TypeError: 'GuiComponentCollection' object is not iterable
#TypeError: 'GuiComponentCollection' object cannot be interpreted as an integer
If you find a 3.6 solution please let me know. Otherwise, I'm happy it works in 2.7!
Regards,
Mason
I created a cool and re-usable gui connection class example using a Tkinter window to run the script.
Many buttons could be added to the window re-using the same connection class for each sap gui scripting function.
# import libraries
import win32com.client
from win32com import *
from win32api import *
from win32com.client import *
import win32com.client as win32
import win32gui, win32con
import pyautogui, time, webbrowser, datetime
from Tkinter import *
# create a reuseable connection class
class cls_SAP_Gui_Scripting:
def __init__(self, api, conn):
self.SAPguiAPP = win32com.client.Dispatch(api)
self.Connection = self.SAPguiAPP.OpenConnection(conn,1)
self.Session = self.Connection.Children(0)
# Create Different SAP Script Functions
def run_my_sap_script():
# instantiate the class inside the function
MySapGui = cls_SAP_Gui_Scripting("Sapgui.ScriptingCtrl.1", "75 – NSP – Production Simple SAP Access")
MySapGui.Session.StartTransaction("PA20")
MySapGui.Session.FindById("wnd[0]/usr/ctxtRP50G-PERNR").Text = '9999999'
# Loop through excel workbook here with excel.application
# Create a main window with Tkinter and add button to run SAP Script Function
def main():
window = Tk()
window.title("SAP Script Automation")
window.wm_state('zoomed')
window.configure(bg='red')
b1 = Button(window,text="Run SAP GUI Script",font=("Helvetica", 16),command=run_my_sap_script)
b1.grid(row=0, column=0)
window.mainloop()
# Call Main
main()
Hello Mason,
that sounds great.
Cheers
Stefan
That was a very good snippet Stefan. Were you able to send any other keys other than Enter?
Like sendVkey(2) which is vkey for F2
Hello Vijay,
thanks for your reply.
Sure is that possible, take a look at the SAP GUI Scripting help:
In the table GUI_FKEY you can find all supported virtual key codes.
Best regards
Stefan
Hi Stefan,
I used VBA to write a tool to operate SAP several month ago. This time I want to change it to C++, but I am a bit confused. Do you have any good suggests about this situation? Thank you!
Best regards
Tiny
Hello Tiny,
I assume that you use SAP GUI Scripting too. In my opinion it should be not a problem to use SAP GUI Scripting with C++, you can find an explanation to use COM with C++ here
https://msdn.microsoft.com/en-us/library/windows/desktop/ff485848(v=vs.85).aspx
Best regards
Stefan
Hi Stefan,
I have a question related to SAP GUI screens which have dynamic screen names and changes often for which FindByID is not working.
Currently I'm trying to use FindByName to handle this, but unable to fetch the text from the field, can you please help ?
Hello Raghavendran,
I don’t know what your problem is, I tried it and it works in my case without any problems.
Cheers
Stefan
Hi Stefan,
Thanks for your quick response , i was able to figure out the problem in my code using your example and few others from my search.
My incorrect - Code below -
Raghav
how can we achieve a similar result in MAC? is this possible at all?
Hello David,
I am afraid that is not possible, but I don't know it exactly. SAP GUI Scripting bases on COM and as far as I know it works only on Windows environments.
Cheers
Stefan
Hi Stefan,
Im trying to get the SAP GUI session and print it so that i can know whats the connection currently running, this is currently supported with SAP Scripting Tracker tool provided by you and i able to see the current SAP GUI active.
E.g.
I would like to get the con[4] and print this using python ? Is there a way to achieve this.
Expectation is to get the con[4] value and route my SAP python scripts to specific connection of SAP GUI
Hello Raghavendran,
you can find many examples how to loop over your sessions here:
The same way you can use to detect your correct connection and session to use it with your Python script.
Cheers
Stefan
Stefan, thanks a lot for sharing this knowledge!
We're building in my company a Python app to interact with SAP GUI.
The script you shared at the beginning works fine, but it requires SAP GUI to be already opened. We would like to automate everything from the beginning, including opening SAP GUI, selecting the desired connection, login and so on. However, everytime we try to do that, the SAP GUI interface we get is very different than when we open it manually. Furthermore, it seems the list of connections is not even the same.
The python constructor is this
The script works, and this is shown:
but the GUI is different, this is how it looks if we opened it manually:
And this is the UI when called with Python
Any thoughts on this? Thanks!
Hello David,
your observations are very interesting.
To the different appearance of the UI: David S asked the same question here and I assume that Sapgui.ScriptingCtrl works independently from and without the SAP Logon.
But the requester speaks another language. Disable the notifications and you should not see it again. But it seems that Sapgui.ScriptingCtrl considered this settings but it doesn’t considered the selected theme. Also look at RZ11 with the parameter sapgui/user_scripting_force_notification, it should set to FALSE.
Best regards
Stefan
Hi Stefan,
I have installed py32win on my system but when I run your code example on top I am receiving this error :
Hi Faranak,
Have you solve the problem with python 3.7. I am also facing error when trying to
Hi Steve,
please post your question here to receive help by community members: https://answers.sap.com/questions/ask.html
Thanks.
Mynyna (SAP Community moderator)
Hi,
I have the same issue as reported by
<class 'pywintypes.com_error'>
What should I do?
Thanks
Hi Stefan Schnell
I need help to return session if exists, or log in and return session case not exists.
Can help me this?
Like this but in python:
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(connection) Then
Set connection = application.Children(0)
End If
If Not IsObject(session) Then
Set session = connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject application, "on"
End If
Hello all,
I'm not having any trouble, I'm just in doubt if I'm able to execute a Python code in background (like using Task Scheduler to run a code in a VM).
Is it possible?
This is my code:
Hello, after enabling scripting for my SAP profile, I'm able to generate a script and run it from Python... my question is, would it be possible to deploy this solution as a package (an exe generated from Python for example) to another SAP user (a colleague) without enabling scripting on his SAP profile? Thanks a lot for any support.