Skip to Content
Technical Articles
Author's profile photo Stefan Schnell

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:

Assigned tags

      34 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo William Ayd
      William Ayd

      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!

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      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

      Author's profile photo William Ayd
      William Ayd

      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 ?

      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.CDispatch
              cls.app = gui.GetScriptingEngine
              cls.conn = app.Children(0)
              cls.sess = app.Children(1)
              cls.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()
      
      Author's profile photo Francisco Carlos
      Francisco Carlos

      How can I connect the SAP GUI with SapGuiLibrary in the Robot Framework?

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      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

      Author's profile photo Steve Dooley
      Steve Dooley

      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!

      
      
      
      
      Author's profile photo sobin paul
      sobin paul

      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

       

      Author's profile photo Former Member
      Former Member

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

      Author's profile photo Former Member
      Former Member

      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'")

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      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:

      session.sendcommand(Command = "/nse16")

      I get the result that the transaction 0 doesn't exists.

      And if I try this:

      Session.SendCommand(“Session.FindById(‘wnd[0]/usr/ctxtRP50G-PERNR’).text=’9999999′”)

      I get an error message.

      Best regards
      Stefan

       

      Author's profile photo Former Member
      Former Member

      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

      """

       

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      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.

      session.findById("wnd[0]/usr/subSUBSCR_PERNR:SAPMP50A:0110/ctxtRP50G-PERNR").text = "999999"

      Please check your path and let us know your result.

      Cheers
      Stefan

       

       

      Author's profile photo Former Member
      Former Member

      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

       

       

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Mason,

      you open a new connection so you can use this to solve your problem:

      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 = Connection.Children(0)
      Session1.StartTransaction(“PA20”)
      Session1.FindById(“wnd[0]/usr/lblRP50G-PERNR”).text = ‘999999’

      Cheers
      Stefan

      Author's profile photo Former Member
      Former Member

      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

      Author's profile photo Former Member
      Former Member

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

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Mason,

      that sounds great.

      Cheers
      Stefan

      Author's profile photo Former Member
      Former Member

      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

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      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

      Author's profile photo Former Member
      Former Member

      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

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      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

      Author's profile photo Raghavendran Ramasubramanian
      Raghavendran Ramasubramanian

      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 ?

       

      PONbr = cls.session.FindById(
          "wnd[0]/usr").FindByName("txtMEPO_TOPLINE-EBELN","GuiCTextField").text
      
      
      Error I'm getting as below - 
      
      Traceback (most recent call last):
      File "C:\Users\rrama3\PycharmProjects\pysaf_core\pysaf\tests\testBusinessFlows\crossAppTesting\coupaPOValidateInSAP.py", line 47, in get_display_validate_PO
      "wnd[0]/usr").FindByName("txtMEPO_TOPLINE-EBELN","GuiCTextField").text
      AttributeError: 'NoneType' object has no attribute 'Text'
      
      
      How can i interact with FindByName fields to get text, I'm writing my scripts in Python
      
      
      
      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Raghavendran,

      I don’t know what your problem is, I tried it and it works in my case without any problems.

      Cheers
      Stefan

      #-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(0)
          if not type(session) == win32com.client.CDispatch:
            connection = None
            application = None
            SapGuiAuto = None
            return
      
          UserArea = session.findById("wnd[0]/usr")
          Control = UserArea.findByName("shellcont", "GuiContainerShell")
          print(Control.Text)
      
          print(session.findById("wnd[0]/usr").findByName("shellcont", "GuiContainerShell").Text)
      
        except:
          print(sys.exc_info()[0])
      
        finally:
          session = None
          connection = None
          application = None
          SapGuiAuto = None
      
      #-Main------------------------------------------------------------------
      Main()
      
      #-End-------------------------------------------------------------------
      Author's profile photo Raghavendran Ramasubramanian
      Raghavendran Ramasubramanian

      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 -

      PONbr = cls.session.FindById(
          "wnd[0]/usr").FindByName("txtMEPO_TOPLINE-EBELN","GuiCTextField").text
      
      
      Small change makes it work - (which was caused due incorrect Name)
      
      Working Code - (after removing 'txt' from name)
      PONbr = cls.session.FindById( "wnd[0]/usr").FindByName("MEPO_TOPLINE-EBELN","GuiCTextField").text
      
      
      Thanks,

      Raghav

      Author's profile photo David Sanchez
      David Sanchez

      how can we achieve a similar result in MAC? is this possible at all?

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      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

      Author's profile photo Raghavendran Ramasubramanian
      Raghavendran Ramasubramanian

      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

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      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

      Author's profile photo David S
      David S

      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

      class SapGuiScripting:
      
          def __init__(self, api):
              # self.sap_app = win32com.client.Dispatch(api)
              # self.sap_connection = self.sap_app.OpenConnection(conn,1)
              # self.sap_session = self.sap_connection.Children(0)
      sap_gui= SapGuiScripting("Sapgui.ScriptingCtrl.1","the name of our connection")

      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!

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      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

      Author's profile photo Faranak Ghahari Kermani
      Faranak Ghahari Kermani

      Hi Stefan,

      I have installed py32win on my system but when I run your code example on top I am receiving this error :

      <class 'pywintypes.com_error'>
      
      I searched on google about this error I was wondering is this error because of unmatching between the python version and system version?
      my python version is 3.7 (32bit) and my system is 64bit so I installed this package pywin32-224.win32-py3.7.exe.
      I didn't get any error during installation.
      
      Thank you.
      
      Best regards,
      
      Faranak
      Author's profile photo Tung Huynh
      Tung Huynh

      Hi Faranak,

       

      Have you solve the problem with python 3.7. I am also facing error when trying to

      dispatch(”Sapgui.ScriptingCtrl.1")
      Author's profile photo Mynyna Chau
      Mynyna Chau

      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)

      Author's profile photo Johan van der Schelling
      Johan van der Schelling

      Hi,

      I have the same issue as reported by

       

      <class 'pywintypes.com_error'>

      What should I do?

      Thanks