Embedded Python利用時にエラーが発生した場合の対応方法のご紹介
これは InterSystems FAQ サイトの記事です。
PythonスクリプトファイルやPythonで記述されたIRIS内メソッドを呼び出す際、エラーが発生した場合の対応方法をご紹介します。
説明使用するコードや資料PDFは公開しています👉 test1.py、FS.Utilsクラス、コードのコピー元、ビデオで解説している資料PDF
Embedded Python 自習用ビデオをご用意しています(項目別にYouTubeプレイリストをご用意しています)。
各プレイリストについて詳しくはこちらをご参照ください👉【はじめてのInterSystems IRIS】Embedded Python セルフラーニングビデオシリーズ公開!
Python側でエラーが発生した場合、ObjectScriptのシステムエラーとして取り扱うことができます。
具体的に確認してみましょう。
解説と実行例については以下のビデオの 最初~03:57までで解説しています。
例えば、以下メソッドの第2引数に0を指定すると'ZeroDivisionError'エラーが発生します。IRISから呼び出した場合は、このエラーは特殊変数$ZERRORにセットされます(=ObjectScriptでエラーが発生したときと同じ状況になります)
ClassMethod errtest1(a As%Integer, b As%Integer) As%Integer [ Language = python ]
{
result=a/b
return result
}
IRISから実行した場合の結果は以下の通りです(特殊変数$ZERRORにエラー文字列が設定されていることを確認できます)。
コマンド例は以下の通りです。
do##class(FS.Utils).errtest1(1,0)ターミナル実行例は以下の通りです。
DO ##CLASS(FS.Utils).errtest1(1,0)
^
<THROW> *%Exception.PythonException <PYTHON EXCEPTION> 246 <class 'ZeroDivisionError'>: division by zero
USER>w $ZE
<THROW> *%Exception.PythonException <PYTHON EXCEPTION> 246 <class 'ZeroDivisionError'>: division by zero
USER>
次に、Pythonのコード内で%Statusのエラーが発生した場合はどうなるでしょうか。
下記コードの解説と実行例については、ビデオの 03:37~ 07:43まで解説しています。
《ObjectScript》
ClassMethod statustest() [ Language = python ]
{
import iris
try:
a=iris.cls("FS.Person")._New()
a.DOB="ThisIsError"
st=a._Save()
iris.check_status(st)
except RuntimeError as ex:
print("pythonのエクセプション!")
print(str(repr(ex)))
raise
}コマンド例は以下の通りです。
write##class(FS.Utils).errtest1(1,0)ターミナル実行例は以下の通りです。
WRITE ##CLASS(FS.Utils).errtest1(1,0)
^
<THROW> *%Exception.PythonException <PYTHON EXCEPTION> 246 <class 'ZeroDivisionError'>: division by zero
USER>
《Pythonスクリプト》
deferr1(a,b):
result=a/b
return resultコマンド例は以下の通りです。
set sys=##class(%SYS.Python).Import("sys")
do sys.path.append("c:\WorkSpace\TryIRIS")
set test1=##class(%SYS.Python).Import("test1")
write test1.err1(1,0)ターミナル実行例は以下の通りです。
USER>do sys.path.append("c:\WorkSpace\TryIRIS")
USER>set test1=##class(%SYS.Python).Import("test1")
USER>write test1.err1(1,0)
WRITE test1.err1(1,0)
^
<THROW> *%Exception.PythonException <PYTHON EXCEPTION> 246 <class 'ZeroDivisionError'>: division by zero
USER>
SQL実行時のエラーはどうなるでしょうか。
下記コードの解説と実行例については、ビデオの07:43~09:06 をご参照ください。
《Pythonスクリプト》
defsqlerr():
import iris
import irisbuiltins
try:
sql="select * from Training.Person"
rset=iris.sql.exec(sql)
for key,val in enumerate(rset):
print(val)
except irisbuiltins.SQLError as ex:
print(str(repr(ex)))
print(ex.sqlcode)
print(ex.message)
print(ex.statement)
raise一連のコマンド例は以下の通りです。
//ローカル変数に何も設定されていない事を確認しますwrite//システムエラーが発生した場合に$ZE特殊変数に情報が設定されますwrite$ZE// Pythonシェル起動do##class(%SYS.Python).Shell()
## 以下Pythonシェルで実行
import sys
sys.path+=["c:\WorkSpace\TryIRIS"]
import test1
test1.sqlerr()
quit()
// 以下IRISターミナルで実行write$ZE// %objlasterrorが存在すると、エラーメッセージが表示されます。do$system.OBJ.DisplayError()ターミナル実行例は以下の通りです。
USER>write $ZE
USER>:py //またはdo ##class(%SYS.Python).Shell()
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type quit() or Ctrl-D to exit this shell.
>>> import sys
>>> sys.path+=["c:\WorkSpace\TryIRIS"]
>>> import test1
>>> test1.sqlerr()
SQLError(" テーブル 'TRAINING.PERSON' が見つかりません")
-30
テーブル 'TRAINING.PERSON' が見つかりません
select * from Training.Person
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "c:\WorkSpace\TryIRIS\test1.py", line 36, in sqlerr
rset=iris.sql.exec(sql)
irisbuiltins.SQLError: テーブル 'TRAINING.PERSON' が見つかりません
>>> quit()
USER>write $ZE
<SYNTAX>errdone+2^%qaqqt
《2024/7/8確認》ビデオで触れていませんがこの時点で、%Statusのエラーが生成され %objlasterror変数に直近のエラー情報がセットされています。(Pythonシェルで受け取ったエラーと同様の情報を確認できます。)
%objlasterror="0 ÞâB Æ0ü0Ö0ë0 'TRAINING.PERSON' L0d0K00~0[00USER
e^exec+3^%SYS.Python.SQL.1^1e^^%SYS.Python.1^0w^Shell+47^%SYS.Python.1^1-e^%DispatchClassMethod+2^%SYSTEM.Python.1^1d^^^0"
USER>do $system.OBJ.DisplayError()
エラー #5521: SQLエラー: SQLCODE=-30 %msg= テーブル 'TRAINING.PERSON' が見つかりません
USER>
%Statusのエラーの表示方法ついて詳しくは、ObjectScriptクックブックの「%Statusのエラーが戻ってきたら」
Python側でエラー処理を書かない場合の説明についてはビデオ 09:06~ ご参照ください。
続いて、Embedded Python利用時にエラーが発生した場合のエラー処理例をご紹介します。
戻り値でエラーだったことを報告する例(Pythonスクリプトの例)の解説は、ビデオの最初~1:48までをご参照ください。
戻り値でエラーだったことを報告する例(language=pythonの例)は、以下ビデオの1:48~3:16で解説しています。
コード例は以下の通りです。
《Pythonスクリプト》
deferr2(a,b):
try:
if b==1:
modori="1で割っても答えは同じです"
return modori
print(f"割り算の答えは={a/b}")
modori="OK"
return modori
except ZeroDivisionError as ex:
modori=str(repr(ex))
print(modori)
return modori《IRISからのコマンド実行例》
set sys=##class(%SYS.Python).Import("sys")
do sys.path.append("C:\WorkSpace\TryIRIS")
set errtest=##class(%SYS.Python).Import("test1")
set ret=errtest.err2(2,2) write ret
set ret=errtest.err2(2,1)
write ret
set ret=errtest.err2(2,0)
write retターミナル実行例は以下の通りです。
USER>do sys.path.append("C:\WorkSpace\TryIRIS")
USER>set errtest=##class(%SYS.Python).Import("test1")
USER>set ret=errtest.err2(2,2) write ret
割り算の答えは=1.0
OK
USER>set ret=errtest.err2(2,1)
USER>write ret
1で割っても答えは同じです
USER>set ret=errtest.err2(2,0)
ZeroDivisionError('division by zero')
USER>write ret
ZeroDivisionError('division by zero')
USER>
《ObjectScriptの例》
ClassMethod errtest2(a As%Integer, b As%Integer) As%Integer [ Language = python ]
{
try:
if b==1:
modori="1で割っても答えは同じです"
return modori
print(f"割り算の答えは={a/b}")
modori="OK"
return modori
except ZeroDivisionError as ex:
modori=str(repr(ex))
print(modori)
return modori
}コマンド実行例は以下の通りです。
set modori=##class(FS.Utils).errtest2(2,2)
write modori
set modori=##class(FS.Utils).errtest2(2,1)
write modori
set modori=##class(FS.Utils).errtest2(2,0)
write modoriターミナル実行例は以下の通りです。
割り算の答えは=1.0
USER>write modori
OK
USER>set modori=##class(FS.Utils).errtest2(2,1)
USER>write modori
1で割っても答えは同じです
USER>set modori=##class(FS.Utils).errtest2(2,0)
ZeroDivisionError('division by zero')
USER>write modori
ZeroDivisionError('division by zero')
USER>
戻り値でエラーだったことを報告する例(%Statusを戻す場合)は、ビデオの3:38~5:22で解説しています。
コード例は以下の通りです。
《ObjectScriptの例》
ClassMethod errtest3(a As%Integer, b As%Integer) As%Status [ Language = python ]
{
import iris
try:
print(a/b)
ret=1
except Exception as ex:
moji="エラーが発生しました!"+str(repr(ex))
ret=iris.system.Status.Error(5001,moji)
return ret
}コマンド実行例は以下の通りです。
set status=##class(FS.Utils).errtest3(1,0)
write$system.Status.GetErrorText(status)
set status=##class(FS.Utils).errtest3(1,1)
write statusターミナル実行例は以下の通りです。
USER>write $system.Status.GetErrorText(status)
エラー #5001: エラーが発生しました!ZeroDivisionError('division by zero')
USER>set status=##class(FS.Utils).errtest3(1,1)
1.0
USER>write status
1
USER>
try: except: を使う + raise でそのままIRISに例外を戻す例と解説は以下ビデオ5:22~最後までご覧ください。
《Pythonスクリプトの例》
def err3(a,b):
try:
ret=a/b
print(ret)
except:
raise《ObjectScriptコード例》
ClassMethod errtest4() As%Status
{
#dim ex As%Exception.AbstractException
try {
set sys=##class(%SYS.Python).Import("sys")
do sys.path.append("C:\WorkSpace\TryIRIS")
set errtest=##class(%SYS.Python).Import("test1")
do errtest.err3(1,0)
}
catch ex {
write"エラーが発生しました:",ex.DisplayString(),!
//例外から%Statusに変換
set st=ex.AsStatus()
//例外からSQLCODEとメッセージを取得
set SQLCODE=ex.AsSQLCODE()
set SQLMessage=ex.AsSQLMessage()
}
} コマンド実行例は以下の通りです。
do##class(FS.Utils).errtest4()ターミナル実行例は以下の通りです。
エラーが発生しました:<PYTHON EXCEPTION> 246 <class 'ZeroDivisionError'>: division by zero
USER>