![](https://en.delphipraxis.net/uploads/set_resources_2/84c1e40ea0e759e3f1505eb1788ddf3c_pattern.png)
![](https://en.delphipraxis.net/uploads/monthly_2023_03/I_member_11328.png)
iqrf
-
Content Count
44 -
Joined
-
Last visited
Posts posted by iqrf
-
-
Hi,
I finally solved it at the Python level.I have two TPython modules, one named main_module and the other sub_module.
Just add to the InitScript
import main_module
import sub_module
main_module.sub_module = sub_moduleAnd you can use in Python main_module.sub_module.function1()
but of course, also sub_module.function1().In this way, a pseudo-hierarchical structure of modules can be created.
Because this doesn't import main_module.sub_module as a test. main_module is not a package! -
Hello,
I have such a dictionary... AddMethod( 'TestArray', @TPyPoint.DoTestArray, 'Point.TestArray()' ); function TPyPoint.DoTestArray(args : PPyObject): PPyObject; cdecl; type TDevice = record ValueA: Integer; ValueB: String; end; TDevices = array of TDevice; var DeviceArray: TDevices; I: Integer; DeviceList: PPyObject; DeviceDict: PPyObject; function TDeviceToPyObject(const Device: TDevice): PPyObject; var DeviceDict: PPyObject; begin with GetPythonEngine do begin DeviceDict := PyDict_New; PyDict_SetItemString(DeviceDict, 'ValueA', PyLong_FromLong(Device.ValueA)); PyDict_SetItemString(DeviceDict, 'ValueB', PyUnicodeFromString(PAnsiChar(AnsiString(Device.ValueB)))); Result := DeviceDict; end; end; begin SetLength(DeviceArray, 2); DeviceArray[0].ValueA := 1; DeviceArray[0].ValueB := 'Device 1'; DeviceArray[1].ValueA := 2; DeviceArray[1].ValueB := 'Device 2'; with GetPythonEngine do begin Adjust(@Self); DeviceList := PyList_New(0); for I := 0 to High(DeviceArray) do begin DeviceDict := TDeviceToPyObject(DeviceArray[I]); PyList_Append(DeviceList, DeviceDict); Py_DecRef(DeviceDict); end; Result := DeviceList; end; end;
Is there any possibility to make the data read-only in Python?
I can only do this if I pass them as Tuples using ArrayToPyTuple(MyArray), but then it's just a one-dimensional array.
And one more question, how to pass TDevice data to Python so that it can be written in Python
instead of this one a = spam.myPoint.TestArray() print(a[0]['ValueA']) print(a[0]['ValueB']) this one a = spam.myPoint.TestArray() print(a[0].ValueA) print(a[0].ValueB)
Thanks.
-
Thanks, but understanding this code is beyond my abilities.
-
Hello,
is it possible to somehow create a submodule. Something like thisMainModule := TPythonModule.Create(nil); MainModule.ModuleName := 'spam'; SubModule := TPythonModule.Create(nil); SubModule.ModuleName := 'spam.test';
and call in Python
import spam import spam.test spam.function1() spam.test.function2()
it reports an error
if i do it like this it's fine
import spam import spam.test as T spam.function1() T.function2()
Can it be solved somehow?
Thanks for the ideas. -
Thanks, it works.
try MaskFPUExceptions(True); PythonEngine1.ExecStrings(Memo1.Lines); except errorMessage := MainModule.mystderr.getvalue(); ErrorLog(errorMessage); end;
I would just like to continuously catch errors if someone writes in the Python code for example print("Error example 1", file=sys.stderr)
or
sys.stderr.write("Error Example 2")
The current solution only prints everything at once, with the same timestamp.Thanks.
-
Hello,
is there any way to remap PyErr_Print using a custom function? I would like to log the error output on a separate sheet. Now everything ends up in TPythonInputOutput. Or can it be done differently?
Thanks for the idea. -
I will answer myself, this is functional
import builtins def myinput(prompt): builtins._input_prompt = prompt return builtins._input(prompt) builtins._input = builtins.input builtins.input = myinput
Thanks again, I'm learning Python and I'm still amazed at what it can do.
-
1
-
-
Thanks a lot, the text is passed, but the input value is always NoneType.
import builtins def myinput(prompt): builtins._input_prompt = prompt builtins._input(prompt) builtins._input = builtins.input builtins.input = myinput nadr = int(input('Enter device address (0 - 239, 255): ')) print(f'Node {nadr} is not bonded')
procedure TForm1.PythonInputOutput1ReceiveUniData(Sender: TObject; var Data: string); var s: string; begin InputQuery( 'Query from Python', MainModule.builtins._input_prompt, s); Data := AnsiString(s); end;
Enter device address (0 - 239, 255): Traceback (most recent call last): File "<string>", line 11, in <module> TypeError : int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
-
On 12/14/2021 at 3:49 PM, pyscripter said:But what you can do is overwrite builtins.input with your own function.
How to override builtins.input please?
-
Unfortunately SystemError: <DebugOutput.write function
happens even if I catch the KeyboardInterrupt in a python script or in Delphi. I am attaching a test application.
If I insert a sleep mode (0,1) before printing, the error does not appear.
If I put sleep(0.08) sometimes it throws SystemError: <function DebugOutput.write sometimes
SystemError: <builtin sleep function> returned a result with an exception set
The value of sleep when the error does not occur will depend on the speed of the computer.
Thanks -
Yes, I end with
GetPythonEngine.PyEval_AcquireThread(PyThread.ThreadState); GetPythonEngine.PyErr_SetString(GetPythonEngine.PyExc_KeyboardInterrupt^, 'Terminated'); GetPythonEngine.PyEval_ReleaseThread(PyThread.ThreadState);
I am having trouble terminating a thread using PyThread.Terminate. It doesn't work in the Demo33 example either. Why?
I don't mean the KeyboardInterrupt: Terminated exception, that's ok.
My point is that in the case of this script, where there is no wait time, another exception will be thrown
while True: print(datetime.now())
SystemError: <function DebugOutput.write at 0x02C56758> returned a result with an exception set --------------------------- Debugger Exception Notification --------------------------- Project Demo01.exe raised exception class EPySystemError with message 'SystemError: <function DebugOutput.write at 0x02C56758> returned a result with an exception set'. --------------------------- Break Continue Help Copy ---------------------------
It looks like the python engine is trying to write to DebugOutput at the moment when the thread is already canceled. If there is a wait in the script, the error will not occur.
Thanks a lot for your help.
-
I modified as per the SimpleDemo but I still get the same error when exiting the thread
Quoteprocedure TForm1.PythonInputOutput1SendUniData(Sender: TObject; const Data: string); var ScheduleWrite: Boolean; begin if Data = '' then Exit; fCriticalSection.Enter; try ScheduleWrite := FOutputStream.Size = 0; FOutputStream.Write(Data[1], Length (Data) * 2); if ScheduleWrite then TThread.ForceQueue(nil, procedure var WS: string; begin fCriticalSection.Enter; try if fOutputStream.Size > 0 then begin SetLength(WS, fOutputStream.Size div 2); fOutputStream.Position := 0; fOutputStream.Read(WS[1], Length(WS) * 2); fOutputStream.Size := 0; if (Memo2.Lines.Count > 0) and (Memo2.Lines[Memo2.Lines.Count -1] <> '') then Memo2.Lines.BeginUpdate; try Memo2.Lines.Add(''); Memo2.Text := Memo2.Text + WS; // Memo2.Lines.GoToTextEnd; finally Memo2.Lines.EndUpdate; end; end; finally fCriticalSection.Leave; end; end); finally fCriticalSection.Leave; end; Sleep(1); end;
2023-04-24 18:00:05.560557 2023-04-24 18:00:05.575824 KeyboardInterrupt: Terminated The above exception was the direct cause of the following exception: Traceback (most recent call last): File "<string>", line 8, in <module> SystemError: <function DebugOutput.write at 0x02C56758> returned a result with an exception set
-
Hi,
According to Demo33, we edited Demo01 to run the script in a thread using the Start and Stop buttons.. PythonGUIInputOutput1 replaced PythonInputOutput1.
unit Unit1; interface uses Classes, SysUtils, Windows, Messages, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls, System.Math,System.SyncObjs, PythonEngine, Vcl.PythonGUIInputOutput; type TPyThread = class(TPythonThread) protected procedure ExecuteWithPython; override; end; TForm1 = class(TForm) PythonEngine1: TPythonEngine; Memo1: TMemo; Panel1: TPanel; Button1: TButton; Splitter1: TSplitter; Button2: TButton; Button3: TButton; OpenDialog1: TOpenDialog; SaveDialog1: TSaveDialog; PythonGUIInputOutput1: TPythonGUIInputOutput; Memo2: TMemo; PythonInputOutput1: TPythonInputOutput; Button4: TButton; Button5: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure PythonInputOutput1SendUniData(Sender: TObject; const Data: string); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button5Click(Sender: TObject); private FCriticalSection : TCriticalSection; PyThread: TPyThread; procedure ThreadDone(Sender: TObject); { Déclarations privées } public { Déclarations publiques } end; var Form1: TForm1; implementation {$R *.DFM} procedure TPyThread.ExecuteWithPython; begin inherited; Form1.PythonEngine1.ExecString(UTF8Encode(Form1.Memo1.Text)); end; procedure TForm1.ThreadDone(Sender: TObject); begin TPythonThread.Py_End_Allow_Threads; end; procedure TForm1.Button1Click(Sender: TObject); var s: String; begin MaskFPUExceptions(True); PythonEngine1.ExecStrings(Memo1.Lines); end; procedure TForm1.Button2Click(Sender: TObject); begin with OpenDialog1 do begin if Execute then Memo1.Lines.LoadFromFile( FileName ); end; end; procedure TForm1.Button3Click(Sender: TObject); begin with SaveDialog1 do begin if Execute then Memo1.Lines.SaveToFile( FileName ); end; end; procedure TForm1.Button4Click(Sender: TObject); begin TPythonThread.Py_Begin_Allow_Threads; PyThread := TPyThread.Create(True); PyThread.FreeOnTerminate := True; PyThread.OnTerminate := ThreadDone; PyThread.Start; end; procedure TForm1.Button5Click(Sender: TObject); begin if Assigned(PyThread) and (not PyThread.Finished) then begin GetPythonEngine.PyEval_AcquireThread(PyThread.ThreadState); GetPythonEngine.PyErr_SetString(GetPythonEngine.PyExc_KeyboardInterrupt^, 'Terminated'); GetPythonEngine.PyEval_ReleaseThread(PyThread.ThreadState); while not PyThread.Finished do application.ProcessMessages; end; end; procedure TForm1.FormCreate(Sender: TObject); begin FCriticalSection := TCriticalSection.Create; end; procedure TForm1.FormDestroy(Sender: TObject); begin if Assigned(PyThread) and (not PyThread.Finished) then Button5Click(Sender); FCriticalSection.Free; end; procedure TForm1.PythonInputOutput1SendUniData(Sender: TObject; const Data: string); begin fCriticalSection.Enter; try TThread.ForceQueue(nil, procedure begin memo2.Lines.Add(data); end); finally fCriticalSection.Leave; end; Sleep(1); end; end.
If I run this script, everything is OK
from datetime import datetime import time while True: time.sleep(0.1) print(datetime.now())
2023-04-24 12:24:21.726342 2023-04-24 12:24:21.834341 2023-04-24 12:24:21.943236 2023-04-24 12:24:22.051522 Traceback (most recent call last): File "<string>", line 8, in <module> KeyboardInterrupt: Terminated
If this one
from datetime import datetime import time while True: print(datetime.now())
so i get an error
2023-04-24 12:44:57.749385 2023-04-24 12:44:57.764722 2023-04-24 12:44:57.780558 2023-04-24 12:44:57.796288 2023-04-24 12:44:57.811762 KeyboardInterrupt: Terminated The above exception was the direct cause of the following exception: Traceback (most recent call last): File "<string>", line 5, in <module> SystemError: <function DebugOutput.write at 0x03FF6758> returned a result with an exception set
Please how to get rid of this error.
Thank you
-
Hi,
in demo34 there is an example of using a user Exception
with PythonModule1.Errors.Add do begin Name := 'PointError'; ErrorType := etClass; end; GetModule.RaiseError( 'PointError', 'this is an example of raising an error !' );
Is there any way to use the definitions of exceptions from an external exception.py file and call them with GetModule.RaiseError?
class RequestNadrInvalidError(ValueError): """ Invalid NADR value. This error is raised whenever a request object receives address that is out of allowed range ([C]: 0, [N]: 1-239). """ pass class RequestHwpidInvalidError(ValueError): """ Invalid HWPID value. This error is raised whenever a request object receives HWPID that is out of allowed range (0-65535 / 0x00-0xFF). """ pass class RequestParameterInvalidValueError(ValueError): """ Invalid request parameter value. This error is raised whenever a request object receives a parameter with value outside of it's defined domain. """ pass
Thanks
-
7 hours ago, pyscripter said:The a great document, thanks a lot.
-
HI,
I took inspiration from Demo34 and did what I needed. Everything works. I just want to ask why it is necessary to call Adjust(@Self);
Do I have to worry about releasing the created PyBytes in TPyPoint.DoReceive using Py_XDECREF(pyBytes) or will Python take care of that?Thanks
function TPyPoint.DoSend(args : PPyObject) : PPyObject; var data: TBytes; pyBytes: PPyObject; function PyBytesAsBytes(Obj: PPyObject): TBytes; var size: NativeInt; buffer: PAnsiChar; arr: TBytes; begin Result := Default(TBytes); with GetPythonEngine do begin if not PyBytes_Check(Obj) then Exit; PyBytes_AsStringAndSize(Obj, buffer, size); if (size = 0) then Exit; SetLength(Result, size); CopyMemory(Result, buffer, size); end; end; begin with GetPythonEngine do begin Adjust(@Self); if PyArg_ParseTuple( args, 'S:Point.Send', @pyBytes ) <> 0 then begin data := PyBytesAsBytes(pyBytes); // .... Result := ReturnNone; end else Result := nil; end; end; function TPyPoint.DoReceive(args : PPyObject) : PPyObject; var pyBytes: PPyObject; data: TBytes; begin with GetPythonEngine do begin Adjust(@Self); SetLength(data, 5); data[0] := 65; data[1] := 66; data[2] := 67; data[3] := 68; data[4] := 69; PyBytes := PyBytes_FromStringAndSize(PAnsiChar(data), Length(data)); Result := pyBytes; end; end;
import spam d = bytes([0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6]) spam.myPoint.Send(d) print(list(d)) d = spam.myPoint.Receive() print(list(d))
-
Yes it can be done using events or just like this
test.send(testC.get_x())procedure Send(Data: Variant);
My point is to pass a python object and then call its function in Delphi.
-
Hi,
I'm completely new to P4D and trying to pass a python object to delphi as a function parameter with no success.
Python:
import delphi
class myclass:
def __init__(self, x, y):
self.x = x + ydef increment(self):
self.x += 1def get_x(self):
return self.xif __name__ == '__main__':
testC = myclass(1, 2)
testC.increment()
print(testC.get_x())
test = delphi.test
test.send(testC) # raised exception class EPyTypeError with message 'TypeError: "Send" called with invalid arguments. Error: Could not find a method with compatible arguments'.
Delphi:{$METHODINFO ON}
TTest = class(TPersistent)
private
public
procedure Send(AObject: PyObject);
published
end;{$METHODINFO OFF}
procedure TTest.Send(AObject: PyObject);
begin//I don't know how to get the x value of myclass here
//showmessage(x.toString);
end;
......
var
test: TTest;
p: PPyObject;
begintest := TTest.Create;
p := PyDelphiWrapper.Wrap(test, soOwned);
PythonModule.SetVar('test', p );GetPythonEngine.ExecString(UTF8Encode(sePythonCode.Text));
end;
Many thanks ahead.
Petr
TPythonModule - submodule
in Python4Delphi
Posted
I finally found a way to make a package
Then it is possible
Only this import my_package.module1 as T is not possible.
ModuleNotFoundError: No module named 'my_package.sub_module1'
Does anyone know why?