@@ -1049,6 +1049,7 @@ function RttiCall(ParentAddress: pointer; DelphiWrapper: TPyDelphiWrapper;
10491049
10501050function RttiCall (ParentAddress: pointer; DelphiWrapper: TPyDelphiWrapper;
10511051 Method: TRttiMethod; ob1, ob2: PPyObject; const Args: TArray<TValue>;
1052+ const VarParamIndices: TArray<Integer>;
10521053 AParentAddrIsClass: Boolean = false): PPyObject; overload; forward ;
10531054
10541055function GetRttiAttr (ParentAddr: Pointer; ParentType: TRttiStructuredType;
@@ -1465,7 +1466,7 @@ function TPyIndexedProperty.MpSubscript(obj: PPyObject) : PPyObject;
14651466 PyArgs := FPyWrapper.Engine.MakePyTuple([obj]);
14661467
14671468 Result := RttiCall(PascalObject, FPyWrapper, FProperty.ReadMethod,
1468- PyArgs, nil , []);
1469+ PyArgs, nil , [], [] );
14691470
14701471 if not FPyWrapper.Engine.PyTuple_Check(obj) then
14711472 FPyWrapper.Engine.Py_DECREF(PyArgs); // release created tuple
@@ -1514,7 +1515,7 @@ function TPyIndexedProperty.MpAssSubscript(obj1, obj2: PPyObject) : Integer;
15141515 PyArgs := Engine.MakePyTuple([obj1, obj2]);
15151516
15161517 TempPy := RttiCall(PascalObject, FPyWrapper, FProperty.WriteMethod,
1517- PyArgs, nil , []);
1518+ PyArgs, nil , [], [] );
15181519
15191520 Engine.Py_DECREF(PyArgs); // release created tuple
15201521
@@ -1862,7 +1863,8 @@ function PyObjectToTValue(PyArg : PPyObject; ArgType: TRttiType;
18621863end ;
18631864
18641865
1865- function PyArgsToValues (PyArgs: PPyObject; Method: TRttiMethod; out Args: array of TValue): Boolean;
1866+ function PyArgsToValues (PyArgs: PPyObject; Method: TRttiMethod;
1867+ out Args: array of TValue; out VarParamIndices: TArray<Integer>): Boolean;
18661868var
18671869 Index: Integer;
18681870 PyArg : PPyObject;
@@ -1875,15 +1877,16 @@ function PyArgsToValues(PyArgs: PPyObject; Method: TRttiMethod; out Args: array
18751877 if Length(Args) <> Length(Params) then
18761878 Exit(False);
18771879
1880+ VarParamIndices := [];
18781881 Engine := GetPythonEngine;
18791882 for Index := 0 to Length(Params) - 1 do
18801883 begin
18811884 Param := Params[Index];
18821885 PyArg := Engine.PyTuple_GetItem(PyArgs, Index);
1883- if (Param.Flags * [TParamFlag.pfVar, TParamFlag.pfOut] <> []) or
1884- not PyObjectToTValue(PyArg, Param.ParamType, Args[Index], ErrMsg)
1885- then
1886+ if not PyObjectToTValue(PyArg, Param.ParamType, Args[Index], ErrMsg) then
18861887 Exit(False);
1888+ if (Param.Flags * [TParamFlag.pfVar, TParamFlag.pfOut] <> []) then
1889+ VarParamIndices := VarParamIndices + [Index];
18871890 end ;
18881891 Result := True;
18891892end ;
@@ -2616,20 +2619,9 @@ function RttiCall(ParentAddress: pointer; DelphiWrapper: TPyDelphiWrapper;
26162619 MethName: string; ParentRtti: TRttiStructuredType; ob1, ob2: PPyObject;
26172620 AParentAddrIsClass: Boolean): PPyObject;
26182621
2619- { TODO: Handle methods with var parameters
2620- procedures/functions with var parameters should return a tuple
2621- e.g.
2622- procedure Test(var Param: Integer)
2623- use in python:
2624- param = objref.Test(param)
2625-
2626- function Test(var Param: Integer): Integer
2627- use in python:
2628- res, param = objref.Test(param) }
2629-
26302622 function FindMethod (const MethName:string; RttiType : TRttiType;
26312623 PyArgs: PPyObject; var Args: array of TValue;
2632- out ErrMsg: string):TRttiMethod;
2624+ out VarParamIndices: TArray<Integer>; out ErrMsg: string):TRttiMethod;
26332625 // Deals with overloaded methods
26342626 // Constructs the Arg Array
26352627 // PyArgs is a Python tuple
@@ -2640,7 +2632,7 @@ function RttiCall(ParentAddress: pointer; DelphiWrapper: TPyDelphiWrapper;
26402632 ErrMsg := rs_UnknownAttribute;
26412633 for Method in RttiType.GetMethods do
26422634 if SameText(Method.Name , MethName) then begin
2643- if PyArgsToValues(PyArgs, Method, Args) then
2635+ if PyArgsToValues(PyArgs, Method, Args, VarParamIndices ) then
26442636 begin
26452637 Result := Method;
26462638 Break;
@@ -2652,55 +2644,61 @@ function RttiCall(ParentAddress: pointer; DelphiWrapper: TPyDelphiWrapper;
26522644
26532645var
26542646 Args: TArray<TValue>;
2647+ VarParamIndices: TArray<Integer>;
26552648 ArgCount: Integer;
26562649 meth: TRttiMethod;
2657- ReturnValue: TValue;
26582650 ErrMsg : string;
2659- Addr: TValue;
26602651
26612652begin
26622653 Result := nil ;
26632654
26642655 ArgCount := DelphiWrapper.Engine.PyTuple_Size(ob1);
26652656 SetLength(Args, ArgCount);
26662657
2667- meth := FindMethod(MethName, ParentRtti, ob1, Args, ErrMsg);
2658+ meth := FindMethod(MethName, ParentRtti, ob1, Args, VarParamIndices, ErrMsg);
26682659
26692660 if not Assigned(meth) then begin
26702661 InvalidArguments(MethName, ErrMsg);
26712662 Exit;
26722663 end ;
26732664
26742665 Result := RttiCall(ParentAddress, DelphiWrapper, meth, ob1, ob2, Args,
2675- AParentAddrIsClass);
2666+ VarParamIndices, AParentAddrIsClass);
26762667end ;
26772668
26782669// This overload can be called either directly or from the overload above.
26792670// When it is called from above Args are already setup and validated
26802671// When it is called directly Args = []
26812672function RttiCall (ParentAddress: pointer; DelphiWrapper: TPyDelphiWrapper;
26822673 Method: TRttiMethod; ob1, ob2: PPyObject; const Args: TArray<TValue>;
2674+ const VarParamIndices: TArray<Integer>;
26832675 AParentAddrIsClass: Boolean = false): PPyObject;
26842676var
26852677 ArgCount: Integer;
26862678 LArgs: TArray<TValue>;
2679+ LVarParamIndices: TArray<Integer>;
26872680 Addr: TValue;
26882681 ReturnValue: TValue;
2689- ErrMsg : string;
2682+ ErrMsg: string;
2683+ TempPy: PPyObject;
2684+ Index, Pos: Integer;
26902685begin
26912686 Result := nil ;
26922687 // Ignore keyword arguments ob2
26932688 // ob1 is a tuple with zero or more elements
26942689
26952690 ArgCount := DelphiWrapper.Engine.PyTuple_Size(ob1);
26962691 if Length(Args) = ArgCount then
2692+ begin
26972693 // already validated
2698- LArgs := Args
2694+ LArgs := Args;
2695+ LVarParamIndices := VarParamIndices;
2696+ end
26992697 else
27002698 begin
27012699 SetLength(LArgs, ArgCount);
27022700
2703- if not PyArgsToValues(ob1, Method, LArgs) then
2701+ if not PyArgsToValues(ob1, Method, LArgs, LVarParamIndices ) then
27042702 begin
27052703 InvalidArguments(Method.Name , rs_IncompatibleArguments);
27062704 Exit;
@@ -2723,7 +2721,66 @@ function RttiCall(ParentAddress: pointer; DelphiWrapper: TPyDelphiWrapper;
27232721
27242722 ReturnValue := Method.Invoke(Addr, LArgs);
27252723
2726- Result := TValueToPyObject(ReturnValue, DelphiWrapper, ErrMsg);
2724+ { Deal with var/out arguments
2725+ e.g.
2726+ procedure Test(var I: Integer)
2727+ use in python:
2728+ ivalue = objref.Test(param)
2729+
2730+ procedures/functions with var parameters should return a tuple
2731+ function Test(var I: Integer): Integer
2732+ use in python:
2733+ res, ivalue = objref.Test(ivalue)
2734+
2735+ procedure Test(var I: Integer; var S: string);
2736+ use in python:
2737+ ivalue, svalue = objref.Test(ivalue, svalue) }
2738+
2739+
2740+ if Length(VarParamIndices) = 0 then
2741+ Result := TValueToPyObject(ReturnValue, DelphiWrapper, ErrMsg)
2742+ else if (Method.ReturnType = nil ) and (Length(VarParamIndices) = 1 ) then
2743+ Result := TValueToPyObject(LArgs[VarParamIndices[0 ]], DelphiWrapper, ErrMsg)
2744+ else
2745+ begin
2746+ // we return a tuple - start with the return value
2747+ if Method.ReturnType = nil then
2748+ Pos := 0
2749+ else
2750+ Pos := 1 ;
2751+
2752+ Result := DelphiWrapper.Engine.PyTuple_New(Length(VarParamIndices) + Pos);
2753+ if Method.ReturnType <> nil then
2754+ begin
2755+ TempPy := TValueToPyObject(ReturnValue, DelphiWrapper, ErrMsg);
2756+
2757+ if TempPy = nil then
2758+ begin
2759+ DelphiWrapper.Engine.Py_DECREF(Result);
2760+ Result := nil ;
2761+ end
2762+ else
2763+ DelphiWrapper.Engine.PyTuple_SetItem(Result, 0 , TempPy);
2764+ end ;
2765+
2766+ if Result <> nil then
2767+ for Index in VarParamIndices do
2768+ begin
2769+ TempPy := TValueToPyObject(LArgs[Index], DelphiWrapper, ErrMsg);
2770+ if TempPy = nil then
2771+ begin
2772+ DelphiWrapper.Engine.Py_DECREF(Result);
2773+ Result := nil ;
2774+ Break;
2775+ end
2776+ else
2777+ begin
2778+ DelphiWrapper.Engine.PyTuple_SetItem(Result, Pos, TempPy);
2779+ Inc(Pos);
2780+ end ;
2781+ end ;
2782+ end ;
2783+
27272784 if Result = nil then
27282785 with DelphiWrapper.Engine do
27292786 PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString(
@@ -3989,7 +4046,7 @@ function TPyDelphiObject.MpSubscript(obj: PPyObject) : PPyObject;
39894046 PyArgs := PyDelphiWrapper.Engine.MakePyTuple([obj]);
39904047
39914048 Result := RttiCall(DelphiObject, PyDelphiWrapper, Prop.ReadMethod,
3992- PyArgs, nil , []);
4049+ PyArgs, nil , [], [] );
39934050
39944051 if not PyDelphiWrapper.Engine.PyTuple_Check(obj) then
39954052 PyDelphiWrapper.Engine.Py_DECREF(PyArgs); // release created tuple
@@ -4034,7 +4091,7 @@ function TPyDelphiObject.MpAssSubscript(obj1, obj2: PPyObject) : Integer;
40344091 PyArgs := Engine.MakePyTuple([obj1, obj2]);
40354092
40364093 TempPy := RttiCall(DelphiObject, PyDelphiWrapper, Prop.WriteMethod,
4037- PyArgs, nil , []);
4094+ PyArgs, nil , [], [] );
40384095
40394096 Engine.Py_DECREF(PyArgs); // release created tuple
40404097
0 commit comments