Difference between revisions of "Using Python in Lazarus on Windows/Linux"

From Free Pascal wiki
Jump to navigationJump to search
Line 22: Line 22:
 
[[File:Python app MacOS.png]]
 
[[File:Python app MacOS.png]]
  
= P4D fork =
+
Code is modified Python4Delphi package. Compile and install the Lazarus package. You will see "Python" tab in IDE component pallette. What is changed since original Python4Delphi:
 
 
You need modified P4D package, see link to Github above.  
 
Compile and install the package. You must see "Python" tab appeared in component pallette.
 
What is changed:
 
  
 
* deleted all refs to units "..Delphi..", seems units aren't needed for Lazarus apps.
 
* deleted all refs to units "..Delphi..", seems units aren't needed for Lazarus apps.
 
* modifications to PythonEngine.pas, see lines with "//AT".
 
* modifications to PythonEngine.pas, see lines with "//AT".
* added support for Mac for ex. by replacing "ifdef linux" with "ifdef unix".
+
* added support for macOS, for ex by replacing "$ifdef linux" with "$ifdef unix".
  
 
= Files on Windows =
 
= Files on Windows =

Revision as of 08:17, 10 October 2017

Intro

I need to make app, cross platform, Win/Linux/Mac, which embeds Python engine. I tried Python4Delphi, it doesn't compile and work on Linux x64 and Mac. App must use: portable Python on Win, system Python on Linux, Python installer on Mac.

Resulting repo

Github repo: https://github.com/Alexey-T/Python-for-Lazarus

It has demo, which shows TEdit+TMemo as Python console, to input commands in Edit and show results in Memo. Special allowed first char "=" means to do "print(...)".

Screenshot on Ubuntu 14 x64:

Python app Linux.png

Screenshot on Windows 7 x64:

Python app Windows.png

Screenshot on macOS 10.8:

Python app MacOS.png

Code is modified Python4Delphi package. Compile and install the Lazarus package. You will see "Python" tab in IDE component pallette. What is changed since original Python4Delphi:

  • deleted all refs to units "..Delphi..", seems units aren't needed for Lazarus apps.
  • modifications to PythonEngine.pas, see lines with "//AT".
  • added support for macOS, for ex by replacing "$ifdef linux" with "$ifdef unix".

Files on Windows

On Windows you need to copy files to app folder. From "Sublime Text 3" installation for win, take Python files and copy them to app folder:

  • python33.dll
  • msvcr100.dll
  • python33.zip
  • .pyd files, to folder DLLs

Manifest on Windows: "appname.exe.manifest":

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
   <noInheritable/>
   <assemblyIdentity
       type="win32"
       name="DelphiApplication"
       version="1.0.0.0" 
       processorArchitecture="*"/>
   <dependency>
     <dependentAssembly>
       <assemblyIdentity type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*' />
     </dependentAssembly>
   </dependency>
   <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
     <security>
       <requestedPrivileges>
         <requestedExecutionLevel level='asInvoker' uiAccess='false' />
       </requestedPrivileges>
     </security>
   </trustInfo>
 </assembly>

Files on MacOS

OSX 10.8 doesn't have Python. User needs to install official Py 3.4 pack.

Full path to library must be set in code, I could not load it w/out path. (Maybe I can read some env-var, I didn't try.)

Code

Form

Put on form:

  • TPythonEngine
  • TPythonInputOutput
  • TCombobox (edConsole)
  • TMemo (memoConsole)

Properties 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 set "sys.path" for Win (remember, we use portable py for Win).
procedure TfmMain.PythonEngineAfterInit(Sender: TObject);
var
  dir: string;
begin
  {$ifdef windows}
  dir:= ExtractFilePath(Application.ExeName);
  Py_SetSysPath([
    dir + 'DLLs',
    dir + 'python33.zip'
    ]);
  {$endif}
end;

procedure Py_SetSysPath(const Dirs: array of string);
var
  Str: string;
  i: Integer;
begin
  Str:= '';
  for i:= 0 to Length(Dirs)-1 do
    Str:= Str + 'r"' + 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:
const
  cPyLibraryWindows = 'python33.dll';
  cPyLibraryLinux = 'libpython3.4m.so.1.0';
  cPyLibraryMac = '/Library/Frameworks/Python.framework/Versions/3.4/lib/libpython3.4.dylib';

procedure TfmMain.FormCreate(Sender: TObject);
var
  S: string;
begin
  S:=
    {$ifdef windows} cPyLibraryWindows {$endif}
    {$ifdef linux} cPyLibraryLinux {$endif}
    {$ifdef darwin} cPyLibraryMac {$endif} ;
  PythonEngine.DllPath:= ExtractFileDir(S);
  PythonEngine.DllName:= ExtractFileName(S);
  PythonEngine.LoadDll;
end;