使用Python在SAP GUI中进行多处理

发布于 2025-02-05 20:21:33 字数 4880 浏览 3 评论 0原文

我的汁液很老,我无法用它拨打API。因此,我必须操纵SAP的GUI才能做我的事情。

我正在尝试使用Python在两个不同的窗口中同时访问两项SAP交易。

为此,我正在使用库:pywin32,子进程和多处理。

但是我会收到以下错误:

TypeError:无法泡菜'Pyidispatch'对象

常规:[WinError 5] Acess拒绝

我到目前为止所获得的是打开两个窗口(创建两个SAP GUI会话),并在不同的窗口中访问交易,但一个接一个地,换句话说,而不是同时。

该测试程序构成3个分开的脚本:

  • 一个类可以创建连接,创建第一个会话并登录到帐户中。
  • 第二类是“操纵” SAP GUI
  • 最后一个是主要脚本。

脚本:

  1. createConnection.py
      subcrocess Import popen
    进口时间
    来自win32com.client import getObject
    
    
    SAP类:
        def __init __(self,sap_env,user_id,user_password,语言=“ en”,
            新闻= false,connectby = 2):
            self.sap_file =“ c:\\ program文件(x86)\\ sap \\ frontend \\ sapgui” +\ \ \ \ \ \ \ \ \
                            “ \\ saplogon.exe”
            self.sap_env = sap_env
            self.user_id = user_id
            self.user_password = user_password
            self.language =语言
            self.connectby =连接
            self.newsession =新闻
    
        def __get_sap_gui __(self):
            尝试:
                返回getObject('sapgui')。getCriptingEngine
            除了:
                时间。
                返回self .__ get_sap_gui __()
    
        def get_sap_connection(self):
            如果self.connectby == 3:
                popen(self.sap_file +'' + self.sap_env)
                sapgui = self .__ get_sap_gui __()
                conn = sapgui.connections(0)
                超时= 10
                而conn.sessions.count == 0和超时:
                    时间。
                    超时 -  = 1
                如果超时== 0:提高异常(“无法连接”)
            别的:
                popen(self.sap_file)
                sapgui = self .__ get_sap_gui __()
                conn =无
                如果self.connectby == 1:
                    如果sapgui.connections.count> 0:#不好,我稍后再解决
                        对于sapgui.connections中的conn:
                            如果conn.description == self.sap_env:
                                休息
                    如果不是conn:
                        conn = sapgui.openconnection(self.sap_env)
                别的:
                    如果sapgui.connections.count> 0:
                        对于sapgui.connections中的conn:
                            如果在conn.connectionstring中self.sap_env:
                                休息
                    如果不是conn:
                        conn = sapgui.openconnectionbyconnectionstring(self.sap_env)
            返回连接
    
        def get_sap_session(self,conn):
            如果self.newsession:
                numsessions = conn.sessions.count + 1
                conn.sessions(0).createsession()
                而Conn.Sessions.Count≪数字:通过
                session = conn.sessions(numsessions-1)
            别的:
                会话= conn.sessions(0)
    
            如果session.findbyid('wnd [0]/sbar')。text.startswith('snc登录'):
                session.findbyid('wnd [0]/usr/txtrsyst-langu')。text = self.language
                session.findbyid('wnd [0]')。sendvkey(0)
                session.findbyid('wnd [0]')。sendvkey(0)
            elif session.info.user =='':
                session.findbyid('wnd [0]/usr/txtrsyst-bname')。text = self.user_id
                session.findbyid('wnd [0]/usr/pwdrsyst-bcode')。文本= \
                    self.user_password
                session.findbyid('wnd [0]/usr/txtrsyst-langu')。text = self.language
                session.findbyid('wnd [0]')。sendvkey(0)
            session.findbyid('wnd [0]')。最大化()
            返回会话
     
  2. manipulatesap.py
     
    从createConnection导入SAP
    
    
    类Querysap(SAP):
        def __init __(self,sap_env,user_id,user_password,语言):
            super()。
            self.connection = self.get_sap_connection()
            self.session = self.get_sap_session(self.connection)
            self.new_session =无
    
        def open_new_windows(self):
            self.connection。课程(0).createsession()
            self.connection。课程(0).createsession()
            self.new_session = self.connection.sessions(1)
    
        @财产
        def sess1(self):
            返回自我
    
        @财产
        def sess2(self):
            返回self.new_session
     
  3. main.py
     来自ManiPulateSap Import QuerySap
    从多处理进口池,过程
    从时间进口睡眠
    
    def goto_trasaction(会话,transacion):
        session.findbyid(“ wnd [0]/tbar [0]/okcd”)。text = transacion
        session.findbyid(“ wnd [0]”)。sendvkey(0)
        睡眠(5)
    
    
    def sap_interface_multi_process(USR,PW,Env):
        sap_nav = querysap(sap_env = env,user_id = usr,user_password = pw,
                           语言=“ pt”)
        sap_nav.open_new_windows()
        session1 = sap_nav.sess1
        session2 = sap_nav.sess2
        p1 = process(target = goto_trasaction,args =(session1,“ transacion a”))
        p2 = process(target = goto_trasaction,args =(session2,“ transaction b”))
        p1.start()
        p2.start()
        p1.join()
        p1.join()
    
    def main():
        打印(“>>> start”)
        sap_env =“ string_for_connection”
        sap_interface_multi_process(“ usr_id”,“ usr_pw”,sap_env)
        打印(“>>> terinial”)
    
    如果__name__ ==“ __ -main __”:
        主要的()
     

