306 lines
10 KiB
OpenEdge ABL
306 lines
10 KiB
OpenEdge ABL
VERSION 1.0 CLASS
|
|
BEGIN
|
|
MultiUse = -1 'True
|
|
END
|
|
Attribute VB_Name = "s_Python"
|
|
Attribute VB_GlobalNameSpace = False
|
|
Attribute VB_Creatable = False
|
|
Attribute VB_PredeclaredId = False
|
|
Attribute VB_Exposed = False
|
|
Option Explicit
|
|
|
|
' TODO:
|
|
' Public Function RunPyStandalone(sPyCommand$, Optional sWorkDir$ = "") As Long
|
|
' Public Function RunPyFrozen(iPython$, Optional sArgs$ = "") As Long
|
|
|
|
' Public Function API_Python.Execute(sPyCommand$) As Boolean
|
|
' Public Function API_Python.Evaluate(sPyStatement$) As Variant
|
|
|
|
#If Win64 Then
|
|
Private Declare PtrSafe Function GetServer Lib "vbatopy-connector64.dll" (ByRef vResult As Variant) As Long
|
|
Private Declare PtrSafe Function KillPythonServer Lib "vbatopy-connector64.dll" Alias "KillServer" () As Long
|
|
#Else
|
|
Private Declare PtrSafe Function GetServer Lib "vbatopy-connector32.dll" (ByRef vResult As Variant) As Long
|
|
Private Declare PtrSafe Function KillPythonServer Lib "vbatopy-connector32.dll" Alias "KillServer" () As Long
|
|
#End If
|
|
|
|
Dim python_ As API_Python
|
|
|
|
Private Const TEST_FUNCS_FILE = "testFuncs.py"
|
|
Private Const TEST_WRAP_SOURCE = "testWrap.py"
|
|
Private Const TEST_WRAP_RESULT = "testWrap.bas"
|
|
|
|
Public Function Setup()
|
|
' Mandatory setup function
|
|
Set python_ = New API_Python
|
|
Call python_.Init(iPython:=PY_DEFVALUE_INTERPRETER, sModules:="", bDoDebug:=False)
|
|
Call python_.LoadDLL
|
|
End Function
|
|
|
|
Public Function Teardown()
|
|
' Mandatory teardown function
|
|
Call python_.KillServer
|
|
Set python_ = Nothing
|
|
End Function
|
|
|
|
Public Function t_StartServer()
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call Dev_NewCase("Invalid python")
|
|
Dim iTest As New API_Python
|
|
Call iTest.Init("invalid_python", "")
|
|
On Error Resume Next
|
|
Call iTest.StartServer
|
|
Call Dev_ExpectAnyError
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call Dev_NewCase("Missing server module")
|
|
Call iTest.Init("python", "", bDoDebug:=False)
|
|
On Error Resume Next
|
|
Call iTest.StartServer
|
|
Call Dev_ExpectAnyError
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call Dev_NewCase("Too long command")
|
|
Call iTest.Init("python", String$(10000, "A"))
|
|
On Error Resume Next
|
|
Call iTest.StartServer
|
|
Call Dev_ExpectAnyError
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call Dev_NewCase("Start valid")
|
|
Dim iServer As Variant: Call GetServer(iServer)
|
|
Call Dev_ExpectTrue(iServer Is Nothing, "Not started")
|
|
Call Dev_ExpectFalse(python_.Validate, "Not started")
|
|
Call python_.StartServer
|
|
Call GetServer(iServer)
|
|
Call Dev_ExpectTrue(python_.Validate, "After start")
|
|
Call Dev_ExpectFalse(iServer Is Nothing, "After start")
|
|
On Error Resume Next
|
|
Call python_.StartServer
|
|
Call Dev_ExpectNoError("Double start")
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call Dev_NewCase("Double python object")
|
|
Call iTest.Init("python", "")
|
|
On Error Resume Next
|
|
Call iTest.StartServer
|
|
Call Dev_ExpectNoError
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Exit Function
|
|
PROPAGATE_ERROR:
|
|
Call Dev_LogError(Err.Number, Err.Description)
|
|
End Function
|
|
|
|
Public Function t_KillServer()
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call Dev_NewCase("Not started")
|
|
On Error Resume Next
|
|
Call python_.KillServer
|
|
Call Dev_ExpectNoError
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call Dev_NewCase("Valid kill")
|
|
Call python_.StartServer
|
|
Call python_.KillServer
|
|
Dim iServer As Variant: Call GetServer(iServer)
|
|
Call Dev_ExpectTrue(iServer Is Nothing)
|
|
Call Dev_ExpectFalse(python_.Validate)
|
|
On Error Resume Next
|
|
Call python_.KillServer
|
|
Call Dev_ExpectNoError("Dobule kill")
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call Dev_NewCase("Hijack and kill first")
|
|
Call python_.StartServer
|
|
Call KillPythonServer
|
|
On Error Resume Next
|
|
Call python_.KillServer
|
|
Call Dev_ExpectNoError
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Exit Function
|
|
PROPAGATE_ERROR:
|
|
Call Dev_LogError(Err.Number, Err.Description)
|
|
End Function
|
|
|
|
Public Function t_RunPython()
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call Dev_NewCase("Not started")
|
|
Call Dev_ExpectFalse(python_.Validate)
|
|
Call Dev_ExpectTrue(python_.Execute("print(1)"))
|
|
Call Dev_ExpectTrue(python_.Validate)
|
|
|
|
Call Dev_NewCase("Already started")
|
|
Call Dev_ExpectTrue(python_.Execute("print(2)"))
|
|
|
|
Call Dev_NewCase("Invalid code")
|
|
Call Dev_ExpectFalse(python_.Execute("invalid_func_call(42, '42')"))
|
|
Call Dev_ExpectFalse(python_.Execute("do_something_illegal42"))
|
|
|
|
Exit Function
|
|
PROPAGATE_ERROR:
|
|
Call Dev_LogError(Err.Number, Err.Description)
|
|
End Function
|
|
|
|
Public Function t_LoadModule()
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Dim sModule$: sModule = Dev_GetTestFolder & "\" & TEST_FUNCS_FILE
|
|
Call python_.StartServer
|
|
|
|
Call Dev_ExpectFalse(python_.LoadModule(""), "Empty input")
|
|
|
|
Call Dev_NewCase("Missing file")
|
|
Call Dev_ExpectFalse(python_.LoadModule(Dev_GetTestFolder & "\missingFile.py"))
|
|
|
|
Call Dev_NewCase("Valid load")
|
|
Call Dev_ExpectTrue(python_.LoadModule(sModule))
|
|
Call Dev_ExpectEQ("Hello world!", python_.CallFunction("testFuncs", "hello", Array("world")))
|
|
|
|
Call Dev_NewCase("Double load")
|
|
Call Dev_ExpectTrue(python_.LoadModule(sModule))
|
|
|
|
Exit Function
|
|
PROPAGATE_ERROR:
|
|
Call Dev_LogError(Err.Number, Err.Description)
|
|
End Function
|
|
|
|
Public Function t_CallFunctionInvalid()
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call python_.StartServer
|
|
Call Dev_ExpectTrue(python_.LoadModule(Dev_GetTestFolder & "\" & TEST_FUNCS_FILE))
|
|
|
|
Call Dev_NewCase("Invalid module")
|
|
Call Dev_ExpectLike(python_.CallFunction("invalid_module", "get_42"), "Unexpected Python Error*")
|
|
Call Dev_ExpectLike(python_.CallFunction("", "get_42"), "Unexpected Python Error*")
|
|
|
|
Call Dev_NewCase("Invalid function")
|
|
Call Dev_ExpectLike(python_.CallFunction("testFuncs", "invalid_function_name42"), "Unexpected Python Error*")
|
|
Call Dev_ExpectLike(python_.CallFunction("testFuncs", ""), "Unexpected Python Error*")
|
|
|
|
Call Dev_NewCase("Invalid arguments")
|
|
Call Dev_ExpectEQ("Hello world!", python_.CallFunction("testFuncs", "hello", Array("world")), "Unexpected Python Error*")
|
|
Call Dev_ExpectLike(python_.CallFunction("testFuncs", "hello"), "Unexpected Python Error*", "Missing argument")
|
|
Call Dev_ExpectLike(python_.CallFunction("testFuncs", "hello", "world"), "Unexpected Python Error*", "Invalid argument type - string")
|
|
Call Dev_ExpectLike(python_.CallFunction("testFuncs", "hello", ThisWorkbook), "Unexpected Python Error*", "Invalid argument type - object")
|
|
Call Dev_ExpectLike(python_.CallFunction("testFuncs", "hello", Array("world", "big")), "Unexpected Python Error*", "Invalid argument count")
|
|
|
|
Exit Function
|
|
PROPAGATE_ERROR:
|
|
Call Dev_LogError(Err.Number, Err.Description)
|
|
End Function
|
|
|
|
Public Function t_CallFunctionBasic()
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call python_.StartServer
|
|
Call Dev_ExpectTrue(python_.LoadModule(Dev_GetTestFolder & "\" & TEST_FUNCS_FILE))
|
|
|
|
Call Dev_NewCase("No return")
|
|
Call Dev_ExpectTrue(IsNull(python_.CallFunction("testFuncs", "no_return")))
|
|
|
|
Call Dev_NewCase("No arguments")
|
|
Call Dev_ExpectEQ(42, python_.CallFunction("testFuncs", "get_42"))
|
|
|
|
Call Dev_NewCase("Strings")
|
|
Call Dev_ExpectEQ("Hello world!", python_.CallFunction("testFuncs", "hello", Array("world")))
|
|
Call Dev_ExpectEQ("Hello 42!", python_.CallFunction("testFuncs", "hello", Array(42)))
|
|
|
|
Call Dev_NewCase("Multiple args")
|
|
Call Dev_ExpectEQ((13 + 5) * 2, python_.CallFunction("testFuncs", "double_sum", Array(13, 5)))
|
|
|
|
Call Dev_NewCase("Array arg")
|
|
Call Dev_ExpectEQ(42 + 1337 + 1, python_.CallFunction("testFuncs", "sum_array", Array(Array(42, 1337, 1))))
|
|
|
|
Call Dev_NewCase("Dictionary argument")
|
|
Call Dev_ExpectEQ(3, python_.CallFunction("testFuncs", "process_dict", Array(CSet(1, 2, 43))))
|
|
|
|
Call Dev_NewCase("Optional arg")
|
|
Call Dev_ExpectEQ(42, python_.CallFunction("testFuncs", "optional_arg"))
|
|
Call Dev_ExpectEQ(1337, python_.CallFunction("testFuncs", "optional_arg", Array(1337)))
|
|
|
|
Call Dev_NewCase("Multiple return")
|
|
Call Dev_ExpectEQ(Array(42, "test"), python_.CallFunction("testFuncs", "return_tuple"))
|
|
|
|
Call Dev_NewCase("Return list")
|
|
Call Dev_ExpectEQ(Array(42, "test", 11), python_.CallFunction("testFuncs", "return_list"))
|
|
|
|
Call Dev_NewCase("Return 2dlist")
|
|
Call Dev_ExpectEQ(Array(Array(1, 2, 42), Array("test", 13), Array(11)), python_.CallFunction("testFuncs", "return_2dlist"))
|
|
|
|
Call Dev_NewCase("Return dict")
|
|
Dim iTest As New Scripting.Dictionary
|
|
iTest("a") = 42
|
|
iTest("b") = "test"
|
|
iTest("c") = 11
|
|
Call Dev_ExpectEQ(iTest, python_.CallFunctionReturnObject("testFuncs", "return_dict"))
|
|
|
|
Exit Function
|
|
PROPAGATE_ERROR:
|
|
Call Dev_LogError(Err.Number, Err.Description)
|
|
End Function
|
|
|
|
Public Function t_CallFunctionObjects()
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Call python_.StartServer
|
|
Call Dev_ExpectTrue(python_.LoadModule(Dev_GetTestFolder & "\" & TEST_FUNCS_FILE))
|
|
|
|
Call Dev_NewCase("Access VBA COM from Python")
|
|
Dim iCell As Excel.Range: Set iCell = ThisWorkbook.Sheets(1).Cells(1, 1)
|
|
iCell = "test"
|
|
Call Dev_ExpectEQ("test", python_.CallFunction("testFuncs", "extract_range_text", Array(ThisWorkbook.Sheets(1))))
|
|
iCell = ""
|
|
|
|
Call Dev_NewCase("Return VBA object from Python")
|
|
Dim iResult As Object
|
|
Set iResult = python_.CallFunctionReturnObject("testFuncs", "return_range_object", Array(ThisWorkbook.Sheets(1)))
|
|
iResult = "test"
|
|
Call Dev_ExpectEQ("test", iCell.Text)
|
|
iCell = ""
|
|
|
|
Exit Function
|
|
PROPAGATE_ERROR:
|
|
Call Dev_LogError(Err.Number, Err.Description)
|
|
End Function
|
|
|
|
Public Function t_WrapPython()
|
|
On Error GoTo PROPAGATE_ERROR
|
|
|
|
Dim fso As New Scripting.FileSystemObject
|
|
Dim sSource$: sSource = Dev_GetTestFolder & "\" & TEST_WRAP_SOURCE
|
|
Dim sDestination$: sDestination = ThisWorkbook.Path & "\" & TEST_WRAP_RESULT
|
|
Dim sTest$: sTest = Dev_GetTestFolder & "\" & TEST_WRAP_RESULT
|
|
Call python_.StartServer
|
|
Call Dev_AssertEQ(sDestination, python_.WrapPython(sSource, sDestination))
|
|
Call Dev_ExpectEQ(ReadFile(sTest), ReadFile(sDestination))
|
|
|
|
Call fso.DeleteFile(sDestination)
|
|
|
|
Exit Function
|
|
PROPAGATE_ERROR:
|
|
Call Dev_LogError(Err.Number, Err.Description)
|
|
End Function
|
|
|
|
' =====
|
|
Private Function ReadFile(sFile$) As String
|
|
Dim adoStream As New ADODB.Stream
|
|
adoStream.Charset = "utf-8"
|
|
Call adoStream.Open
|
|
|
|
On Error GoTo ERROR_FILE
|
|
Call adoStream.LoadFromFile(sFile)
|
|
On Error GoTo 0
|
|
|
|
ReadFile = adoStream.ReadText
|
|
|
|
ERROR_FILE:
|
|
Call adoStream.Close
|
|
On Error GoTo 0
|
|
End Function
|