iqrf 3 Posted April 24, 2023 (edited) 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 Edited April 24, 2023 by iqrf Share this post Link to post
pyscripter 689 Posted April 24, 2023 You are producing output at a high speed from a thread. You need to buffer the output in a way similar to that in python4delphi/Unit1.pas at master · pyscripter/python4delphi (github.com). Share this post Link to post
iqrf 3 Posted April 24, 2023 I modified as per the SimpleDemo but I still get the same error when exiting the thread Quote python4delphi/Unit1.pas at master · pyscripter/python4delphi (github.com). procedure 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 Share this post Link to post
pyscripter 689 Posted April 24, 2023 (edited) 2 hours ago, iqrf said: when exiting the thread How are you exiting the thread? Are you raising a KeyboardInterrupt as in demo 33? Then why are you surprised that an exception is raised, when the print statement executes. You can modify your script as follows (not tested): while True: try: time.sleep(0.1) print(datetime.now()) except KeyboardInterrupt: break or handle the exception in your Delphi code Edited April 24, 2023 by pyscripter Share this post Link to post
iqrf 3 Posted April 24, 2023 (edited) 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. Edited April 24, 2023 by iqrf Share this post Link to post
pyscripter 689 Posted April 24, 2023 (edited) The KeyboardInterrupt is the correct way to terminate a thread from the main thread. 47 minutes ago, iqrf said: <function DebugOutput.write at 0x02C56758> returned a result with an exception set' This is because print statement executes without clearing the KeyboardInterrupt exception. You need to trap the KeyboardInterrupt exception either in Python or Delphi code. You can also add to your PythonInputOutput1SendUniData with GetPythonEngine do if PyErr_Occurred <> nil then begin PyErr_Clear; Exit; end; Edited April 24, 2023 by pyscripter Share this post Link to post
iqrf 3 Posted April 25, 2023 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 Demo01.zip Share this post Link to post