0

I use D7 with Python4Delphi. After users have imported much of py-files, Python have all these modules cached. I need a way to reset Py engine. So that Py "forgets" all user-imported modules, and I have "clean" Python, w/out restarting the app. How to do it?

Prog1020
  • 4,530
  • 8
  • 31
  • 65
  • Hmm, good luck with that. I believe you have zero chance of success. Once Python is in your process, in my experience, it's there for good. – David Heffernan Jan 30 '14 at 18:02

2 Answers2

2

It should be sufficient to destroy and re-create the TPythonEngine object:

OriginalOwner := GetPythonEngine.Owner;
GetPythonEngine.Free;
TPythonEngine.Create(OriginalOwner);

Destroying it calls Py_Finalize, which frees all memory allocated by the Python DLL.

Or, if you're just using the Python API without the VCL wrappers, you can probably just call Py_NewInterpreter on your TPythonInterface object to get a fresh execution environment without necessarily discarding everything done before.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • In my experience this will not yield good results. Have you experienced success in booting Python out like that? – David Heffernan Jan 30 '14 at 18:39
  • @david inability to load new python instances – David Heffernan Jan 31 '14 at 07:05
  • @Rob Did you test it with TPythonModule, TPythonGuiInputOutput, are they reinited ok? I test myself later. – Prog1020 Jan 31 '14 at 14:50
  • Haven't tested anything, @Alextp. I don't have Delphi. I only read the documentation and looked at the source code. – Rob Kennedy Jan 31 '14 at 15:03
  • @Rob, sorry. I took demo05 from P4D, added button "Reset", and added ur code. I pressed "exec script", then "Reset", then "exec script", and got Access Violation at `function TPythonInterface.GetInitialized`. – Prog1020 Jan 31 '14 at 15:12
  • You're going to have to do some debugging. It looks like the DLL will only get loaded automatically when the component comes from a DFM resource; if it's created manually, you'll have to re-call `LoadDll` yourself before any Python API functions are valid. – Rob Kennedy Jan 31 '14 at 15:23
  • @Rob yes, some work needed, when I added after your code `GetPythonEngine.Initialize` I got exception "No python engine was created" inside `GetPythonEngine` – Prog1020 Jan 31 '14 at 15:38
  • 1
    @alextp My Python embedding experience is with the raw C API and not this Delphi wrapper. I have tried very hard to remove the Python engine from the process, and then bring it back. I failed. This is not to say that I am sure it cannot be done, just that I think you should be prepared for failure. The docs suggest that this should be possible, with some caveats: http://docs.python.org/2/c-api/init.html – David Heffernan Feb 01 '14 at 13:08
2

There is a demo showing you how to unload/reload python using P4D at https://github.com/pyscripter/python4delphi/tree/master/PythonForDelphi/Demos/Demo34. The key method that (re)creates the python components and (re)loads different versions of python is shown below:

procedure TForm1.CreatePythonComponents;
begin
  if cbPyVersions.ItemIndex <0 then begin
    ShowMessage('No Python version is selected');
    Exit;
  end;

  // Destroy P4D components
  FreeAndNil(PythonEngine1);
  FreeAndNil(PythonType1);
  FreeAndNil(PythonModule1);

  { TPythonEngine }
  PythonEngine1 := TPythonEngine.Create(Self);
  PyVersions[cbPyVersions.ItemIndex].AssignTo(PythonEngine1);

  PythonEngine1.IO := PythonGUIInputOutput1;

  { TPythonModule }
  PythonModule1 := TPythonModule.Create(Self);

  PythonModule1.Name := 'PythonModule1';
  PythonModule1.Engine := PythonEngine1;
  PythonModule1.ModuleName := 'spam';
  with PythonModule1.Errors.Add do begin
    Name := 'PointError';
    ErrorType := etClass;
  end;
  with PythonModule1.Errors.Add do begin
    Name := 'EBadPoint';
    ErrorType := etClass;
    ParentClass.Name := 'PointError';
  end;

  { TPythonType }
  PythonType1 := TPythonType.Create(Self);

  PythonType1.Name := 'PythonType1';
  PythonType1.Engine := PythonEngine1;
  PythonType1.OnInitialization := PythonType1Initialization;
  PythonType1.TypeName := 'Point';
  PythonType1.Prefix := 'Create';
  PythonType1.Services.Basic := [bsRepr,bsStr,bsGetAttrO,bsSetAttrO];
  PythonType1.TypeFlags :=
    [tpfHaveGetCharBuffer,tpfHaveSequenceIn,tpfHaveInplaceOps, 
   tpfHaveRichCompare,tpfHaveWeakRefs,tpfHaveIter,tpfHaveClass,tpfBaseType];
  PythonType1.Module := PythonModule1;

  PythonEngine1.LoadDll;
end;

The demo uses the unit PythonVersions to discover installed python versions.

PyScripter
  • 584
  • 5
  • 12