Using Python in Lazarus on Windows/Linux

From Free Pascal wiki
Jump to navigationJump to search

Intro

I need to make app, cross platform, Win/Linux, which embeds Python engine. I tried Python4Delphi, but it doesn't compile and work on Linux x64. Same app must run on Win and Linux, must use portable Python 3 on Win and system Python 3 on Linux.

Result

Links

Work on Ubuntu 14.04 x64

Python app Linux.png

Work on Windows7 x64

Python app Windows.png

Code

P4D

Package "p4dlaz.lpk": delete all refs to units "...Delphi...". (Maybe units aren't needed for Lazarus apps.) Make modifications to PythonEngine.pas, see lines with "//AT". Compile and use package. You must see "Python" tab appeared in component pallette.

Files

--

App form

Put on form: TPythonEngine, TPythonInputOutput, set such props of PythonEngine:

  • AutoLoad=False
  • DllName empty
  • DllPath empty
  • FatalAbort=False
  • InitScript="import sys; print('Python', sys.version)"
  • IO=PythonInputOutput1
  • PyFlags=[pfIgnoreEnvironmentFlag]
  • UseLastKnownVersion=False

Event handlers

  • PythonEngine.OnAfterInit: must add paths to "sys.path". Must do only for Windows, for portable Python, don't do for Linux. I add paths: dir+'DLLs', dir+'python33.zip', dir+'Py' (dir is ExtractFilePath(Application.ExeName)).
 procedure TfmMain.PythonEngineAfterInit(Sender: TObject);
 var
   SDir, S1, S2, S3: string;
 begin
   {$ifdef windows}
   SDir:= ExtractFilePath(Application.ExeName);
   S1:= SDir + 'DLLs';
   S2:= SDir + 'python33.zip';
   S3:= SDir + 'Py';
   Py_SetSysPath([S1, S2, S3]);
   {$endif}
 end;
 procedure Py_SetSysPath(const Dirs: array of string);
 var
   Str: AnsiString;
   i: Integer;
 begin
   Str:= ;
   for i:= 0 to Length(Dirs)-1 do
     Str:= Str + SWideStringToPythonString(Dirs[i]) + ',';
   Str:= Format('sys.path = [%s]', [Str]);
   GetPythonEngine.ExecString(Str);
 end;
  • PythonInputOutput.OnSendData, OnSendUniData:
 procedure TfmMain.PythonInputOutput1SendData(Sender: TObject;
   const Data: AnsiString);
 begin
   memoConsole.Lines.Add(Data);
 end;
 procedure TfmMain.PythonInputOutput1SendUniData(Sender: TObject;
   const Data: UnicodeString);
 begin
   memoConsole.Lines.Add(Data);
 end;
  • edConsole.OnKeyPress:
 procedure TfmMain.edConsoleKeyPress(Sender: TObject; var Key: char);
 var
   Str: string;
 begin
   if Key=#13 then
   begin
     Str:= edConsole.Text;
 
     //support entering "=some cmd"
     if (Str<>) and (Str[1]='=') then
       Str:= 'print('+Copy(Str, 2, MaxInt) + ')';
 
     memoConsole.Lines.Add('>>> '+Str);
     edConsole.Text:= ;
     edConsole.Items.Insert(0, Str);
     try
       GetPythonEngine.ExecString(Str);
     except
     end;
   end;
 end;
  • main form OnCreate:
 procedure TfmMain.FormCreate(Sender: TObject);
 begin
   {$ifdef windows}
   PythonEngine.DllName:= 'python33.dll';
   {$endif}
   {$ifdef linux}
   PythonEngine.DllName:= 'libpython3.4m.so.1.0';
   {$endif}
   PythonEngine.LoadDll;
 end;