SE37에서 테스트한 RFC 함수를 Python(pyrfc)으로 부르기 ① 첫 호출과 예외
SAP 밖의 프로그램이 SAP 데이터를 쓰는 가장 흔한 길은 RFC(Remote Function Call)입니다. SE37에서 F8로 테스트하던 함수 모듈을 Python에서는 pyrfc의 conn.call 한 줄로 똑같이 부를 수 있습니다.
이 글은 「SAP + WEB 연동 강의」 1강의 실습 코드입니다. RFC 함수(ABAP)를 직접 만들고, 같은 호출을 SE37과 Python으로 각각 해서 돌아온 값을 나란히 비교합니다. 코드 · 출력 · 화면은 모두 실제 SAP 서버(A4H)에서 2026-11-04에 돌려 본 그대로입니다.
영상으로 먼저 보기
이 글의 순서 그대로 SE37 화면과 Python 코드를 나란히 놓고 실행한 2분 53초짜리 녹화 영상입니다. ②편의 표 파라미터까지 들어 있습니다.
Python을 잘 몰라도 따라올 수 있습니다
Python 코드는 짧은 덩어리 세 개(① 접속 ② 호출 ③ 결과)뿐입니다. 덩어리마다 SE37의 어느 화면과 같은 일인지 짝지어 설명합니다.
이번 글에서 배울 내용과 진행 순서
1단계 — RFC 함수 만들기: 메시지 클래스, 함수 그룹, 함수 모듈
Z_LEC01_PING(Remote-Enabled)을 만듭니다.2단계 — SE37에서 먼저 테스트하기: 값을 넣으면 무엇이 돌아오는지, 빈 값이면 어떤 예외가 나는지 화면으로 봅니다.
3단계 — Python(pyrfc)으로 같은 호출:
rfc_ping.py로 같은 함수를 부르고 SE37 결과와 비교합니다.4단계 — 예외 잡기:
rfc_error.py로 SE37의 Exception이 Python에서는 무엇으로 오는지 봅니다.
여러 행(표)을 돌려받는 방법은 ②편에서 이어집니다.
준비물
SAP: 함수 모듈을 만들 수 있는 개발 시스템과 사용자. 이 글은 ABAP Cloud Developer Trial 2025(시스템 ID
A4H,SAP_BASIS816, 클라이언트001)에서 확인했습니다.PC: Python 3.12 이하(pyrfc 설치 파일이 3.8~3.12용만 있습니다),
pip install pyrfc==3.3.1, 그리고 SAP NW RFC SDK 7.50.
- SDK는 SAP Support Portal에서 S-user로 받습니다(SAP Note 2573790). pyrfc는 이 C 라이브러리를 감싼 패키지라, SDK 없이 pyrfc만 설치하면 import pyrfc에서 실패합니다. - Windows는 zip을 C:\nwrfcsdk에 풀고, 환경변수 SAPNWRFC_HOME을 C:\nwrfcsdk로 만들고, PATH에 C:\nwrfcsdk\lib를 더합니다. - NW RFC SDK 7.50은 Visual C++ 2013 x64 런타임(msvcr120.dll · msvcp120.dll)이 필요합니다. 이 글의 PC에는 x86판만 있어서 오류 126이 났고, x64 DLL을 C:\nwrfcsdk\lib에 넣어 해결했습니다. 보통은 Microsoft의 Visual C++ 2013 재배포 패키지(x64)를 설치합니다. - 이 글은 Windows 11 · PowerShell 7 · Python 3.12.4 · pyrfc 3.3.1 · NW RFC SDK 7.50 PL9에서 돌렸습니다.
권한: 부르는 사용자에게 권한 객체
S_RFC(함수 그룹ZLEC01, 활동16)가 있어야 합니다.
1단계: RFC 함수 만들기
아래 순서로 만듭니다. 이 글에서는 로컬 패키지 $ZLEC를 썼습니다. 회사 시스템에서는 회사의 패키지와 이름 규칙을 따르세요.
SE91에서 메시지 클래스
ZLEC01을 만들고 메시지를 넣습니다.
- 001 보낼 문자열이 비어 있습니다 - 002 테이블 &1 조회 권한이 없습니다 (②편에서 씀) - 003 자재 &1 이(가) 없습니다 (②편에서 씀)
SE80에서 함수 그룹
ZLEC01을 만들고, 함께 생긴 TOP includeLZLEC01TOP의 내용을 아래 코드로 바꿉니다.같은 함수 그룹에 include
LZLEC01F01을 만들어 아래 FORM을 넣습니다. 메인 프로그램SAPLZLEC01에INCLUDE lzlec01f01.줄이 있는지 확인합니다.SE37에서 함수 모듈
Z_LEC01_PING을 함수 그룹ZLEC01로 만듭니다.
- Attributes 탭에서 Remote-Enabled Module을 고르고, 모든 파라미터에 Pass Value를 체크합니다. 둘 중 하나라도 빠지면 SAP 밖에서 부를 수 없습니다. - SE37에서는 Import · Export · Exceptions 탭에 아래 시그니처대로 등록한 뒤 본문(CLEAR부터)만 붙여 넣습니다. ADT(Eclipse)를 쓰면 FUNCTION 줄부터 그대로 붙여 넣으면 시그니처까지 들어갑니다.
함수 그룹 전체를 활성화합니다.
LZLEC01TOP — 함수 그룹의 전역 선언
상수 가운데 테이블 이름과 건수는 ②편의 함수가 씁니다.
*&---------------------------------------------------------------------*
*& 객체 종류 : 함수 그룹 ZLEC01 의 TOP include (LZLEC01TOP)
*& 만드는 곳 : SE80(또는 SE37 > Goto > Function Groups > Create Group)에서
*& 함수 그룹 ZLEC01 '1강 첫 RFC 호출' 을 패키지 $ZLEC 로 만들면 생긴다.
*& 생성된 LZLEC01TOP 내용을 아래로 바꾼다.
*& 함수 : Z_LEC01_PING, Z_LEC01_TYPES_DEMO (둘 다 Remote-Enabled)
*& 메시지 : 메시지 클래스 ZLEC01 (SE91) 001~003, README 'SAP 쪽 준비' 참고
*&---------------------------------------------------------------------*
*& Change History
*& 2026.11.03 Aiden Kim (local $ZLEC) 최초 작성 - 1강 실습용
*&---------------------------------------------------------------------*
FUNCTION-POOL zlec01 MESSAGE-ID zlec01.
" 강의 공통 데이터($ZEDU) 조회 권한 검사 대상
CONSTANTS: gc_tab_mat TYPE tabname VALUE 'ZEDU_MAT',
gc_tab_vend TYPE tabname VALUE 'ZEDU_VEND',
gc_actvt_display TYPE activ_auth VALUE '03'.
" 거래처 반환 건수 기본값·상한
CONSTANTS: gc_vend_default TYPE int4 VALUE 3,
gc_vend_max TYPE int4 VALUE 100.LZLEC01F01 — 서버 시간대 읽기
함수 모듈은 짧게 두고 실제 일은 FORM으로 내립니다. 이번 편에서는 시스템 시간대를 읽는 FORM 하나만 씁니다. 나머지 FORM은 ②편에서 이 파일 아래에 이어 붙입니다.
*&---------------------------------------------------------------------*
*& 객체 종류 : 함수 그룹 ZLEC01 의 FORM include (LZLEC01F01)
*& 만드는 곳 : SE80 > 함수 그룹 ZLEC01 > 오른쪽 클릭 Create > Include,
*& 이름 LZLEC01F01. 메인 프로그램 SAPLZLEC01 에
*& 'INCLUDE lzlec01f01.' 줄이 들어갔는지 확인한다.
*& 내용 : Z_LEC01_PING, Z_LEC01_TYPES_DEMO 의 조회·가공 로직.
*& FORM 은 오류 결과만 돌려주고, 예외(RAISING)는 함수 모듈이 낸다.
*&---------------------------------------------------------------------*
*& Change History
*& 2026.11.03 Aiden Kim (local $ZLEC) 최초 작성 - 1강 실습용
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Form get_system_timezone
*&---------------------------------------------------------------------*
FORM get_system_timezone CHANGING pv_tzone TYPE tznzone.
CLEAR pv_tzone.
" 시스템 시간대 (STZAC). 설정이 없으면 빈 값
CALL FUNCTION 'GET_SYSTEM_TIMEZONE'
IMPORTING
timezone = pv_tzone
EXCEPTIONS
customizing_missing = 1
OTHERS = 2.
IF sy-subrc <> 0.
CLEAR pv_tzone.
ENDIF.
ENDFORM.Z_LEC01_PING — 받은 글자를 돌려주고 서버 정보를 알려 주는 함수
받은
IV_TEXT를EV_ECHO로 그대로 돌려주고, 서버의 시스템 ID · 클라이언트 · 사용자 · 호스트 · 날짜 · 시각 · 시간대를 함께 알려 줍니다.IV_TEXT가 비어 있으면MESSAGE e001(zlec01) RAISING empty_text로 예외EMPTY_TEXT를 냅니다. 4단계에서 이 예외를 Python으로 잡습니다.
*&---------------------------------------------------------------------*
*& 객체 종류 : 함수 모듈 Z_LEC01_PING
*& 함수 그룹 : ZLEC01 (패키지 $ZLEC)
*& 만드는 곳 : SE37 (또는 ADT New > ABAP Function Module)
*& 속성 : Processing Type = Remote-Enabled Module, 모든 파라미터 Pass Value
*& 내용 : 받은 문자열을 그대로 돌려주고, 서버의 시스템 ID·클라이언트·사용자·
*& 서버 날짜·시각·시간대를 함께 알려 준다. 1강 첫 Z 함수 호출용.
*& 예외 : EMPTY_TEXT - IV_TEXT 가 비었을 때 (메시지 ZLEC01 001)
*& → pyrfc ABAPApplicationError(key='EMPTY_TEXT') → saplab SapAbapError
*& 붙여 넣기 : ADT 에서는 아래 FUNCTION 줄부터 그대로. SE37 에서는 파라미터를
*& Import/Export 탭에 등록한 뒤 본문(CLEAR 부터)만 붙여 넣는다.
*&---------------------------------------------------------------------*
*& Change History
*& 2026.11.03 Aiden Kim (local $ZLEC) 최초 작성 - 1강 실습용
*&---------------------------------------------------------------------*
FUNCTION z_lec01_ping
IMPORTING
VALUE(iv_text) TYPE text255
EXPORTING
VALUE(ev_echo) TYPE text255
VALUE(ev_sysid) TYPE syst_sysid
VALUE(ev_client) TYPE syst_mandt
VALUE(ev_user) TYPE syst_uname
VALUE(ev_host) TYPE syst_host
VALUE(ev_date) TYPE syst_datum
VALUE(ev_time) TYPE syst_uzeit
VALUE(ev_sys_tzone) TYPE tznzone
VALUE(ev_user_tzone) TYPE syst_zonlo
VALUE(ev_timestamp) TYPE timestamp
EXCEPTIONS
empty_text.
CLEAR: ev_echo, ev_sysid, ev_client, ev_user, ev_host,
ev_date, ev_time, ev_sys_tzone, ev_user_tzone, ev_timestamp.
" 빈 문자열은 예외로 돌려준다 (Python 예외 실습)
IF iv_text IS INITIAL.
MESSAGE e001(zlec01) RAISING empty_text.
ENDIF.
ev_echo = iv_text.
" 서버 쪽 시스템 필드 그대로
ev_sysid = sy-sysid.
ev_client = sy-mandt.
ev_user = sy-uname.
ev_host = sy-host.
ev_date = sy-datum.
ev_time = sy-uzeit.
ev_user_tzone = sy-zonlo.
PERFORM get_system_timezone CHANGING ev_sys_tzone.
" UTC 기준 타임스탬프
GET TIME STAMP FIELD ev_timestamp.
ENDFUNCTION.확인: 함수 그룹을 활성화했을 때 오류가 없으면 다음 단계로 넘어갑니다.
2단계: SE37에서 먼저 테스트하기
SE37에서 Z_LEC01_PING을 열고 테스트(F8)를 누르면 값을 넣는 화면이 나옵니다.
첫 칸
RFC Target은 비워 둡니다이 칸은 다른 시스템으로 보낼 때 쓰는 칸입니다. 처음에 여기에 값을 넣었다가 'Destination 안녕 SAP not defined' 오류를 봤습니다. 값은 아래
IV_TEXT줄에 넣습니다.
다시 F8을 누르면 결과 화면이 나옵니다. Export parameters에 서버가 돌려준 값이 보입니다.
이번에는 IV_TEXT를 비우고 F8을 누릅니다. 필수 파라미터라서 값을 넣으라는 창(Enter Parameter Value)이 한 번 뜨고, Enter로 넘기면 예외가 보입니다.
확인: 그림 2처럼 Export 값이 보이고 빈 값에서 EMPTY_TEXT가 나오면 SAP 쪽 준비는 끝입니다.
3단계: Python(pyrfc)으로 같은 호출 — rfc_ping.py
이제 같은 함수를 Python에서 부릅니다. 파일 하나에 덩어리 세 개입니다.
import os
from pyrfc import Connection
# ① 접속: SAP Logon 에 넣는 값과 같다
conn = Connection(
ashost="vhcala4hci", sysnr="00", client="001",
user="DEVELOPER", lang="EN",
passwd=os.environ["SAP_PASSWORD"], # 코드에 쓰지 않는다
)
# ② 호출: SE37 테스트와 같다 (함수 이름 + Import 값)
result = conn.call("Z_LEC01_PING", IV_TEXT="안녕 SAP")
# ③ 결과: dict — Export 파라미터 이름이 키
for name, value in result.items():
print(f"{name:<14} {value}")
conn.close()① 접속 = SAP Logon:
Connection에 넣는 값은 SAP Logon에 넣는 값과 같습니다.ashost(서버 주소),sysnr(인스턴스 번호),client,user,lang(로그온 언어). 비밀번호는 코드에 쓰지 않고 환경변수SAP_PASSWORD에서 읽습니다.② 호출 = SE37의 F8:
conn.call("함수 이름", 파라미터=값). 함수 이름과 Import 값을 넣는 것까지 SE37 테스트 화면과 똑같습니다. 파라미터 이름은 대문자로 씁니다.③ 결과 = Export 화면: 돌아온 값은 dict(이름과 값의 묶음)이고, 키가 Export 파라미터 이름입니다.
result["EV_ECHO"]처럼 하나만 꺼내 쓸 수도 있습니다.다 쓰면
conn.close()로 닫습니다. 연결 하나가 SAP 쪽 사용자 세션 하나라서, 닫지 않으면 서버에 세션이 남습니다.
PowerShell 7에서 비밀번호를 화면에 보이지 않게 넣고 실행합니다(-MaskInput은 PowerShell 7.1부터 있습니다).
$env:SAP_PASSWORD = Read-Host -MaskInput "SAP 비밀번호"
python rfc_ping.py실제로 나온 결과입니다.
EV_CLIENT 001
EV_DATE 20261104
EV_ECHO 안녕 SAP
EV_HOST vhcala4hci
EV_SYSID A4H
EV_SYS_TZONE UTC
EV_TIME 112515
EV_TIMESTAMP 20261104112515
EV_USER DEVELOPER
EV_USER_TZONE CETSE37 결과(그림 2)와 나란히 보면 이렇습니다.
EV_ECHO·EV_SYSID·EV_CLIENT·EV_USER·EV_HOST는 글자까지 같습니다.날짜는 SE37이
04.11.2026, pyrfc가20261104입니다. SE37은 사용자 설정 형식으로 바꿔서 보여 주고, RFC는 SAP 안에 저장된 내부 형식 그대로 줍니다. 시각도09:44:39와112515처럼 같은 차이가 납니다. 시각 값 자체가 다른 것은 두 번을 따로 실행했기 때문입니다.EV_TIMESTAMP도 SE37은20.261.104.094.439처럼 자릿수 구분 기호를 넣어 보여 주고, pyrfc는20261104112515(UTC)를 줍니다.줄 순서가 다른 것은 pyrfc가 돌려준 dict가 이름 순이었기 때문입니다(SE37은 인터페이스에 적은 순서). 값은 같습니다.
서버 시각이 한국 시각과 9시간 다른 것은 이 서버의 시스템 시간대가 UTC이기 때문입니다(
EV_SYS_TZONE).
확인: EV_ECHO 안녕 SAP 줄이 보이면 첫 호출에 성공한 것입니다.
4단계: 예외 잡기 — rfc_error.py
import os
from pyrfc import Connection, ABAPApplicationError
conn = Connection(ashost="vhcala4hci", sysnr="00", client="001",
user="DEVELOPER", lang="EN", passwd=os.environ["SAP_PASSWORD"])
# ④ 함수가 낸 예외는 ABAPApplicationError 로 온다
try:
conn.call("Z_LEC01_PING", IV_TEXT="")
except ABAPApplicationError as e:
print("key :", e.key) # SE37 의 Exception
print("message:", e.msg_class, e.msg_number) # 메시지 클래스 · 번호
print("text :", e.message)
conn.close()함수가
RAISING으로 낸 예외는 Python에서ABAPApplicationError로 옵니다.try:안에서 부르고except로 받습니다.e.key가 SE37의 Exception 이름(EMPTY_TEXT)이고,e.msg_class·e.msg_number가 메시지 ID와 번호입니다.
실제로 나온 결과입니다.
key : EMPTY_TEXT
message: ZLEC01 001
text : ID:ZLEC01 Type:E Number:001SE37(그림 3)과 비교하면 예외 이름 · 메시지 ID · 번호는 같습니다. 그런데 메시지 글('보낼 문자열이 비어 있습니다')은 RFC로 오지 않았습니다. e.message에는 ID · 유형 · 번호만 들어 있습니다(이 서버에서 확인한 동작입니다).
그래서 프로그램은 글이 아니라
e.key로 어떤 오류인지 가립니다.사용자에게 보여 줄 글이 꼭 필요하면, 함수가
BAPIRET2같은 반환 파라미터에 글을 담아 돌려주게 만드는 편이 확실합니다.
확인: key : EMPTY_TEXT가 보이면 예외를 잡은 것입니다.
핵심 정리
SAP Logon =
Connection(...)SE37 테스트(함수 이름 + Import 값) =
conn.call("Z_LEC01_PING", IV_TEXT="안녕 SAP")Export 파라미터 = 결과 dict의 키
Exception =
ABAPApplicationError의key날짜 · 시각 · 숫자는 SE37이 보기 좋게 바꾼 값, RFC는 내부 값 그대로
②편에서는 같은 함수 그룹에 표(여러 행)를 돌려주는 함수를 더하고, Python에서 그 표를 list[dict]로 받습니다.
주의할 점
pyrfc는 유지보수가 끝났습니다. SAP가 2024년에
SAP/PyRFC저장소를 보관(archived) 처리했고, PyPI의 마지막 판 3.3.1은 yanked 상태라서pip install pyrfc==3.3.1처럼 버전을 꼭 적어야 받아집니다. 기존 회사 코드에서는 여전히 많이 쓰지만, 새로 오래 갈 연동이라면 대상 시스템에 OData · REST가 열려 있는지 먼저 보세요.NW RFC SDK는 SAP 라이선스 대상입니다. 저장소나 공유 폴더에 올리지 않습니다.
비밀번호는 코드 · 로그 · 화면에 남기지 않습니다. 운영에서는 화면 로그온이 안 되는 RFC 전용 사용자(System 또는 Communication 유형)와, 필요한 함수 그룹만 연
S_RFC권한을 씁니다.접속 값(
vhcala4hci,00,001,DEVELOPER)은 이 글의 체험판 서버 값입니다. 여러분 시스템의 SAP Logon 값으로 바꾸세요. 방화벽은 게이트웨이 포트33+ 인스턴스 번호(인스턴스00이면3300)가 열려 있어야 합니다.lang은 서버에 설치된 언어여야 합니다. 이 서버에는 한국어가 설치되어 있지 않아서lang="KO"로는 로그온이 거부됐습니다(Select one of the installed languages).
출처와 이용 안내
「SAP + WEB 연동 강의」 1강 실습을 위해 직접 작성한 코드입니다.
2026-11-04 ABAP Cloud Developer Trial 2025(A4H,
SAP_BASIS816, 클라이언트001)에서 SE37 테스트와 Python 실행(Windows 11, Python 3.12.4, pyrfc 3.3.1, NW RFC SDK 7.50)으로 확인했습니다. 본문의 화면과 출력은 그때 받은 그대로입니다.회사마다 SAP 버전 · 이름 규칙 · 권한 정책이 다르므로, 실무에 쓸 때는 소속 프로젝트의 개발 표준을 먼저 확인해 주세요.
SAP와 SAP 제품명은 SAP SE의 상표이며, 바로투입은 SAP와 관련이 없습니다.
댓글 0
아직 댓글이 없어요.
로그인하고 댓글 쓰기