Jump to content

iqrf

Members
  • Content Count

    44
  • Joined

  • Last visited

Everything posted by iqrf

  1. Hello, is it possible to somehow create a submodule. Something like this MainModule := 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.
  2. iqrf

    TPythonModule - submodule

    I finally found a way to make a package import importlib import types import sys # Package name package_name = 'my_package' # List of modules to be part of the package module_names = ['module1', 'module2'] # Create an empty package package = types.ModuleType(package_name) package.__path__ = [] # Import and add individual modules to the package for module_name in module_names: module = importlib.import_module(module_name) setattr(package, module_name, module) # Set __all__ to the list of module names package.__all__ = module_names # Add the package to the list of imported modules sys.modules[package_name] = package Then it is possible import my_package from my_package import module1 from my_package import module2 as T print(dir(module1)) print(dir(my_package.module1)) print(dir(T)) Only this import my_package.module1 as T is not possible. ModuleNotFoundError: No module named 'my_package.sub_module1' Does anyone know why?
  3. iqrf

    TPythonModule - submodule

    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_module And 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!
  4. 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.
  5. iqrf

    TPythonModule - submodule

    Thanks, but understanding this code is beyond my abilities.
  6. 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.
  7. 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.
  8. iqrf

    Get the propt value of input()

    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.
  9. iqrf

    Get the propt value of input()

    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'
  10. iqrf

    Get the propt value of input()

    How to override builtins.input please?
  11. iqrf

    TPythonThread

    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
  12. iqrf

    TPythonThread

    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
  13. iqrf

    TPythonThread

    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.
  14. iqrf

    TPythonThread

    I modified as per the SimpleDemo but I still get the same error when exiting the thread 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
  15. 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
  16. 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 + y def increment(self): self.x += 1 def get_x(self): return self.x if __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; begin test := TTest.Create; p := PyDelphiWrapper.Wrap(test, soOwned); PythonModule.SetVar('test', p ); GetPythonEngine.ExecString(UTF8Encode(sePythonCode.Text)); end; Many thanks ahead. Petr
  17. The a great document, thanks a lot.
  18. 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))
  19. 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.
×