iqrf 3 Posted June 7, 2023 (edited) Hi, I have a TPythonType object TPyDevice = class(TPyObject) and Interface methods in it function DoSendAndReceive(args: PPyObject): PPyObject; cdecl; function TPyDevice.DoSendAndReceive(args: PPyObject): PPyObject; cdecl; var data: TBytes; pyBytes: PPyObject; timeout: Single; logging: Boolean; begin with GetPythonEngine do begin Adjust(@Self); logging := False; if PyArg_ParseTuple( args, 'S|fp:device.send_and_receive', @pyBytes, @timeout, @logging) <> 0 then begin data := PyBytesAsBytes(pyBytes); var response := False; .... .... if response then begin pyBytes := PyBytes_FromStringAndSize(PAnsiChar(data), Length(data)); Result := pyBytes; end else Result := ReturnNone; end else Result := nil; end; end; I use it like this response = device_manager.device.send_and_receive(dat, 0, True) or response = device_manager.device.send_and_receive(dat) I would like to call the function like this device_manager.device.send_and_receive(data=dat, timeout 0, logging=True) or device_manager.device.send_and_receive(data=dat, logging=True) I edited it like this function TPyDevice.DoSendAndReceive(args, kwds: PPyObject): PPyObject; cdecl; var data: TBytes; pyBytes: PPyObject; timeout: Single; logging: Boolean; keyArray: array of AnsiString; keyPointerArray: array of PAnsiChar; begin with GetPythonEngine do begin Adjust(@Self); logging := False; KeyArray := ['data', 'timeout', 'logging']; KeyPointerArray := [PAnsiChar(KeyArray[0]), PAnsiChar(KeyArray[1]), PAnsiChar(KeyArray[2])]; if PyArg_ParseTupleAndKeywords(args, kwds, 'S|fp:device.send_and_receive', @keyPointerArray[0], @pyBytes, @timeout, @logging) <> 0 then begin data := PyBytesAsBytes(pyBytes); var response := False; .... .... if response then begin pyBytes := PyBytes_FromStringAndSize(PAnsiChar(data), Length(data)); Result := pyBytes; end else Result := ReturnNone; end else Result := nil; end; end; TPyDevice = class(TPyObject) ... constructor CreateWith( PythonType : TPythonType; args : PPyObject ); override; // Basic services function Repr : PPyObject; override; function Str : PPyObject; override; function GetAttr(Key: PAnsiChar): PPyObject; override; function SetAttr(Key: PAnsiChar; Value: PPyObject): Integer; override; // Methods of TPyDevice ... // Class methods class procedure RegisterMethods(PythonType: TPythonType); override; class procedure RegisterMembers(PythonType: TPythonType); override; class procedure RegisterGetSets(PythonType: TPythonType); override; // Interface methods function DoSendAndReceive(args, kwds: PPyObject): PPyObject; cdecl; ... end; class procedure TPyDevice.RegisterMethods(PythonType: TPythonType); begin inherited; with PythonType do begin AddMethod('send_and_receive', @TPyDevice.DoSendAndReceive, 'device_manager.device.send_and_recive(data: bytes)'); .... end; end; FPythonType_Device := TPythonType.Create(nil); FPythonType_Device.Name := 'FPythonType_Device'; FPythonType_Device.GenerateCreateFunction := False; FPythonType_Device.Engine := FEngine; FPythonType_Device.OnInitialization := OnInitialization_PythonType_Device; FPythonType_Device.TypeName := 'Device'; FPythonType_Device.Prefix := ''; FPythonType_Device.Services.Basic := [bsGetAttr, bsSetAttr, bsRepr, bsStr]; FPythonType_Device.Module := FPythonModule_DeviceManager; pDevice := FPythonType_Device.CreateInstance; FEngine.CheckError; device := TPyDevice(PythonToDelphi(pDevice)); FPythonModule_DeviceManager.SetVar('device', pDevice); FEngine.Py_DecRef(pDevice); But I get TypeError: send_and_receive() takes no keyword arguments. Execution of the send_and_receive function will not start at all. I looked at the Demo32 example, but there it is used with CreateWith which has parameters args, kwds: PPyObject already PythoEngine.pas Thank you in advance for your help. Edited June 7, 2023 by iqrf Share this post Link to post
pyscripter 689 Posted June 7, 2023 Demo32 demonstrates how to use PyArg_ParseTupleAndKeywords. Share this post Link to post
iqrf 3 Posted June 7, 2023 Yes, according to Demo32 I implemented it. But it is an example of use in CreateWidth. I am trying to use it in a method. Share this post Link to post
iqrf 3 Posted June 7, 2023 (edited) I will answer myself. To register a method, you need to use AddMethodWithKeywords instead of AddMethod. It was enough to look at WrapDelphi.pas. I think it would be beneficial if Demo32 included an example of such a method. 14 hours ago, iqrf said: AddMethod('send_and_receive', @TPyDevice.DoSendAndReceive, 'device_manager.device.send_and_recive(data: bytes)'); and still to fix Quote KeyPointerArray := [PAnsiChar(KeyArray[0]), PAnsiChar(KeyArray[1]), PAnsiChar(KeyArray[2])]; KeyPointerArray := [PAnsiChar(KeyArray[0]), PAnsiChar(KeyArray[1]), PAnsiChar(KeyArray[2]), nil]; Edited June 8, 2023 by iqrf Share this post Link to post