你们能帮我找到我想念的东西以及我应该做什么吗?

非常感谢。

My SAP is very old and I can't make API calls with it. So, I have to manipulate the GUI of SAP to do my stuff.

I'm trying to access two SAP transactions at the same time in two different windows using Python.

To do this I'm using the libraries: pywin32, subprocess and multiprocessing.

But I'm getting the following error:

TypeError: cannot pickle 'PyIDispatch' object

and

PermissionError: [WinError 5] Acess denied

What I got until now is to open two windows (create two SAP GUI sessions) and access the transaction in different windows but one after the other, in other words, not at the same time.

This test program constitutes in 3 separated scripts:

  • One have the class to create a connection, create the first session and login into the account.
  • The second class is to "manipulate" the SAP GUI
  • The last one is the main script.

The Scripts:

  1. createconnection.py
    from subprocess import Popen
    import time
    from win32com.client import GetObject
    
    
    class Sap:
        def __init__(self, sap_env, user_id, user_password, language="EN",
            newSession=False, connectBy=2):
            self.sap_file = "C:\\Program Files (x86)\\SAP\\FrontEnd\\SapGui" +\
                            "\\saplogon.exe"
            self.sap_env = sap_env
            self.user_id = user_id
            self.user_password = user_password
            self.language = language
            self.connectBy = connectBy
            self.newSession = newSession
    
        def __get_sap_gui__(self):
            try:
                return GetObject('SAPGUI').GetScriptingEngine
            except:
                time.sleep(0.5)
                return self.__get_sap_gui__()
    
        def get_sap_connection(self):
            if self.connectBy == 3:
                Popen(self.sap_file + ' ' + self.sap_env)
                sapGui = self.__get_sap_gui__()
                conn = sapGui.Connections(0)
                timeout = 10
                while conn.Sessions.Count == 0 and timeout:
                    time.sleep(1)
                    timeout -= 1
                if timeout == 0: raise Exception("Fail to connect")
            else:
                Popen(self.sap_file)
                sapGui = self.__get_sap_gui__()
                conn = None
                if self.connectBy == 1:
                    if sapGui.Connections.Count > 0: # it's not good, I'll fix this later
                        for conn in sapGui.Connections:
                            if conn.Description == self.sap_env:
                                break
                    if not conn:
                        conn = sapGui.OpenConnection(self.sap_env)
                else:
                    if sapGui.Connections.Count > 0:
                        for conn in sapGui.Connections:
                            if self.sap_env in conn.ConnectionString:
                                break
                    if not conn:
                        conn = sapGui.OpenConnectionByConnectionString(self.sap_env)
            return conn
    
        def get_sap_session(self, conn):
            if self.newSession:
                numSessions = conn.Sessions.Count + 1
                conn.Sessions(0).createsession()
                while conn.Sessions.Count < numSessions: pass
                session = conn.Sessions(numSessions-1)
            else:
                session = conn.Sessions(0)
    
            if session.findById('wnd[0]/sbar').text.startswith('SNC logon'):
                session.findById('wnd[0]/usr/txtRSYST-LANGU').text = self.language
                session.findById('wnd[0]').sendVKey(0)
                session.findById('wnd[0]').sendVKey(0)
            elif session.Info.User == '':
                session.findById('wnd[0]/usr/txtRSYST-BNAME').text = self.user_id
                session.findById('wnd[0]/usr/pwdRSYST-BCODE').text =\
                    self.user_password
                session.findById('wnd[0]/usr/txtRSYST-LANGU').text = self.language
                session.findById('wnd[0]').sendVKey(0)
            session.findById('wnd[0]').maximize()
            return session
    
  2. manipulatesap.py
    
    from createconnection import Sap
    
    
    class QuerySap(Sap):
        def __init__(self, sap_env, user_id, user_password, language):
            super().__init__(sap_env, user_id, user_password, language=language)
            self.connection = self.get_sap_connection()
            self.session = self.get_sap_session(self.connection)
            self.new_session = None
    
        def open_new_windows(self):
            self.connection.Sessions(0).createsession()
            self.connection.Sessions(0).createsession()
            self.new_session = self.connection.Sessions(1)
    
        @property
        def sess1(self):
            return self.session
    
        @property
        def sess2(self):
            return self.new_session
    
  3. main.py
    from manipulatesap import QuerySap
    from multiprocessing import Pool, Process
    from time import sleep
    
    def goto_trasaction(session, transacion):
        session.findById("wnd[0]/tbar[0]/okcd").text = transacion
        session.findById("wnd[0]").sendVKey(0)
        sleep(5)
    
    
    def sap_interface_multi_process(usr, pw, env):
        sap_nav = QuerySap(sap_env=env, user_id=usr,user_password=pw,
                           language="PT")
        sap_nav.open_new_windows()
        session1 = sap_nav.sess1
        session2 = sap_nav.sess2
        p1 = Process(target=goto_trasaction, args=(session1, "TRANSACION A"))
        p2 = Process(target=goto_trasaction, args=(session2, "TRANSACTION B"))
        p1.start()
        p2.start()
        p1.join()
        p1.join()
    
    def main():
        print(">>> Start")
        sap_env = "string_for_connection"
        sap_interface_multi_process("usr_id", "usr_pw", sap_env)
        print(">>> Finish")
    
    if __name__ == "__main__":
        main()
    

