there.
I have two daily extractions using Python in SAP GUI that consume a lot of time, and this must be done faster. So, i am trying to run in parallel two transactions for solve this issue.
I am stuck in the same problem occurred here Multiprocessing in SAP GUI using Python , but i cannot find the way this it was solve. Basically, it is a problem when i am trying to acess SAP GUI using multiprocessing library for Python and one of internal modules try pickle the SAP GUI session object.
This is the error: TypeError: cannot pickle 'PyIDispatch' object
I am trying to acess SAP GUI version 740 for extract two transactions report at the same time, and like my friend
above i cannot use RFC tools. I kwnow that is non-maintainable solution, but it will be a temporary solution for this problem.
I have two files in my code - sap_novo:
import time, win32com.client
from subprocess import Popen
class SAP:
def __init__(self, site): # Função que inicia a classe SAP
self.path = 'C:\\Program Files (x86)\\SAP\\FrontEnd\\SAPgui\\saplgpad.exe'
self.site = site
self.SSO = SSO
self.con = None
self.appl = None
self.sap_gui = None
self.session = None
@property
def session(self):
return self._session
@session.setter
def session(self, value):
self._session = value
def connectToSAP(self):
Popen(self.path)
time.sleep(15)
SapGui = win32com.client.GetObject("SAPGUI")
Appl = SapGui.GetScriptingEngine
con = Appl.OpenConnection(self.site, True)
self.session = con.Children(0)
self.con = Appl.Connections(0)
main
from multiprocess import Process
import sap_novo
import dill
def CX34(con_base, id_session):
sap_session = con_base.Sessions(id_session)
sap_session.findById("wnd[0]").maximize()
sap_session.findById("wnd[0]/tbar[0]/okcd").text = "cx34"
sap_session.findById("wnd[0]").sendVKey(0)
def FS10N(con_base, id_session):
sap_session = con_base.Sessions(id_session)
sap_session.findById("wnd[0]").maximize()
sap_session.findById("wnd[0]/tbar[0]/okcd").text = "FS10N"
sap_session.findById("wnd[0]").sendVKey(0)
def run_parallel(connection):
p1 = Process(target=CX34, args=(connection, 0))
p2 = Process(target=FS10N, args=(connection, 1))
p1.start()
p2.start()
p1.join()
p2.join()
def main():
sap_obj = sap_novo.SAP('Environment')
sap_obj.connectToSAP()
sap_obj.checkLogin(sap_obj.session,"wnd[1]")
run_parallel(sap_obj.con)
if __name__ == '__main__':
main()
I use dill package for understand what is happening using this
dill.detect.trace(True)
dill.pickles(sap_obj.session)
print(dill.dumps(sap_obj.session))
, and i got:
T4: \<class 'win32com.client.CDispatch'\>
# T4 \[32 B\]
┬ D2: \<dict object at 0x20ba608a500\>
┬ T4: \<class 'win32com.client.CDispatch'\>
└ # T4 \[32 B\]
┬ D2: \<dict object at 0x20ba608a500\>
Then, it looks like a problem with serialization/pickle in win32com.client.CDispatch objects.
Anyone could help me this?
Thanks!!
guys.
I achieved my goal using python threading package. I could not make it work using multiprocess.
Basicaly, i am making two threads, one of each transaction code, and passing a session id for each function.
However, it is necessary a intermediary step for make this work. I had to use pythoncom library for pass a session object between the threads, because there is some limitation in working with COM objects and threads together in python. This topic help me to do that Using win32com with multithreading.
In this sense, i had to create two functions to serialize and deserialize sessions objects.
def serializeSessions(sap_sessions):
sessions = []
for session in sap_sessions:
sessions.append(pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch,
session))
return sessions
def deserializeSession(session_id):
pythoncom.CoInitialize()
#
# Get instance from the id
session = win32com.client.Dispatch(
pythoncom.CoGetInterfaceAndReleaseStream(session_id, pythoncom.IID_IDispatch)
)
return session
With this, i am doing a serialize before instantiate a thread, then i pass the serialized session object and run a deserialization inside the transaction function.