Technical Articles
How to use SAP NetWeaver RFC Library with Python – Execute ABAP Report
I presented until now in the series “How to use SAPNetWeaver RFC Library with Pyhton” :
Here now an example how to define and run ABAP code from Python.
All constants, structures and prototypes are in the quasi-include file sapnwrfc.py.
The ABAP report itself is an array of strings. We use the function module (FM) RFC_ABAP_INSTALL_AND_RUN to implement and execute the ABAP program. We set the report line by line in the PROGRAM table of the FM, invoke the function and get a result back in the WRITES table. We read each line of ZEILE and add it to a Result string.
# -*- coding: iso-8859-15 -*-
#-Begin-----------------------------------------------------------------
#-Include---------------------------------------------------------------
FileName = "sapnwrfc.py"
exec(compile(open(FileName).read(), FileName, "exec"))
#-Main------------------------------------------------------------------
#-Connection parameters-------------------------------------------------
RfcConnParams[0].name = "ASHOST"; RfcConnParams[0].value = "NSP"
RfcConnParams[1].name = "SYSNR" ; RfcConnParams[1].value = "00"
RfcConnParams[2].name = "CLIENT"; RfcConnParams[2].value = "001"
RfcConnParams[3].name = "USER" ; RfcConnParams[3].value = "BCUSER"
RfcConnParams[4].name = "PASSWD"; RfcConnParams[4].value = "minisap"
#-ABAPReport------------------------------------------------------------
#-
#- Code your ABAP report here. The length of each line must be equal or
#- less than 72 characters.
#-
#-----------------------------------------------------------------------
ABAP=[]
ABAP.append("Report zTest Line-Size 256.")
ABAP.append("Write: 'Hello World from'.")
ABAP.append("Write: sy-sysid.")
hRFC = SAP.RfcOpenConnection(RfcConnParams, 5, RfcErrInf)
if hRFC != None:
charBuffer = create_unicode_buffer(256 + 1)
Result = ""
hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "RFC_ABAP_INSTALL_AND_RUN", \
RfcErrInf)
if hFuncDesc != 0:
hFunc = SAP.RfcCreateFunction(hFuncDesc, RfcErrInf)
if hFunc != 0:
hTable = c_void_p(0)
#-Writes the report into the PROGRAM table------------------------
if SAP.RfcGetTable(hFunc, "PROGRAM", hTable, RfcErrInf) == RFC_OK:
for i in range(0, len(ABAP)):
hRow = SAP.RfcAppendNewRow(hTable, RfcErrInf)
rc = SAP.RfcSetChars(hRow, "LINE", ABAP[i], len(ABAP[i]), \
RfcErrInf)
if SAP.RfcInvoke(hRFC, hFunc, RfcErrInf) == RFC_OK:
#-Gets the result from the WRITES table-----------------------
if SAP.RfcGetTable(hFunc, "WRITES", hTable, RfcErrInf) == RFC_OK:
RowCount = c_ulong(0)
rc = SAP.RfcGetRowCount(hTable, RowCount, RfcErrInf)
rc = SAP.RfcMoveToFirstRow(hTable, RfcErrInf)
for i in range(0, RowCount.value):
hRow = SAP.RfcGetCurrentRow(hTable, RfcErrInf)
rc = SAP.RfcGetChars(hRow, "ZEILE", charBuffer, 256, \
RfcErrInf)
Result = Result + charBuffer.value
if i < RowCount.value:
rc = SAP.RfcMoveToNextRow(hTable, RfcErrInf)
#-Shows the result------------------------------------------
print(Result)
rc = SAP.RfcDestroyFunction(hFunc, RfcErrInf)
rc = SAP.RfcCloseConnection(hRFC, RfcErrInf)
else:
print(RfcErrInf.key)
print(RfcErrInf.message)
del SAP
#-End-------------------------------------------------------------------
As you can see, it is no problem to define and execute an ABAP program inside Python.
2015/09/16: Three days ago the new Python release 3.5.0 has been published. The method above works perfect with the new release.
2017/04/24: I check the method above with Python release 3.6.1 x64 and with the SAP NetWeaver RFC library 721 PL42 x64 and it works perfect.
Hint: In actual releases of SAP AS you need an extra authorization object S_RFCRAIAR to execute reports via RFC_ABAP_INSTALL_AND_RUN.
Here the include file:
#-Begin-----------------------------------------------------------------
#-Packages--------------------------------------------------------------
from ctypes import *
import platform, os
#-Structures------------------------------------------------------------
class RFC_ERROR_INFO(Structure):
_fields_ = [("code", c_long),
("group", c_long),
("key", c_wchar * 128),
("message", c_wchar * 512),
("abapMsgClass", c_wchar * 21),
("abapMsgType", c_wchar * 2),
("abapMsgNumber", c_wchar * 4),
("abapMsgV1", c_wchar * 51),
("abapMsgV2", c_wchar * 51),
("abapMsgV3", c_wchar * 51),
("abapMsgV4", c_wchar * 51)]
class RFC_CONNECTION_PARAMETER(Structure):
_fields_ = [("name", c_wchar_p),
("value", c_wchar_p)]
#-Constants-------------------------------------------------------------
#-RFC_RC - RFC return codes---------------------------------------------
RFC_OK = 0
RFC_COMMUNICATION_FAILURE = 1
RFC_LOGON_FAILURE = 2
RFC_ABAP_RUNTIME_FAILURE = 3
RFC_ABAP_MESSAGE = 4
RFC_ABAP_EXCEPTION = 5
RFC_CLOSED = 6
RFC_CANCELED = 7
RFC_TIMEOUT = 8
RFC_MEMORY_INSUFFICIENT = 9
RFC_VERSION_MISMATCH = 10
RFC_INVALID_PROTOCOL = 11
RFC_SERIALIZATION_FAILURE = 12
RFC_INVALID_HANDLE = 13
RFC_RETRY = 14
RFC_EXTERNAL_FAILURE = 15
RFC_EXECUTED = 16
RFC_NOT_FOUND = 17
RFC_NOT_SUPPORTED = 18
RFC_ILLEGAL_STATE = 19
RFC_INVALID_PARAMETER = 20
RFC_CODEPAGE_CONVERSION_FAILURE = 21
RFC_CONVERSION_FAILURE = 22
RFC_BUFFER_TOO_SMALL = 23
RFC_TABLE_MOVE_BOF = 24
RFC_TABLE_MOVE_EOF = 25
RFC_START_SAPGUI_FAILURE = 26
RFC_ABAP_CLASS_EXCEPTION = 27
RFC_UNKNOWN_ERROR = 28
RFC_AUTHORIZATION_FAILURE = 29
#-RFCTYPE - RFC data types----------------------------------------------
RFCTYPE_CHAR = 0
RFCTYPE_DATE = 1
RFCTYPE_BCD = 2
RFCTYPE_TIME = 3
RFCTYPE_BYTE = 4
RFCTYPE_TABLE = 5
RFCTYPE_NUM = 6
RFCTYPE_FLOAT = 7
RFCTYPE_INT = 8
RFCTYPE_INT2 = 9
RFCTYPE_INT1 = 10
RFCTYPE_NULL = 14
RFCTYPE_ABAPOBJECT = 16
RFCTYPE_STRUCTURE = 17
RFCTYPE_DECF16 = 23
RFCTYPE_DECF34 = 24
RFCTYPE_XMLDATA = 28
RFCTYPE_STRING = 29
RFCTYPE_XSTRING = 30
RFCTYPE_BOX = 31
RFCTYPE_GENERIC_BOX = 32
#-RFC_UNIT_STATE - Processing status of a background unit---------------
RFC_UNIT_NOT_FOUND = 0
RFC_UNIT_IN_PROCESS = 1
RFC_UNIT_COMMITTED = 2
RFC_UNIT_ROLLED_BACK = 3
RFC_UNIT_CONFIRMED = 4
#-RFC_CALL_TYPE - Type of an incoming function call---------------------
RFC_SYNCHRONOUS = 0
RFC_TRANSACTIONAL = 1
RFC_QUEUED = 2
RFC_BACKGROUND_UNIT = 3
#-RFC_DIRECTION - Direction of a function module parameter--------------
RFC_IMPORT = 1
RFC_EXPORT = 2
RFC_CHANGING = RFC_IMPORT + RFC_EXPORT
RFC_TABLES = 4 + RFC_CHANGING
#-RFC_CLASS_ATTRIBUTE_TYPE - Type of an ABAP object attribute-----------
RFC_CLASS_ATTRIBUTE_INSTANCE = 0
RFC_CLASS_ATTRIBUTE_CLASS = 1
RFC_CLASS_ATTRIBUTE_CONSTANT = 2
#-RFC_METADATA_OBJ_TYPE - Ingroup repository----------------------------
RFC_METADATA_FUNCTION = 0
RFC_METADATA_TYPE = 1
RFC_METADATA_CLASS = 2
#-Variables-------------------------------------------------------------
ErrInf = RFC_ERROR_INFO; RfcErrInf = ErrInf()
ConnParams = RFC_CONNECTION_PARAMETER * 5; RfcConnParams = ConnParams()
SConParams = RFC_CONNECTION_PARAMETER * 3; RfcSConParams = SConParams()
#-Library---------------------------------------------------------------
if str(platform.architecture()[0]) == "32bit":
os.environ['PATH'] += ";C:\\SAPRFCSDK\\32bit"
SAPNWRFC = "C:\\SAPRFCSDK\\32bit\\sapnwrfc.dll"
elif str(platform.architecture()[0]) == "64bit":
os.environ['PATH'] += ";C:\\SAPRFCSDK\\64bit"
SAPNWRFC = "C:\\SAPRFCSDK\\64bit\\sapnwrfc.dll"
SAP = windll.LoadLibrary(SAPNWRFC)
#-Prototypes------------------------------------------------------------
SAP.RfcAppendNewRow.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcAppendNewRow.restype = c_void_p
SAP.RfcCloseConnection.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcCloseConnection.restype = c_ulong
SAP.RfcCreateFunction.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcCreateFunction.restype = c_void_p
SAP.RfcCreateFunctionDesc.argtypes = [c_wchar_p, POINTER(ErrInf)]
SAP.RfcCreateFunctionDesc.restype = c_void_p
SAP.RfcDestroyFunction.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcDestroyFunction.restype = c_ulong
SAP.RfcDestroyFunctionDesc.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcDestroyFunctionDesc.restype = c_ulong
SAP.RfcGetChars.argtypes = [c_void_p, c_wchar_p, c_void_p, c_ulong, \
POINTER(ErrInf)]
SAP.RfcGetChars.restype = c_ulong
SAP.RfcGetCurrentRow.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcGetCurrentRow.restype = c_void_p
SAP.RfcGetFunctionDesc.argtypes = [c_void_p, c_wchar_p, POINTER(ErrInf)]
SAP.RfcGetFunctionDesc.restype = c_void_p
SAP.RfcGetRowCount.argtypes = [c_void_p, POINTER(c_ulong), \
POINTER(ErrInf)]
SAP.RfcGetRowCount.restype = c_ulong
SAP.RfcGetStructure.argtypes = [c_void_p, c_wchar_p, \
POINTER(c_void_p), POINTER(ErrInf)]
SAP.RfcGetStructure.restype = c_ulong
SAP.RfcGetTable.argtypes = [c_void_p, c_wchar_p, POINTER(c_void_p), \
POINTER(ErrInf)]
SAP.RfcGetTable.restype = c_ulong
SAP.RfcGetVersion.argtypes = [POINTER(c_ulong), POINTER(c_ulong), \
POINTER(c_ulong)]
SAP.RfcGetVersion.restype = c_wchar_p
SAP.RfcInstallServerFunction.argtypes = [c_wchar_p, c_void_p, \
c_void_p, POINTER(ErrInf)]
SAP.RfcInstallServerFunction.restype = c_ulong
SAP.RfcInvoke.argtypes = [c_void_p, c_void_p, POINTER(ErrInf)]
SAP.RfcInvoke.restype = c_ulong
SAP.RfcListenAndDispatch.argtypes = [c_void_p, c_ulong, POINTER(ErrInf)]
SAP.RfcListenAndDispatch.restype = c_ulong
SAP.RfcMoveToFirstRow.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcMoveToFirstRow.restype = c_ulong
SAP.RfcMoveToNextRow.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcMoveToNextRow.restype = c_ulong
SAP.RfcOpenConnection.argtypes = [POINTER(ConnParams), c_ulong, \
POINTER(ErrInf)]
SAP.RfcOpenConnection.restype = c_void_p
SAP.RfcPing.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcPing.restype = c_ulong
SAP.RfcRegisterServer.argtypes = [POINTER(SConParams), c_ulong, \
POINTER(ErrInf)]
SAP.RfcRegisterServer.restype = c_void_p
SAP.RfcSetChars.argtypes = [c_void_p, c_wchar_p, c_wchar_p, c_ulong, \
POINTER(ErrInf)]
SAP.RfcSetChars.restype = c_ulong
#-End-------------------------------------------------------------------
Enjoy it.
Hi Stefan,
Thank you for this post. I have referred this and implemented successfully in my assignment. Here we are writing the ABAP code and passing via python script, is it possible to call an existing ABAP program using Python scripts. If it is possible, then kindly guide me to proceed further.
Regards
Ramesh
Hello Ramesh,
thanks for your reply.
As far as I know it is not possible to execute an ABAP program via RFC directly. You must code a wrapper RFC enabled function module on your SAP system which calls your ABAP program via SUBMIT. On this little detour you can reach the same result.
This could be a possible solution where the output of the program is set to an export parameter from the function module of the type string:
Function Z_TEST.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" EXPORTING
*" VALUE(E_RESULT) TYPE STRING
*"----------------------------------------------------------------------
Data lv_oList Type Standard Table Of ABAPLIST.
Data lv_aList Type Standard Table Of LISTZEILE.
Data lv_Zeile Type LISTZEILE.
Submit ZTEST2 And Return Exporting List To Memory.
Call Function 'LIST_FROM_MEMORY'
Tables
LISTOBJECT = lv_oList
Exceptions
Others = 1.
Call Function 'LIST_TO_ASCI'
Tables
LISTASCI = lv_aList
LISTOBJECT = lv_oList
Exceptions
Others = 1.
Loop At lv_aList Into lv_Zeile.
Concatenate e_Result lv_Zeile CL_ABAP_CHAR_UTILITIES=>CR_LF
Into e_Result.
EndLoop.
EndFunction.
Here the report:
REPORT ZTEST2.
Write: / 'Hello World'.
And now you can invoke this function module via Python as I described here.
Best regards.
Stefan
Hi Stefan,
Thank you...
I am busy developing the FM, i will confirm once after implementing the same.
Regards
Ramesh
Hi Stefan,
I have another query, the ABAP report which i am passing via Python script is working in one SAP Module(CRM), but the same code is not working in another module(BI or BS) and failing with the auths error. When i checked with auths team, they replied that my program is creating $TMP package which will not be permitted.
Could you please recommend the way forward.
Regards
Ramesh.
Hello Ramesh,
your (RFC) user needs the following authorization objects
Field S_ADMI_FCD, Value RFCA
Field RFC_RAIAR, Value 16
Field TCD, Value SE38
Field DEVCLASS, Value $TMP
Field OBJTYPE, Value PROG
Field OBJNAME, Value Z$$$XRFC
Field P_GROUP
Field ACTVT, Value 1 and 2
And of course S_RFC đ
Also your target SAP system needs different status - look in table TADIR, PGMID Head OBJECT Syst EDTFLAG (Object can only be edited with a special editor) must be space and table T000, field CCNOCLIIND (Maintenance authorization for objects in all clients) must be space or 1.
Look also the discussion here.
Best regards
Stefan
Hi Stefan,
I have requested the Auths team to assign the suggested roles, but they reverted that access cannot be granted as per the policy. Instead they recommended to try the other solution advised by you by developing the ABAP code & FM in SAP box and then to call the same via python scripts.
Once after creating the FM, i will get back to you.
Thank you for the time.
Regards
Ramesh.
Hello Stefan,
Hope you are doing good!
I have another request, I understood the above recommendation. Now I want to pass a value to ABAP report program as parameter for the data selection from Python GUI. Could you please suggest a way to do this.
Regards
Ramesh
Hello Ramesh,
thanks for your reply, I am well, hope you too.
Here my report example:
Here the RFC-enabled function module to call this report:
As you can see I add only a With, and get the expected result.
Now you can call the function module as in the example above via
Let us know your results.
Cheers
Stefan
Hello Ramesh,
here the main Python code:
Your report is okay, but please change the parameter line to
to differentiate between upper and lower case.
In my case it delivers:
Let us know your results.
Cheers
Stefan
Hello Stefan,
Thank you for the tip-off and it worked, Now I am exploring RfcSetString and RfcSetInt đ
Also I could see the functions syntax in Field-Handling Functions - Components of SAP Communication Technology - SAP Library
Regards
Ramesh
Hi,
I've faced to this.
hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "RFC_ABAP_INSTALL_AND_RUN",RfcErrInf)
ctypes.ArgumentError: argument 1: <class 'OverflowError'>: int too long to convert
I'm using Python 3.5.1 (AMD64) on WIN32.
Im running the code on WIndows 10.. 64 Bit
Any suggestions how to fix the error?
Regards,
Arman
Hi Arman,
I missed your query, is it sorted now?
Regards
Ramesh
Hi Team,
Where can I find execution log for ABAP programs executed in Python script?
Regards,