Could you guys help me to find what I missing and what I should do?

Thank you very much.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鹤舞 2025-02-12 20:21:33

终于,在VACTION的一段时间后,我得到了解决方案。

但是我不得不重复大量的代码。

我所做的是将SAP类实例化到一个对象,然后将此对象传递给将在并行执行的函数。在此功能内部,我使用SAP类方法来创建连接并创建会话。

这是我的解决方案。不漂亮,但是有效:

from Modules.Sap.sapinit import Sap

def create_sap_session(sap_obj,  extra_num_sessions):
    sap_conn = sap_obj.get_sap_connection()
    sap_obj.get_sap_session(sap_conn)
    if extra_num_sessions < 1:
        return
    for _ in range(extra_num_sessions):
        sap_conn.Sessions(0).createsession()
    return

def parallel_sap_query(sap_obj, sessions_num, transaction):
    sap_conn = sap_obj.get_sap_connection()
    sap_session = sap_conn.Sessions(sessions_num)
    session.findById("wnd[0]/tbar[0]/okcd").text = transaction
    session.findById("wnd[0]").sendVKey(0)

def execute_cancellations(sap_obj):
    create_sap_session(sap_obj, 2)
    sleep(3)
    p1 = Process(target=parallel_sap_query, args=(sap_obj, 0, "A", ))
    p2 = Process(target=parallel_sap_query, args=(sap_obj, 1, "B", ))
    p3 = Process(target=parallel_sap_query, args=(sap_obj, 2, "C", ))
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    close_sap_sessions(sap_obj, 2, 1, 0)

def close_sap_sessions(sap_obj, *sessions):
    sap_conn = sap_obj.get_sap_connection()
    for session in sessions:
        sap_session = sap_conn.Sessions(session)
        sap_session.findById("wnd[0]").close()
    sap_session.findById("wnd[1]/usr/btnSPOP-OPTION1").press()


def main():
    sap_obj = Sap(sap_env, sap_id, sap_pw, "PT")
    execute_cancellations(sap_obj)

Finally I got the solution after sometime of vaction.

But I had to refactory a lot of my code.

What I did was to instantiate the sap class to an object and pass this object to a function that will be executed in parallel. Inside of this function I use the sap class method to create a connection and create a session.

Here is my solution. Not pretty but worked:

from Modules.Sap.sapinit import Sap

def create_sap_session(sap_obj,  extra_num_sessions):
    sap_conn = sap_obj.get_sap_connection()
    sap_obj.get_sap_session(sap_conn)
    if extra_num_sessions < 1:
        return
    for _ in range(extra_num_sessions):
        sap_conn.Sessions(0).createsession()
    return

def parallel_sap_query(sap_obj, sessions_num, transaction):
    sap_conn = sap_obj.get_sap_connection()
    sap_session = sap_conn.Sessions(sessions_num)
    session.findById("wnd[0]/tbar[0]/okcd").text = transaction
    session.findById("wnd[0]").sendVKey(0)

def execute_cancellations(sap_obj):
    create_sap_session(sap_obj, 2)
    sleep(3)
    p1 = Process(target=parallel_sap_query, args=(sap_obj, 0, "A", ))
    p2 = Process(target=parallel_sap_query, args=(sap_obj, 1, "B", ))
    p3 = Process(target=parallel_sap_query, args=(sap_obj, 2, "C", ))
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    close_sap_sessions(sap_obj, 2, 1, 0)

def close_sap_sessions(sap_obj, *sessions):
    sap_conn = sap_obj.get_sap_connection()
    for session in sessions:
        sap_session = sap_conn.Sessions(session)
        sap_session.findById("wnd[0]").close()
    sap_session.findById("wnd[1]/usr/btnSPOP-OPTION1").press()


def main():
    sap_obj = Sap(sap_env, sap_id, sap_pw, "PT")
    execute_cancellations(sap_obj)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文