Jump to content

pyscripter

Members
  • Content Count

    1045
  • Joined

  • Last visited

  • Days Won

    70

pyscripter last won the day on August 28

pyscripter had the most liked content!

Community Reputation

828 Excellent

Technical Information

  • Delphi-Version
    Delphi 12 Athens

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. pyscripter

    New file system monitoring component

    You will still have the same issue if the parent directory (or the parent of the parent...) gets deleted or renamed. Even if not, you may be getting many more notifications than you need. Also you would have to watch subfolders, which you may not want. It is not worth it. Checking every x seconds whether the monitored directories still exist, is a tiny overhead.
  2. pyscripter

    New file system monitoring component

    @mjustin Have a look at the source code. https://github.com/pyscripter/FileSystemMonitor/blob/2dd27a0570ae2f839acb9de3bf67bb2247893784/Source/FileSystemMonitor.pas#L415C16-L415C41 All the thread does is wait on the I/O complection port using GetQueuedCompletionStatus. This function blocks until a change happens. The only polling that takes place is to check every 5 seconds, for deletion/rename of the monitored directories themselves, which are not reported by ReadDirectoryChanges. Folders can be attached to/detached from the completion port at any time, without any problem.
  3. pyscripter

    Correctly let python free a result

    For the benefit of anyone reading this thread, the most powerful way to allow your python script to create instances of a Delphi class (e.g. TEntry) is to create a wrapper: type TEntryClassWrapper = class(TPyClassWrapper<TEntry>) constructor CreateWith(APythonType: TPythonType; args, kwds: PPyObject); overload; override; end; { TEntryClassWrapper } constructor TEntryClassWrapper.CreateWith(APythonType: TPythonType; args, kwds: PPyObject); var _obj : PPyObject; begin if GetPythonEngine.PyArg_ParseTuple( args, 'O:CreteWith',@_obj ) <> 0 then begin Create(APythonType); DelphiObject := TEntry.Create(GetPythonEngine.PyObjectAsString(_obj)); end; end; You need to register and initialize the wrapper in your Form.Create: procedure TForm1.FormCreate(Sender: TObject); begin PyDelphiWrapper1.RegisterDelphiWrapper(TEntryClassWrapper).Initialize; end; and then in python: from spam import * entry = Entry('Test') print(entry.Name()) entry = None The Delphi TEntry class is exposed as the python type Entry in your python code.
  4. pyscripter

    Correctly let python free a result

    Not really. You can use the following ExecStrings overload procedure ExecStrings(strings: TStrings; locals, globals: PPyObject; const FileName: string = '<string>'); overload; providing your own globals and locals so that you do not mess up the python namespace. Please search in this forum. There was a discussion about this.
  5. pyscripter

    Correctly let python free a result

    TEntry = class(TObject) strict private FstrName: string; FclsStringList: TStringList; public constructor Create(strName: string); destructor Destory; function Name: string; end; Destroy misspelled and not declared with override. If you fix this TEntry gets destroyed. But the better way is: function TManager.GetNewEntry: TEntry; begin Result := TEntry.Create('Test'); end; and in python from spam import * entry = manager.GetNewEntry() print(entry.Name()) entry.__owned__ = True entry = None Explanation: When P4D wraps the result of GetNewEntry it does not know who owns the return value. The default is that Delphi does. But the ownership can be changed in python using the __owned__ property.
  6. pyscripter

    Correctly let python free a result

    Please search this forum for answers/discussion of this question.
  7. pyscripter

    Correctly let python free a result

    Could you please attach a zipped project instead?
  8. pyscripter

    Correctly let python free a result

    It will be called if you change your python script to: entry = manager.GetNewEntry() print(entry.Name()) entry = None
  9. Whilst there are many Delphi components for detecting changes to file system folders they suffer from serious limitations: typically they only allow you to monitor a single folder they do not support the monitoring of specific files they rely on the FindFirstChangeNotification API which gives no information about what has changed, requiring an inefficient search. I have created a new file system monitoring library that addresses the above limitations. Features: Easy to use, but also suitable for heavy duty monitoring Single unit with no external dependencies Allows monitoring folders and/or specific files Uses the ReadDirectoryChangesW API which provides information about what exactly was changed A single instance of the component can handle the monitoring of many folders and/or files Uses an I/O completion port for efficient handling of large numbers of requests A single thread handles all requests A different notification handler can be specified for each request You can have multiple handlers for each folder or file When you monitor folders you can specify whether you want to also monitor subfolders Installation: You do not need to install the library. Just download or clone the repo and add the source subdirectory to the Library path. Usage: procedure TForm1.FormCreate(Sender: TObject); begin // Create the IFileSystemMonitor interface FFileSystemMonitor := CreateFileSystemMonitor; // Monitor a directory FFileSystemMonitor.AddDirectory(TPath.GetTempPath, False, HandleChange); // Also monitor a specific file FFileSystemMonitor.AddFile('pathtoyourfile', HandleChange); end; procedure TForm1.HandleChange(Sender: TObject; const Path: string; ChangeType: TFileChangeType); begin with lvEventList.Items.Add do begin Caption := GetEnumName(TypeInfo(TFileChangeType), Integer(ChangeType)); SubItems.Add(Path); end; end; To stop monitoring a specific file or folder you use the following methods: function RemoveDirectory(const Directory: string; OnChange: TMonitorChangeHandler): Boolean; function RemoveFile(const FilePath: string; OnChange: TMonitorChangeHandler): Boolean;
  10. pyscripter

    Correctly let python free a result

    function TManager.GetNewEntry: PPyObject; begin // I want TEntry to be destroyed by python once it is no longer used Result := Form1.GetDelphiWrapper.Wrap(TEntry.Create('Test'), soOwned); Form1.GetPythonEngine.Py_DECREF(Result); end; In the code above Py_DECREF will destroy the TEntry instance immediately, You can confirm that by debugging and putting a brekpoint at TEntry.Destroy. Just remove the Py_DECREF statement. Explanation.: Wrap returns a python object with reference count of 1. When you decrease the reference count, it goes down to 0, and because the wrapped Delphi object is owned it gets destroyed The difference with clsManager := TManager.Create; pyManager := PyDelphiWrapper1.Wrap(clsManager, soReference); PythonModule1.SetVar( 'manager', pyManager ); PythonEngine1.ExecStrings( memo1.Lines ); PythonEngine1.Py_DecRef(pyManager); is that you call SetVar which increases the reference count. However the above code leaks clsManager. It does not get destroyed because you set the Ownership to soReference. Either change that or call clsManager.Free at the end. Conclusion: Python reference counting can be tricky. You should try to understand the rules behind reference counting. (e.g. Reference Counting in Python (tripod.com)) if you use the Python API directly. High level P4D modules (WrapDelphi and VarPython) to a large extent insulate you from that and ensure correct use of reference counting.
  11. pyscripter

    Stopping a P4D Python thread

    TPythonThread is a TThread descendent. But TThread.Terminate, does not stop threads. Your code needs to check the value of Terminated. Did you check Demo 33?https://github.com/pyscripter/python4delphi/blob/b6b63c7a2e94e027a52eac340d6fb38f084d5269/Demos/Demo33/SortThds.pas#L147C1-L158C5. This works in that case because the python code releases the GIL regularly (when you call swap). Alternatively you can expose to your python scripts a Delphi variable that the python scripts check at short intervals. In other words you have to engineer a way to stop the threads gracefully. The same applies to standard Delphi threads.
  12. pyscripter

    Can't print from Python script thread to Delphi main thread

    @Martybartfast Support for output redirection from sub-interpreters has been committed. So with the latest version you do need the above workaround.
  13. pyscripter

    Can't print from Python script thread to Delphi main thread

    @Martybartfast Actually there is an easy solution: Replace TPyThread.ExecuteWithPython with procedure TPyThread.ExecuteWithPython; // Run the script begin TPythonModule(PyEngine.IOPythonModule).MultInterpretersSupport := mmiPerInterpreterGIL; TPythonModule(PyEngine.IOPythonModule).InitializeForNewInterpreter; PyEngine.DoRedirectIO; PyEngine.ExecString(FScript); // Run Python script end; and printing should work.
  14. pyscripter

    Can't print from Python script thread to Delphi main thread

    Output redirection is not supported with emNewInterpreterOwnGIL. See other threads with a discussion of the limitations of that mode in this forum.
  15. From https://github.com/pyscripter/python4delphi/wiki/PythonThreads Why do the following inside the thread? GetPythonEngine.IO := PythonInputOutput1; // do these assignments go here, or before the ThreadPythonExec GetPythonEngine.FatalMsgDlg := FALSE; GetPythonEngine.FatalAbort := TRUE; GetPythonEngine.Py_FatalError := @MyFatalMessage;
×