diff --git a/Demos/Demo06/Unit1.dfm b/Demos/Demo06/Unit1.dfm
index 19538b07..c3a31c64 100644
--- a/Demos/Demo06/Unit1.dfm
+++ b/Demos/Demo06/Unit1.dfm
@@ -10,8 +10,6 @@ object Form1: TForm1
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
- OldCreateOrder = True
- PixelsPerInch = 96
TextHeight = 13
object Splitter1: TSplitter
Left = 0
@@ -20,7 +18,6 @@ object Form1: TForm1
Height = 3
Cursor = crVSplit
Align = alTop
- ExplicitWidth = 536
end
object Memo1: TMemo
Left = 0
diff --git a/Demos/Demo06/Unit1.pas b/Demos/Demo06/Unit1.pas
index df25433d..cf6e6faf 100644
--- a/Demos/Demo06/Unit1.pas
+++ b/Demos/Demo06/Unit1.pas
@@ -42,7 +42,7 @@ TForm1 = class(TForm)
end;
PyPointRec = record
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
po_x : Integer;
po_y : Integer;
@@ -151,6 +151,8 @@ procedure PyPoint_dealloc(obj : PPyObject); cdecl;
// object.value
// object.method(args)
function PyPoint_getattr(obj : PPyObject; key : PAnsiChar) : PPyObject; cdecl;
+var
+ Py_Key: PPyObject;
begin
with GetPythonEngine, PPyPoint(obj)^ do
begin
@@ -163,9 +165,14 @@ function PyPoint_getattr(obj : PPyObject; key : PAnsiChar) : PPyObject; cdecl;
else
begin
// Else check for a method
- Result := PyObject_GenericGetAttr(obj, PyUnicodeFromString(key));
- if not Assigned(Result) then
- PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Unknown attribute "%s"',[key]))));
+ Py_Key := PyUnicodeFromString(key);
+ try
+ Result := PyObject_GenericGetAttr(obj, Py_key);
+ if not Assigned(Result) then
+ PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Unknown attribute "%s"',[key]))));
+ finally
+ Py_DECREF(Py_Key);
+ end;
end;
end;
end;
diff --git a/Demos/Demo07/Unit1.dfm b/Demos/Demo07/Unit1.dfm
index 51b77e56..500ec0e6 100644
--- a/Demos/Demo07/Unit1.dfm
+++ b/Demos/Demo07/Unit1.dfm
@@ -13,8 +13,6 @@ object Form1: TForm1
Font.Name = 'MS Sans Serif'
Font.Pitch = fpVariable
Font.Style = []
- OldCreateOrder = True
- PixelsPerInch = 96
TextHeight = 13
object Splitter1: TSplitter
Left = 0
@@ -23,7 +21,6 @@ object Form1: TForm1
Height = 3
Cursor = crVSplit
Align = alTop
- ExplicitWidth = 536
end
object Memo1: TMemo
Left = 0
diff --git a/Demos/Demo07/Unit1.pas b/Demos/Demo07/Unit1.pas
index 012507af..3514b6a3 100644
--- a/Demos/Demo07/Unit1.pas
+++ b/Demos/Demo07/Unit1.pas
@@ -48,7 +48,7 @@ TForm1 = class(TForm)
end;
PyPointRec = record
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
po_x : Integer;
po_y : Integer;
@@ -191,6 +191,8 @@ procedure PyPoint_dealloc(obj : PPyObject); cdecl;
// object.value
// object.method(args)
function PyPoint_getattr(obj : PPyObject; key : PAnsiChar) : PPyObject; cdecl;
+var
+ Py_Key: PPyObject;
begin
with GetPythonEngine, PPyPoint(obj)^ do
begin
@@ -203,9 +205,14 @@ function PyPoint_getattr(obj : PPyObject; key : PAnsiChar) : PPyObject; cdecl;
else
begin
// Else check for a method
- Result := PyObject_GenericGetAttr(obj, PyUnicodeFromString(key));
- if not Assigned(Result) then
- PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown attribute "%s"',[key]))));
+ Py_Key := PyUnicodeFromString(key);
+ try
+ Result := PyObject_GenericGetAttr(obj, Py_Key);
+ if not Assigned(Result) then
+ PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Unknown attribute "%s"',[key]))));
+ finally
+ Py_DECREF(Py_Key);
+ end;
end;
end;
end;
@@ -226,7 +233,7 @@ function PyPoint_setattrfunc(obj : PPyObject; key : PAnsiChar; value : PPyObjec
Result := 0;
end
else
- PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Attribute "%s" needs an integer',[key]))));
+ PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Attribute "%s" needs an integer',[key]))));
// Check for attribute y
end else if key = 'y' then begin
if PyLong_Check(value) then
@@ -235,9 +242,9 @@ function PyPoint_setattrfunc(obj : PPyObject; key : PAnsiChar; value : PPyObjec
Result := 0;
end
else
- PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Attribute "%s" needs an integer',[key]))));
+ PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Attribute "%s" needs an integer',[key]))));
end else
- PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown attribute "%s"',[key]))));
+ PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Unknown attribute "%s"',[key]))));
end;
end;
diff --git a/Demos/Demo11/ThSort.dfm b/Demos/Demo11/ThSort.dfm
index 2f5f2710..f0c50c0d 100644
--- a/Demos/Demo11/ThSort.dfm
+++ b/Demos/Demo11/ThSort.dfm
@@ -165,7 +165,6 @@ object ThreadSortForm: TThreadSortForm
OnClick = SaveBtnClick
end
object PythonEngine1: TPythonEngine
- InitThreads = True
RedirectIO = False
Left = 16
Top = 32
diff --git a/Demos/Demo29/Unit1.dfm b/Demos/Demo29/Unit1.dfm
index c149398f..c151b511 100644
--- a/Demos/Demo29/Unit1.dfm
+++ b/Demos/Demo29/Unit1.dfm
@@ -10,11 +10,9 @@ object Form1: TForm1
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
- OldCreateOrder = False
DesignSize = (
668
701)
- PixelsPerInch = 96
TextHeight = 13
object Image1: TImage
Left = 8
diff --git a/Demos/Demo29/Unit1.pas b/Demos/Demo29/Unit1.pas
index 025c5cd1..b969d646 100644
--- a/Demos/Demo29/Unit1.pas
+++ b/Demos/Demo29/Unit1.pas
@@ -86,7 +86,7 @@ procedure TForm1.Button2Click(Sender: TObject);
with GetPythonEngine do begin
pargs := MakePyTuple([ExtractPythonObjectFrom(_im)]);
try
- presult := PyEval_CallObjectWithKeywords(
+ presult := PyObject_Call(
ExtractPythonObjectFrom(MainModule.ImageToBytes), pargs, nil);
try
if PyBytes_AsStringAndSize(presult, P, Len) < 0 then begin
diff --git a/Demos/Demo33/ThSort.dfm b/Demos/Demo33/ThSort.dfm
index fa04fa71..3b4c41e6 100644
--- a/Demos/Demo33/ThSort.dfm
+++ b/Demos/Demo33/ThSort.dfm
@@ -171,7 +171,6 @@ object ThreadSortForm: TThreadSortForm
OnClick = StopBtnClick
end
object PythonEngine1: TPythonEngine
- InitThreads = True
PyFlags = [pfDebug, pfInteractive, pfVerbose]
RedirectIO = False
Left = 16
diff --git a/Demos/Demo36/ParallelPython.dpr b/Demos/Demo36/ParallelPython.dpr
index 00883f7a..abcfb0fa 100644
--- a/Demos/Demo36/ParallelPython.dpr
+++ b/Demos/Demo36/ParallelPython.dpr
@@ -109,6 +109,7 @@ begin
WriteLn('Elapsed ms: ' + SW.ElapsedMilliseconds.ToString);
WriteLn;
finally
+ Sleep(1000); // allow some time for the threads to terminate
DestroyEngine;
end;
except
diff --git a/Demos/FPC/Demo06/Unit1.pas b/Demos/FPC/Demo06/Unit1.pas
index 34c8a901..75e705bb 100644
--- a/Demos/FPC/Demo06/Unit1.pas
+++ b/Demos/FPC/Demo06/Unit1.pas
@@ -47,7 +47,7 @@ TForm1 = class(TForm)
end;
PyPointRec = record
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
po_x : Integer;
po_y : Integer;
diff --git a/Demos/FPC/Demo35/project1.lpi b/Demos/FPC/Demo35/project1.lpi
new file mode 100644
index 00000000..ff71647f
--- /dev/null
+++ b/Demos/FPC/Demo35/project1.lpi
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
diff --git a/Demos/FPC/Demo35/project1.lpr b/Demos/FPC/Demo35/project1.lpr
new file mode 100644
index 00000000..bb83f928
--- /dev/null
+++ b/Demos/FPC/Demo35/project1.lpr
@@ -0,0 +1,148 @@
+program project1;
+
+{$mode delphi}{$H+}
+
+uses
+ {$IFDEF UNIX}
+ cthreads,
+ {$ENDIF}
+ Classes, SysUtils, CustApp,
+ { you can add units after this }
+ Variants,
+ PythonEngine,
+ VarPyth,
+ stopwatch;
+
+var
+ PyEngine: TPythonEngine;
+
+procedure CreatePyEngine;
+begin
+ MaskFPUExceptions(True, True);
+ PyEngine := TPythonEngine.Create(nil);
+ PyEngine.Name := 'PythonEngine';
+ PyEngine.UseLastKnownVersion := False;
+ PyEngine.RegVersion:= '3.12';
+ PyEngine.DllName:= 'python312.dll';
+ PyEngine.LoadDll;
+end;
+
+procedure DestroyEngine;
+begin
+ PyEngine.Free;
+end;
+
+const
+ N = 100000;
+
+type
+ PIntArray = ^TIntArray;
+ {$IFDEF MSWINDOWS}
+ TIntArray = array[0..N - 1] of Integer;
+ {$ELSE}
+ TIntArray = array[0..N - 1] of NativeInt;
+ {$ENDIF}
+
+ { TBufferProtocol }
+
+ TBufferProtocol = class(TCustomApplication)
+ protected
+ procedure DoRun; override;
+ public
+ constructor Create(TheOwner: TComponent); override;
+ destructor Destroy; override;
+ end;
+
+{ TBufferProtocol }
+
+procedure TBufferProtocol.DoRun;
+var
+ SW: TStopwatch;
+ Sum: Int64;
+ np: Variant;
+ arr: Variant;
+ np_arr: PPyObject;
+ PyBuffer: Py_buffer;
+ V: Variant;
+ I: Integer;
+ Count: Integer;
+ ArrItem: Variant;
+begin
+ try
+ CreatePyEngine;
+ try
+ // Import numpy and create an array
+ np := Import('numpy');
+ arr := np.&array(BuiltinModule.range(N));
+
+ // This is the slow way to iterate the array
+ WriteLn('Lazy but slow:');
+ SW := TStopwatch.StartNew;
+ Sum := 0;
+ Count := VarPythonToVariant(arr.Length);
+ for I := 0 to Count - 1 do
+ begin
+ ArrItem := BuiltinModule.int(arr.GetItem(I));
+ Sum := Sum + Int64(VarPythonToVariant(ArrItem));
+ end;
+
+ //for V in VarPyIterate(arr) do
+ // Sum := Sum + Int64(VarPythonToVariant(BuiltinModule.int(V)));
+ SW.Stop;
+ WriteLn(Format('Sum from 0 to %d = %d', [N, Sum]));
+ WriteLn('Elapsed ms: ' + SW.ElapsedMilliseconds.ToString);
+ WriteLn;
+
+ WriteLn('Using Py_Buffer:');
+ SW := TStopwatch.StartNew;
+ np_arr := ExtractPythonObjectFrom(arr);
+ PyEngine.PyObject_GetBuffer(np_arr, @PyBuffer, PyBUF_CONTIG);
+ PyEngine.CheckError;
+ try
+ Sum := 0;
+ for I := 0 to N - 1 do
+ Sum := Sum + PIntArray(PyBuffer.buf)^[I];
+ SW.Stop;
+ WriteLn(Format('Sum from 0 to %d = %d', [N, Sum]));
+ finally
+ PyEngine.PyBuffer_Release(@PyBuffer);
+ end;
+ WriteLn('Elapsed ms: ' + SW.ElapsedMilliseconds.ToString);
+ WriteLn;
+
+ // test write access
+ PIntArray(PyBuffer.buf)^[0] := 999;
+ if VarPythonToVariant(BuiltinModule.int(arr.GetItem(0))) = 999 then
+ WriteLn('Successfully modified the numpy array using Py_buffer');
+ finally
+ DestroyEngine;
+ end;
+ except
+ on E: Exception do
+ Writeln(E.ClassName, ': ', E.Message);
+ end;
+ Readln;
+ // stop program loop
+ Terminate;
+end;
+
+constructor TBufferProtocol.Create(TheOwner: TComponent);
+begin
+ inherited Create(TheOwner);
+ StopOnException:=True;
+end;
+
+destructor TBufferProtocol.Destroy;
+begin
+ inherited Destroy;
+end;
+
+var
+ Application: TBufferProtocol;
+begin
+ Application:=TBufferProtocol.Create(nil);
+ Application.Title:='BufferProtocol';
+ Application.Run;
+ Application.Free;
+end.
+
diff --git a/Demos/FPC/Demo35/stopwatch.pas b/Demos/FPC/Demo35/stopwatch.pas
new file mode 100644
index 00000000..d2ef8baf
--- /dev/null
+++ b/Demos/FPC/Demo35/stopwatch.pas
@@ -0,0 +1,191 @@
+{ High frequency stop watch implemntation.
+ Copyright (c) 2012 by Inoussa OUEDRAOGO
+
+ This source code is distributed under the Library GNU General Public License
+ with the following modification:
+
+ - object files and libraries linked into an application may be
+ distributed without source code.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+{$IFDEF FPC}
+ {$mode objfpc}{$H+}
+ {$modeswitch advancedrecords}
+{$ENDIF}
+
+{$IFDEF MSWINDOWS}
+ {$IFNDEF WINDOWS}
+ {$DEFINE WINDOWS}
+ {$ENDIF WINDOWS}
+{$ENDIF MSWINDOWS}
+
+unit stopwatch;
+
+interface
+uses
+ SysUtils
+ {$IFDEF LINUX}
+ ,unixtype, linux
+ {$ENDIF LINUX}
+ ;
+
+type
+
+ { TStopWatch }
+
+ TStopWatch = record
+ private
+ const
+ C_THOUSAND = 1000;
+ C_MILLION = C_THOUSAND * C_THOUSAND;
+ C_BILLION = C_THOUSAND * C_THOUSAND * C_THOUSAND;
+ TicksPerNanoSecond = 100;
+ TicksPerMilliSecond = 10000;
+ TicksPerSecond = C_BILLION div 100;
+ Type
+ TBaseMesure =
+ {$IFDEF WINDOWS}
+ Int64;
+ {$ENDIF WINDOWS}
+ {$IFDEF LINUX}
+ TTimeSpec;
+ {$ENDIF LINUX}
+ strict private
+ class var FFrequency : Int64;
+ class var FIsHighResolution : Boolean;
+ strict private
+ FElapsed : Int64;
+ FRunning : Boolean;
+ FStartPosition : TBaseMesure;
+ strict private
+ procedure CheckInitialization();inline;
+ function GetElapsedMilliseconds: Int64;
+ function GetElapsedTicks: Int64;
+ public
+ class function Create() : TStopWatch;static;
+ class function StartNew() : TStopWatch;static;
+ class property Frequency : Int64 read FFrequency;
+ class property IsHighResolution : Boolean read FIsHighResolution;
+ procedure Reset();
+ procedure Start();
+ procedure Stop();
+ property ElapsedMilliseconds : Int64 read GetElapsedMilliseconds;
+ property ElapsedTicks : Int64 read GetElapsedTicks;
+ property IsRunning : Boolean read FRunning;
+ end;
+
+resourcestring
+ sStopWatchNotInitialized = 'The StopWatch is not initialized.';
+
+implementation
+{$IFDEF WINDOWS}
+uses
+ Windows;
+{$ENDIF WINDOWS}
+
+{ TStopWatch }
+
+class function TStopWatch.Create(): TStopWatch;
+{$IFDEF LINUX}
+var
+ r : TBaseMesure;
+{$ENDIF LINUX}
+begin
+ if (FFrequency = 0) then begin
+{$IFDEF WINDOWS}
+ FIsHighResolution := QueryPerformanceFrequency(FFrequency);
+{$ENDIF WINDOWS}
+{$IFDEF LINUX}
+ FIsHighResolution := (clock_getres(CLOCK_MONOTONIC,@r) = 0);
+ FIsHighResolution := FIsHighResolution and (r.tv_nsec <> 0);
+ if (r.tv_nsec <> 0) then
+ FFrequency := C_BILLION div r.tv_nsec;
+{$ENDIF LINUX}
+ end;
+ FillChar(Result,SizeOf(Result),0);
+end;
+
+class function TStopWatch.StartNew() : TStopWatch;
+begin
+ Result := TStopWatch.Create();
+ Result.Start();
+end;
+
+procedure TStopWatch.CheckInitialization();
+begin
+ if (FFrequency = 0) then
+ raise Exception.Create(sStopWatchNotInitialized);
+end;
+
+function TStopWatch.GetElapsedMilliseconds: Int64;
+begin
+ {$IFDEF WINDOWS}
+ Result := ElapsedTicks * TicksPerMilliSecond;
+ {$ENDIF WINDOWS}
+ {$IFDEF LINUX}
+ Result := FElapsed div C_MILLION;
+ {$ENDIF LINUX}
+end;
+
+function TStopWatch.GetElapsedTicks: Int64;
+begin
+ CheckInitialization();
+{$IFDEF WINDOWS}
+ Result := (FElapsed * TicksPerSecond) div FFrequency;
+{$ENDIF WINDOWS}
+{$IFDEF LINUX}
+ Result := FElapsed div TicksPerNanoSecond;
+{$ENDIF LINUX}
+end;
+
+procedure TStopWatch.Reset();
+begin
+ Stop();
+ FElapsed := 0;
+ FillChar(FStartPosition,SizeOf(FStartPosition),0);
+end;
+
+procedure TStopWatch.Start();
+begin
+ if FRunning then
+ exit;
+ FRunning := True;
+{$IFDEF WINDOWS}
+ QueryPerformanceCounter(FStartPosition);
+{$ENDIF WINDOWS}
+{$IFDEF LINUX}
+ clock_gettime(CLOCK_MONOTONIC,@FStartPosition);
+{$ENDIF LINUX}
+end;
+
+procedure TStopWatch.Stop();
+var
+ locEnd : TBaseMesure;
+ s, n : Int64;
+begin
+ if not FRunning then
+ exit;
+ FRunning := False;
+{$IFDEF WINDOWS}
+ QueryPerformanceCounter(locEnd);
+ FElapsed := FElapsed + (UInt64(locEnd) - UInt64(FStartPosition));
+{$ENDIF WINDOWS}
+{$IFDEF LINUX}
+ clock_gettime(CLOCK_MONOTONIC,@locEnd);
+ if (locEnd.tv_nsec < FStartPosition.tv_nsec) then begin
+ s := locEnd.tv_sec - FStartPosition.tv_sec - 1;
+ n := C_BILLION + locEnd.tv_nsec - FStartPosition.tv_nsec;
+ end else begin
+ s := locEnd.tv_sec - FStartPosition.tv_sec;
+ n := locEnd.tv_nsec - FStartPosition.tv_nsec;
+ end;
+ FElapsed := FElapsed + (s * C_BILLION) + n;
+{$ENDIF LINUX}
+end;
+
+end.
diff --git a/Modules/DelphiVCL/TestVCL.py b/Modules/DelphiVCL/TestVCL.py
index 2641d390..deae197c 100644
--- a/Modules/DelphiVCL/TestVCL.py
+++ b/Modules/DelphiVCL/TestVCL.py
@@ -40,6 +40,7 @@ def main():
f.Show()
FreeConsole()
Application.Run()
+ f.Free()
main()
diff --git a/Modules/DemoModule/InterpreterExecutor.py b/Modules/DemoModule/InterpreterExecutor.py
new file mode 100644
index 00000000..97cca2ab
--- /dev/null
+++ b/Modules/DemoModule/InterpreterExecutor.py
@@ -0,0 +1,35 @@
+#-------------------------------------------------------------------------------
+# Name: InterpreterExecutor.py
+# Purpose: Showcases the use of extension modules created with Delphi
+# with the new in Python 3.14 InterpreterPoolExecutor
+# You need python 3.14 to run this demo
+# It uses the support module prime_utils which imports
+# the delphi created extension module.
+# Note that each interpreters has its own GIL and
+# they are all running in parallel.
+#-------------------------------------------------------------------------------
+
+from concurrent.futures import InterpreterPoolExecutor
+from prime_utils import count_primes_in_range
+import time
+
+def count_primes(max_num, num_interpreters=4):
+ chunk_size = max_num // num_interpreters
+ ranges = [(i, min(i + chunk_size - 1, max_num)) for i in range(2, max_num + 1, chunk_size)]
+ print(ranges)
+
+ total = 0
+ with InterpreterPoolExecutor(max_workers=num_interpreters) as executor:
+ results = executor.map(count_primes_in_range, ranges)
+ total = sum(results)
+
+ return total
+
+if __name__ == "__main__":
+ max_number = 1_000_000
+ start_time = time.time()
+ prime_count = count_primes(max_number)
+ end_time = time.time()
+
+ print(f"Count of prime numbers up to {max_number}: {prime_count}")
+ print(f"Time taken: {end_time - start_time:.2f} seconds")
\ No newline at end of file
diff --git a/Modules/DemoModule/prime_utils.py b/Modules/DemoModule/prime_utils.py
new file mode 100644
index 00000000..29abdea3
--- /dev/null
+++ b/Modules/DemoModule/prime_utils.py
@@ -0,0 +1,5 @@
+# prime_utils.py
+from DemoModule import is_prime
+
+def count_primes_in_range(arange):
+ return sum(1 for n in range(arange[0], arange[1] + 1) if is_prime(n))
diff --git a/Modules/DemoModule/uMain.pas b/Modules/DemoModule/uMain.pas
index 89ef3d22..922ef62e 100644
--- a/Modules/DemoModule/uMain.pas
+++ b/Modules/DemoModule/uMain.pas
@@ -7,13 +7,14 @@ interface
function PyInit_DemoModule: PPyObject; cdecl;
implementation
-Uses
+uses
+ Winapi.Windows,
System.Math,
WrapDelphi;
var
- gEngine : TPythonEngine;
- gModule : TPythonModule;
+ gEngine : TPythonEngine = nil;
+ gModule : TPythonModule = nil;
function IsPrime(x: Integer): Boolean;
// Naive implementation. It is just a demo
@@ -46,10 +47,10 @@ function delphi_is_prime(self, args : PPyObject) : PPyObject; cdecl;
function PyInit_DemoModule: PPyObject;
begin
+ if not Assigned(gEngine) then
try
gEngine := TPythonEngine.Create(nil);
gEngine.AutoFinalize := False;
- gEngine.UseLastKnownVersion := False;
gEngine.UseLastKnownVersion := True;
gModule := TPythonModule.Create(nil);
@@ -57,12 +58,18 @@ function PyInit_DemoModule: PPyObject;
gModule.ModuleName := 'DemoModule';
gModule.AddMethod('is_prime', delphi_is_prime, 'is_prime(n) -> bool' );
+ // We need to set this so that the module is not created by Initialzize
+ gModule.IsExtensionModule := True;
+ gModule.MultInterpretersSupport := mmiPerInterpreterGIL;
+
gEngine.LoadDllInExtensionModule;
except
+ Exit(nil);
end;
- Result := gModule.Module;
-end;
+ // The python import machinery will create the python module from ModuleDef
+ Result := gEngine.PyModuleDef_Init(@gModule.ModuleDef);
+end;
initialization
finalization
diff --git a/Modules/RttiModule/uMain.pas b/Modules/RttiModule/uMain.pas
index 5afc2b19..38b5be84 100644
--- a/Modules/RttiModule/uMain.pas
+++ b/Modules/RttiModule/uMain.pas
@@ -17,6 +17,7 @@ implementation
TDelphiFunctions = class
public
class function is_prime(const N: Integer): Boolean; static;
+ class procedure AfterModuleInit(Sender: TObject);
end;
var
@@ -25,35 +26,37 @@ TDelphiFunctions = class
gDelphiWrapper : TPyDelphiWrapper;
DelphiFunctions: TDelphiFunctions;
-
-
function PyInit_DemoModule: PPyObject;
-var
- Py : PPyObject;
begin
+ if not Assigned(gEngine) then
try
gEngine := TPythonEngine.Create(nil);
gEngine.AutoFinalize := False;
- gEngine.UseLastKnownVersion := False;
- // Adapt to the desired python version
- gEngine.RegVersion := '3.8';
- gEngine.DllName := 'python38.dll';
+ gEngine.UseLastKnownVersion := True;
+ gDelphiWrapper := TPyDelphiWrapper.Create(nil);
+ gDelphiWrapper.Engine := gEngine;
+
+ // !!It is important that the extension module is the last
+ // Engine client created
gModule := TPythonModule.Create(nil);
gModule.Engine := gEngine;
gModule.ModuleName := 'DemoModule';
- gDelphiWrapper := TPyDelphiWrapper.Create(nil);
- gDelphiWrapper.Engine := gEngine;
+ // Set IsExtensionModule so that the module is not created by Initialzize
+ gModule.IsExtensionModule := True;
+ gModule.MultInterpretersSupport := mmiPerInterpreterGIL;
+ gModule.OnAfterInitialization := TDelphiFunctions.AfterModuleInit;
+
gDelphiWrapper.Module := gModule;
- gEngine.LoadDll;
- Py := gDelphiWrapper.Wrap(DelphiFunctions, TObjectOwnership.soReference);
- gModule.SetVar('delphi_funcs', Py);
- gEngine.Py_DecRef(Py);
+ gEngine.LoadDllInExtensionModule;
except
+ Exit(nil);
end;
- Result := gModule.Module;
+
+ // The python import machinery will create the python module from ModuleDef
+ Result := gEngine.PyModuleDef_Init(@gModule.ModuleDef);
end;
{ TTestRttiAccess }
@@ -61,6 +64,15 @@ function PyInit_DemoModule: PPyObject;
{ TDelphiFunctions }
+class procedure TDelphiFunctions.AfterModuleInit(Sender: TObject);
+var
+ Py : PPyObject;
+begin
+ Py := gDelphiWrapper.Wrap(DelphiFunctions, TObjectOwnership.soReference);
+ gModule.SetVar('delphi_funcs', Py);
+ gEngine.Py_DecRef(Py);
+end;
+
class function TDelphiFunctions.is_prime(const N: Integer): Boolean;
// Naive implementation. It is just a demo...
begin
diff --git a/Packages/Delphi/Delphi 10.4+/Python.dproj b/Packages/Delphi/Delphi 10.4+/Python.dproj
index c41368d4..568730b8 100644
--- a/Packages/Delphi/Delphi 10.4+/Python.dproj
+++ b/Packages/Delphi/Delphi 10.4+/Python.dproj
@@ -7,8 +7,9 @@
Python.dpk
Win32
{018AAA56-F5BD-4A04-BCCA-A0043EAAA5CE}
- 19.5
- 168083
+ 20.1
+ 693395
+ Python
true
@@ -54,6 +55,12 @@
true
true
+
+ true
+ Cfg_1
+ true
+ true
+
true
Cfg_1
@@ -88,7 +95,7 @@
..\..\..\lib\$(Platform)\$(Config)
Python4Delphi - Run-time Engine Package
00400000
- Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;DUnitX.Loggers.GUI;Winapi;System.Win;$(DCC_Namespace)
+ System;Xml;Data;Datasnap;Web;Soap;DUnitX.Loggers.GUI;Winapi;System.Win;$(DCC_Namespace)
$(Auto)
true
true
@@ -109,11 +116,11 @@
Debug
- CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers;ITSAppUsesNonExemptEncryption=false
+ CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing the Bluetooth interface
Debug
- CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers;ITSAppUsesNonExemptEncryption=false
+ CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing the Bluetooth interface
Debug
@@ -136,6 +143,9 @@
1
package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
+
+ Debug
+
true
CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
@@ -204,13 +214,14 @@
True
True
+ True
+ True
True
True
True
True
True
- False
- False
+ False
12
diff --git a/Packages/Delphi/Delphi 10.4+/PythonFmx.dproj b/Packages/Delphi/Delphi 10.4+/PythonFmx.dproj
index 224e44cc..e45231c0 100644
--- a/Packages/Delphi/Delphi 10.4+/PythonFmx.dproj
+++ b/Packages/Delphi/Delphi 10.4+/PythonFmx.dproj
@@ -7,8 +7,9 @@
PythonFmx.dpk
Win32
{513BF750-373D-4C95-A672-78CA8DDF3F63}
- 19.5
- 167955
+ 20.1
+ 693395
+ PythonFmx
true
@@ -59,9 +60,14 @@
Base
true
+
+ true
+ Cfg_2
+ true
+ true
+
PythonFmx
- All
..\..\..\lib\$(Platform)\$(Config)
Python4Delphi - Run-time Engine Package for FMX
.\$(Platform)\$(Config)
@@ -87,11 +93,11 @@
Debug
- CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers;ITSAppUsesNonExemptEncryption=false
+ CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing the Bluetooth interface
Debug
- CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers;ITSAppUsesNonExemptEncryption=false
+ CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing the Bluetooth interface
Debug
@@ -127,6 +133,9 @@
false
0
+
+ Debug
+
MainSource
@@ -185,13 +194,14 @@
True
True
- False
+ True
+ True
+ True
True
True
True
True
- False
- False
+ False
12
diff --git a/Packages/Delphi/Delphi 10.4+/PythonFmxLinux.dpk b/Packages/Delphi/Delphi 10.4+/PythonFmxLinux.dpk
deleted file mode 100644
index 9525324e..00000000
--- a/Packages/Delphi/Delphi 10.4+/PythonFmxLinux.dpk
+++ /dev/null
@@ -1,63 +0,0 @@
-package PythonFmxLinux;
-
-{$R *.res}
-{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
-{$ALIGN 8}
-{$ASSERTIONS ON}
-{$BOOLEVAL OFF}
-{$DEBUGINFO OFF}
-{$EXTENDEDSYNTAX ON}
-{$IMPORTEDDATA ON}
-{$IOCHECKS ON}
-{$LOCALSYMBOLS OFF}
-{$LONGSTRINGS ON}
-{$OPENSTRINGS ON}
-{$OPTIMIZATION ON}
-{$OVERFLOWCHECKS OFF}
-{$RANGECHECKS OFF}
-{$REFERENCEINFO OFF}
-{$SAFEDIVIDE OFF}
-{$STACKFRAMES OFF}
-{$TYPEDADDRESS OFF}
-{$VARSTRINGCHECKS ON}
-{$WRITEABLECONST OFF}
-{$MINENUMSIZE 1}
-{$DEFINE RELEASE}
-{$ENDIF IMPLICITBUILDING}
-{$DESCRIPTION 'Python4Delphi - Run-time Engine Package for FMXLinux'}
-{$LIBSUFFIX AUTO}
-{$RUNONLY}
-{$IMPLICITBUILD ON}
-
-requires
- rtl,
- python,
- fmx;
-
-contains
- FMX.PythonGUIInputOutput in '..\..\..\Source\fmx\FMX.PythonGUIInputOutput.pas',
- WrapDelphiFmx in '..\..\..\Source\fmx\WrapDelphiFmx.pas',
- WrapFmxActnList in '..\..\..\Source\fmx\WrapFmxActnList.pas',
- WrapFmxColors in '..\..\..\Source\fmx\WrapFmxColors.pas',
- WrapFmxComCtrls in '..\..\..\Source\fmx\WrapFmxComCtrls.pas',
- WrapFmxControls in '..\..\..\Source\fmx\WrapFmxControls.pas',
- WrapFmxDialogs in '..\..\..\Source\fmx\WrapFmxDialogs.pas',
- WrapFmxEdit in '..\..\..\Source\fmx\WrapFmxEdit.pas',
- WrapFmxForms in '..\..\..\Source\fmx\WrapFmxForms.pas',
- WrapFmxGrids in '..\..\..\Source\fmx\WrapFmxGrids.pas',
- WrapFmxLayouts in '..\..\..\Source\fmx\WrapFmxLayouts.pas',
- WrapFmxListBox in '..\..\..\Source\fmx\WrapFmxListBox.pas',
- WrapFmxListView in '..\..\..\Source\fmx\WrapFmxListView.pas',
- WrapFmxMedia in '..\..\..\Source\fmx\WrapFmxMedia.pas',
- WrapFmxMemo in '..\..\..\Source\fmx\WrapFmxMemo.pas',
- WrapFmxMenus in '..\..\..\Source\fmx\WrapFmxMenus.pas',
- WrapFmxScrollBox in '..\..\..\Source\fmx\WrapFmxScrollBox.pas',
- WrapFmxShapes in '..\..\..\Source\fmx\WrapFmxShapes.pas',
- WrapFmxStdActns in '..\..\..\Source\fmx\WrapFmxStdActns.pas',
- WrapFmxStdCtrls in '..\..\..\Source\fmx\WrapFmxStdCtrls.pas',
- WrapFmxStyles in '..\..\..\Source\fmx\WrapFmxStyles.pas',
- WrapFmxTypes in '..\..\..\Source\fmx\WrapFmxTypes.pas',
- WrapFmxDateTime in '..\..\..\Source\fmx\WrapFmxDateTime.pas';
-
-end.
-
diff --git a/Packages/Delphi/Delphi 10.4+/PythonFmxLinux.dproj b/Packages/Delphi/Delphi 10.4+/PythonFmxLinux.dproj
deleted file mode 100644
index 445f21ac..00000000
--- a/Packages/Delphi/Delphi 10.4+/PythonFmxLinux.dproj
+++ /dev/null
@@ -1,968 +0,0 @@
-
-
- {B0F48139-24FB-42F3-93E8-05DA2E142904}
- PythonFmxLinux.dpk
- True
- Release
- 128
- Package
- FMX
- 19.5
- Linux64
-
-
- true
-
-
- true
- Base
- true
-
-
- true
- Base
- true
-
-
- true
- Base
- true
-
-
- true
- Base
- true
-
-
- true
- Base
- true
-
-
- true
- Cfg_1
- true
- true
-
-
- true
- Base
- true
-
-
- true
- Cfg_2
- true
- true
-
-
- true
- Cfg_2
- true
- true
-
-
- true
- Cfg_2
- true
- true
-
-
- true
- Cfg_2
- true
- true
-
-
- false
- false
- false
- false
- false
- 00400000
- true
- true
- PythonFmxLinux
- Python4Delphi - Run-time Engine Package for FMXLinux
- $(Auto)
- true
- 1046
- CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=
- System;Xml;Data;Datasnap;Web;Soap;REST.Authenticator.OAuth.WebForm;$(DCC_Namespace)
- $(BDSCatalogRepositoryAllUsers)\FmxLinux-1.71\redist;$(DCC_UnitSearchPath)
-
-
- package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
- Debug
- $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
- annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar
-
-
- $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
- annotation-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.0.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.0.1.dex.jar;core-runtime-2.0.1.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.0.0.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.0.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.0.0.dex.jar;lifecycle-runtime-2.0.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.0.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar
-
-
- $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png
-
-
- Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
- Debug
- true
- CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)
- 1033
-
-
- RELEASE;$(DCC_Define)
- 0
- false
- 0
-
-
- /usr/bin/gnome-terminal -- "%debuggee%"
-
-
- DEBUG;$(DCC_Define)
- false
- true
- true
- true
-
-
- Debug
-
-
- Debug
-
-
- Debug
-
-
- Debug
-
-
-
- MainSource
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Base
-
-
- Cfg_1
- Base
-
-
- Cfg_2
- Base
-
-
-
- Delphi.Personality.12
- Package
-
-
-
- PythonFmxLinux.dpk
-
-
- Embarcadero C++Builder Office 2000 Servers Package
- Embarcadero C++Builder Office XP Servers Package
- Microsoft Office 2000 Sample Automation Server Wrapper Components
- Microsoft Office XP Sample Automation Server Wrapper Components
-
-
-
- False
- False
- False
- False
- True
- False
- False
- False
- False
-
-
-
-
- true
-
-
-
-
- true
-
-
-
-
- true
-
-
-
-
- bplPythonFmxLinux.so
- true
-
-
-
-
- PythonFmxLinux.bpl
- true
-
-
-
-
- 1
-
-
- 0
-
-
-
-
- classes
- 64
-
-
- classes
- 64
-
-
-
-
- res\xml
- 1
-
-
- res\xml
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- library\lib\armeabi
- 1
-
-
- library\lib\armeabi
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- library\lib\mips
- 1
-
-
- library\lib\mips
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
- library\lib\arm64-v8a
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- res\drawable
- 1
-
-
- res\drawable
- 1
-
-
-
-
- res\values
- 1
-
-
- res\values
- 1
-
-
-
-
- res\values-v21
- 1
-
-
- res\values-v21
- 1
-
-
-
-
- res\values
- 1
-
-
- res\values
- 1
-
-
-
-
- res\drawable
- 1
-
-
- res\drawable
- 1
-
-
-
-
- res\drawable-xxhdpi
- 1
-
-
- res\drawable-xxhdpi
- 1
-
-
-
-
- res\drawable-xxxhdpi
- 1
-
-
- res\drawable-xxxhdpi
- 1
-
-
-
-
- res\drawable-ldpi
- 1
-
-
- res\drawable-ldpi
- 1
-
-
-
-
- res\drawable-mdpi
- 1
-
-
- res\drawable-mdpi
- 1
-
-
-
-
- res\drawable-hdpi
- 1
-
-
- res\drawable-hdpi
- 1
-
-
-
-
- res\drawable-xhdpi
- 1
-
-
- res\drawable-xhdpi
- 1
-
-
-
-
- res\drawable-mdpi
- 1
-
-
- res\drawable-mdpi
- 1
-
-
-
-
- res\drawable-hdpi
- 1
-
-
- res\drawable-hdpi
- 1
-
-
-
-
- res\drawable-xhdpi
- 1
-
-
- res\drawable-xhdpi
- 1
-
-
-
-
- res\drawable-xxhdpi
- 1
-
-
- res\drawable-xxhdpi
- 1
-
-
-
-
- res\drawable-xxxhdpi
- 1
-
-
- res\drawable-xxxhdpi
- 1
-
-
-
-
- res\drawable-small
- 1
-
-
- res\drawable-small
- 1
-
-
-
-
- res\drawable-normal
- 1
-
-
- res\drawable-normal
- 1
-
-
-
-
- res\drawable-large
- 1
-
-
- res\drawable-large
- 1
-
-
-
-
- res\drawable-xlarge
- 1
-
-
- res\drawable-xlarge
- 1
-
-
-
-
- res\values
- 1
-
-
- res\values
- 1
-
-
-
-
- 1
-
-
- 1
-
-
- 0
-
-
-
-
- 1
- .framework
-
-
- 1
- .framework
-
-
- 1
- .framework
-
-
- 0
-
-
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 0
- .dll;.bpl
-
-
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 0
- .bpl
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- 1
-
-
- 1
-
-
-
-
- ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
- 1
-
-
- ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
- 1
-
-
- ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
- 1
-
-
-
-
-
-
-
- 1
-
-
- 1
-
-
- 1
-
-
-
-
-
-
-
- Contents\Resources
- 1
-
-
- Contents\Resources
- 1
-
-
- Contents\Resources
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
- library\lib\arm64-v8a
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 0
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- 1
-
-
- 1
-
-
-
-
- Assets
- 1
-
-
- Assets
- 1
-
-
-
-
- Assets
- 1
-
-
- Assets
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 12
-
-
-
-
-
diff --git a/Packages/Delphi/Delphi 10.4+/PythonVcl.dproj b/Packages/Delphi/Delphi 10.4+/PythonVcl.dproj
index 3f40f175..9ccee1e3 100644
--- a/Packages/Delphi/Delphi 10.4+/PythonVcl.dproj
+++ b/Packages/Delphi/Delphi 10.4+/PythonVcl.dproj
@@ -7,7 +7,8 @@
PythonVcl.dpk
Win32
{D8908301-393C-4CFA-8842-4948A9935E21}
- 19.5
+ PythonVcl
+ 20.1
3
@@ -144,13 +145,14 @@
False
False
+ False
+ False
False
False
False
True
True
- False
- False
+ False
12
diff --git a/Packages/Delphi/Delphi 10.4+/dclPython.dproj b/Packages/Delphi/Delphi 10.4+/dclPython.dproj
index a2f01927..749430a6 100644
--- a/Packages/Delphi/Delphi 10.4+/dclPython.dproj
+++ b/Packages/Delphi/Delphi 10.4+/dclPython.dproj
@@ -7,7 +7,8 @@
dclPython.dpk
Win32
{D9AB994C-54A3-4E76-81C8-6D0BB035A091}
- 19.5
+ dclPython
+ 20.1
1
@@ -149,6 +150,7 @@
False
True
False
+ False
False
False
diff --git a/Packages/Delphi/Delphi 10.4+/dclPythonFmx.dproj b/Packages/Delphi/Delphi 10.4+/dclPythonFmx.dproj
index 9fed4132..1104549c 100644
--- a/Packages/Delphi/Delphi 10.4+/dclPythonFmx.dproj
+++ b/Packages/Delphi/Delphi 10.4+/dclPythonFmx.dproj
@@ -7,7 +7,8 @@
dclPythonFmx.dpk
Win32
{E057921E-25DB-426E-8090-FE3F428894FF}
- 19.5
+ dclPythonFmx
+ 20.1
1
@@ -125,6 +126,7 @@
False
True
False
+ False
False
False
diff --git a/Packages/Delphi/Delphi 10.4+/dclPythonVcl.dproj b/Packages/Delphi/Delphi 10.4+/dclPythonVcl.dproj
index 3944b8d3..7a1e1ec3 100644
--- a/Packages/Delphi/Delphi 10.4+/dclPythonVcl.dproj
+++ b/Packages/Delphi/Delphi 10.4+/dclPythonVcl.dproj
@@ -7,7 +7,8 @@
dclPythonVcl.dpk
Win32
{48DDC28A-E154-4CA0-864A-30EB8C4CCBB3}
- 19.5
+ dclPythonVcl
+ 20.1
1
@@ -125,6 +126,7 @@
False
True
False
+ False
False
False
diff --git a/Packages/Delphi/P4DLinuxComponentSuite.groupproj b/Packages/Delphi/P4DLinuxComponentSuite.groupproj
deleted file mode 100644
index 544e8812..00000000
--- a/Packages/Delphi/P4DLinuxComponentSuite.groupproj
+++ /dev/null
@@ -1,108 +0,0 @@
-
-
- {8BE1193B-E609-445D-9BA3-F57DBEA042F5}
-
-
-
-
-
-
- Delphi 10.4+\Python.dproj
-
-
- Delphi 10.4+\Python.dproj
-
-
- Delphi 10.4+\PythonVcl.dproj
-
-
-
-
-
-
-
-
-
-
-
-
- Default.Personality.12
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Source/PythonAction.pas b/Source/PythonAction.pas
index 60af65e5..d94d610e 100644
--- a/Source/PythonAction.pas
+++ b/Source/PythonAction.pas
@@ -17,7 +17,7 @@ interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- ActnList, PythonEngine;
+ Actions, ActnList, PythonEngine;
type
TPythonAction = class(TAction)
@@ -114,21 +114,21 @@ function TPythonAction.HandlesTarget(Target: TObject): Boolean;
procedure TPythonAction.InitializeAction;
var
- docString: string;
+ docString: string;
begin
if not (csDesigning in ComponentState) and Assigned(PythonModule) then
begin
fClearname := 'Clear' + Name;
docString := 'Claer all events of "' + Owner.Name + '.' + Name + '" action';
- PythonModule.AddDelphiMethod(PChar(fClearname), PythonClear, PChar(docString));
+ PythonModule.AddDelphiMethod(PAnsiChar(fClearname), PythonClear, PAnsiChar(docString));
fRegistername := 'Register' + Name;
docString := 'Register an event againt the "' + Owner.Name + '.' + Name + '" action';
- PythonModule.AddDelphiMethod(PChar(fRegistername), PythonRegister, PChar(docString));
+ PythonModule.AddDelphiMethod(PAnsiChar(fRegistername), PythonRegister, PAnsiChar(docString));
fUnregistername := 'Unregister' + Name;
docString := 'Unregister an event againt the "' + Owner.Name + '.' + Name + '" action';
- PythonModule.AddDelphiMethod(PChar(fUnregistername), PythonUnregister, PChar(docString));
+ PythonModule.AddDelphiMethod(PAnsiChar(fUnregistername), PythonUnregister, PAnsiChar(docString));
end;
end;
@@ -152,7 +152,7 @@ function TPythonAction.PythonRegister(pself, args: PPyObject): PPyObject;
( not PyFunction_Check(func)) then
begin
s := fRegistername + '(function)';
- PyErr_SetString(PyExc_TypeError^,PChar(s));
+ PyErr_SetString(PyExc_TypeError^, PAnsiChar(Utf8Encode(s)));
end
else
with RegisteredMethods do
@@ -174,7 +174,7 @@ function TPythonAction.PythonUnregister(pself, args: PPyObject): PPyObject;
(RegisteredMethods.IndexOf(func) = -1) then
begin
s := fUnregistername + '(function)';
- PyErr_SetString(PyExc_TypeError^,PChar(s));
+ PyErr_SetString(PyExc_TypeError^, PAnsiChar(Utf8Encode(s)));
end
else
with RegisteredMethods do
diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas
index 7bd52c93..1d3cd846 100644
--- a/Source/PythonEngine.pas
+++ b/Source/PythonEngine.pas
@@ -73,59 +73,51 @@ TPythonVersionProp = record
end;
const
{$IFDEF MSWINDOWS}
- PYTHON_KNOWN_VERSIONS: array[1..10] of TPythonVersionProp =
+ PYTHON_KNOWN_VERSIONS: array[1..7] of TPythonVersionProp =
(
- (DllName: 'python33.dll'; RegVersion: '3.3'; APIVersion: 1013),
- (DllName: 'python34.dll'; RegVersion: '3.4'; APIVersion: 1013),
- (DllName: 'python35.dll'; RegVersion: '3.5'; APIVersion: 1013),
- (DllName: 'python36.dll'; RegVersion: '3.6'; APIVersion: 1013),
- (DllName: 'python37.dll'; RegVersion: '3.7'; APIVersion: 1013),
(DllName: 'python38.dll'; RegVersion: '3.8'; APIVersion: 1013),
(DllName: 'python39.dll'; RegVersion: '3.9'; APIVersion: 1013),
(DllName: 'python310.dll'; RegVersion: '3.10'; APIVersion: 1013),
(DllName: 'python311.dll'; RegVersion: '3.11'; APIVersion: 1013),
- (DllName: 'python312.dll'; RegVersion: '3.12'; APIVersion: 1013)
+ (DllName: 'python312.dll'; RegVersion: '3.12'; APIVersion: 1013),
+ (DllName: 'python313.dll'; RegVersion: '3.13'; APIVersion: 1013),
+ (DllName: 'python314.dll'; RegVersion: '3.14'; APIVersion: 1013)
);
{$ENDIF}
{$IFDEF _so_files}
- PYTHON_KNOWN_VERSIONS: array[1..10] of TPythonVersionProp =
+ PYTHON_KNOWN_VERSIONS: array[1..7] of TPythonVersionProp =
(
- (DllName: 'libpython3.3m.so'; RegVersion: '3.3'; APIVersion: 1013),
- (DllName: 'libpython3.4m.so'; RegVersion: '3.4'; APIVersion: 1013),
- (DllName: 'libpython3.5m.so'; RegVersion: '3.5'; APIVersion: 1013),
- (DllName: 'libpython3.6m.so'; RegVersion: '3.6'; APIVersion: 1013),
- (DllName: 'libpython3.7m.so'; RegVersion: '3.7'; APIVersion: 1013),
(DllName: 'libpython3.8.so'; RegVersion: '3.8'; APIVersion: 1013),
(DllName: 'libpython3.9.so'; RegVersion: '3.9'; APIVersion: 1013),
(DllName: 'libpython3.10.so'; RegVersion: '3.10'; APIVersion: 1013),
(DllName: 'libpython3.11.so'; RegVersion: '3.11'; APIVersion: 1013),
- (DllName: 'libpython3.12.so'; RegVersion: '3.12'; APIVersion: 1013)
+ (DllName: 'libpython3.12.so'; RegVersion: '3.12'; APIVersion: 1013),
+ (DllName: 'libpython3.13.so'; RegVersion: '3.13'; APIVersion: 1013),
+ (DllName: 'libpython3.14.so'; RegVersion: '3.14'; APIVersion: 1013)
);
{$ENDIF}
{$IFDEF DARWIN}
- PYTHON_KNOWN_VERSIONS: array[1..10] of TPythonVersionProp =
+ PYTHON_KNOWN_VERSIONS: array[1..7] of TPythonVersionProp =
(
- (DllName: 'libpython3.3.dylib'; RegVersion: '3.3'; APIVersion: 1013),
- (DllName: 'libpython3.4.dylib'; RegVersion: '3.4'; APIVersion: 1013),
- (DllName: 'libpython3.5.dylib'; RegVersion: '3.5'; APIVersion: 1013),
- (DllName: 'libpython3.6.dylib'; RegVersion: '3.6'; APIVersion: 1013),
- (DllName: 'libpython3.7.dylib'; RegVersion: '3.7'; APIVersion: 1013),
(DllName: 'libpython3.8.dylib'; RegVersion: '3.8'; APIVersion: 1013),
(DllName: 'libpython3.9.dylib'; RegVersion: '3.9'; APIVersion: 1013),
(DllName: 'libpython3.10.dylib'; RegVersion: '3.10'; APIVersion: 1013),
(DllName: 'libpython3.11.dylib'; RegVersion: '3.11'; APIVersion: 1013),
- (DllName: 'libpython3.12.dylib'; RegVersion: '3.12'; APIVersion: 1013)
+ (DllName: 'libpython3.12.dylib'; RegVersion: '3.12'; APIVersion: 1013),
+ (DllName: 'libpython3.13.dylib'; RegVersion: '3.13'; APIVersion: 1013),
+ (DllName: 'libpython3.14.dylib'; RegVersion: '3.14'; APIVersion: 1013)
);
{$ENDIF}
{$IFDEF ANDROID}
- PYTHON_KNOWN_VERSIONS: array[5..10] of TPythonVersionProp =
+ PYTHON_KNOWN_VERSIONS: array[1..7] of TPythonVersionProp =
(
- (DllName: 'libpython3.7m.so'; RegVersion: '3.7'; APIVersion: 1013),
(DllName: 'libpython3.8.so'; RegVersion: '3.8'; APIVersion: 1013),
(DllName: 'libpython3.9.so'; RegVersion: '3.9'; APIVersion: 1013),
(DllName: 'libpython3.10.so'; RegVersion: '3.10'; APIVersion: 1013),
(DllName: 'libpython3.11.so'; RegVersion: '3.11'; APIVersion: 1013),
- (DllName: 'libpython3.12.so'; RegVersion: '3.12'; APIVersion: 1013)
+ (DllName: 'libpython3.12.so'; RegVersion: '3.12'; APIVersion: 1013),
+ (DllName: 'libpython3.13.so'; RegVersion: '3.13'; APIVersion: 1013),
+ (DllName: 'libpython3.14.so'; RegVersion: '3.14'; APIVersion: 1013)
);
{$ENDIF}
@@ -188,8 +180,8 @@ TPythonVersionProp = record
WCharTString = UnicodeString;
{$ENDIF}
- PPy_ssize_t = PNativeInt;
- Py_ssize_t = NativeInt;
+ PPy_ssize_t = PNativeUInt;
+ Py_ssize_t = NativeUInt;
const
{
@@ -352,6 +344,20 @@ TPythonVersionProp = record
PyBUF_READ = $100;
PyBUF_WRITE = $200;
+const
+ // constants used in PyModuleDef slots from moduleobject.h
+ Py_mod_create = 1;
+ Py_mod_exec = 2;
+ Py_mod_multiple_interpreters = 3; // Added in version 3.12
+ Py_mod_gil = 4; // Added in version 3.13
+
+ Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED: Pointer = Pointer(0);
+ Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED: Pointer = Pointer(1);
+ Py_MOD_PER_INTERPRETER_GIL_SUPPORTED: Pointer = Pointer(2);
+
+ Py_MOD_GIL_USED: Pointer = Pointer(0);
+ Py_MOD_GIL_NOT_USED: Pointer = Pointer(1);
+
//#######################################################
//## ##
//## Non-Python specific constants ##
@@ -482,7 +488,7 @@ TPythonVersionProp = record
end;
PyObject = {$IFDEF CPUX86}packed{$ENDIF} record
- ob_refcnt: NativeInt;
+ ob_refcnt: NativeUInt;
ob_type: PPyTypeObject;
end;
@@ -493,7 +499,7 @@ TPythonVersionProp = record
end;
PySliceObject = {$IFDEF CPUX86}packed{$ENDIF} record
- ob_refcnt: NativeInt;
+ ob_refcnt: NativeUInt;
ob_type: PPyTypeObject;
start, stop, step: PPyObject;
end;
@@ -546,28 +552,31 @@ TPythonVersionProp = record
{#define PyDescr_COMMON \
PyObject_HEAD \
PyTypeObject *d_type; \
- PyObject *d_name
+ PyObject *d_name \
+ PyObject *d_qualname
}
PPyDescrObject = ^PyDescrObject;
PyDescrObject = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
d_type : PPyTypeObject;
d_name : PPyObject;
+ d_qualname : PPyObject;
end;
PPyMethodDescrObject = ^PyMethodDescrObject;
PyMethodDescrObject = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of PyDescr_COMMON
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
d_type : PPyTypeObject;
d_name : PPyObject;
+ d_qualname : PPyObject;
// End of PyDescr_COMMON
d_method : PPyMethodDef;
end;
@@ -576,11 +585,12 @@ TPythonVersionProp = record
PyMemberDescrObject = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of PyDescr_COMMON
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
d_type : PPyTypeObject;
d_name : PPyObject;
+ d_qualname : PPyObject;
// End of PyDescr_COMMON
d_member : PPyMemberDef;
end;
@@ -589,11 +599,12 @@ TPythonVersionProp = record
PyGetSetDescrObject = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of PyDescr_COMMON
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
d_type : PPyTypeObject;
d_name : PPyObject;
+ d_qualname : PPyObject;
// End of PyDescr_COMMON
d_getset : PPyGetSetDef;
end;
@@ -602,11 +613,12 @@ TPythonVersionProp = record
PyWrapperDescrObject = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of PyDescr_COMMON
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
d_type : PPyTypeObject;
d_name : PPyObject;
+ d_qualname : PPyObject;
// End of PyDescr_COMMON
d_base : pwrapperbase;
d_wrapped : Pointer; // This can be any function pointer
@@ -615,7 +627,7 @@ TPythonVersionProp = record
PPyModuleDef_Base = ^PyModuleDef_Base;
PyModuleDef_Base = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
m_init : function( ) : PPyObject; cdecl;
@@ -623,6 +635,16 @@ TPythonVersionProp = record
m_copy : PPyObject;
end;
+ // Slots are used for two phase module initialization
+ // which is not yet implemented
+
+ PPyModuleDef_Slot = ^PyModuleDef_Slot;
+ PyModuleDef_Slot = {$IFDEF CPUX86}packed{$ENDIF} record
+ slot: integer;
+ value: Pointer;
+ class function Make(slot: integer; value: Pointer): PyModuleDef_Slot; static;
+ end;
+
PPyModuleDef = ^PyModuleDef;
PyModuleDef = {$IFDEF CPUX86}packed{$ENDIF} record
m_base : PyModuleDef_Base;
@@ -630,12 +652,16 @@ TPythonVersionProp = record
m_doc : PAnsiChar;
m_size : NativeInt;
m_methods : PPyMethodDef;
- m_reload : inquiry;
+ m_slots : PPyModuleDef_Slot;
m_traverse : traverseproc;
m_clear : inquiry;
m_free : inquiry;
end;
+ // signature of functions used in slots
+ Py_create_module_function = function(spec: PPyObject; def: PPyModuleDef):PPyObject; cdecl;
+ Py_exec_module_function = function(module: PPyObject): Integer; cdecl;
+
// pybuffer.h
PPy_buffer = ^Py_Buffer;
@@ -666,7 +692,7 @@ PyBufferProcs = record
// object.h
PyTypeObject = {$IFDEF CPUX86}packed{$ENDIF} record
- ob_refcnt: NativeInt;
+ ob_refcnt: NativeUInt;
ob_type: PPyTypeObject;
ob_size: NativeInt; // Number of items in variable part
tp_name: PAnsiChar; // For printing
@@ -813,7 +839,7 @@ PyBufferProcs = record
type
PyDateTime_Delta = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
hashcode : NativeInt; // -1 when unknown
@@ -825,7 +851,7 @@ PyBufferProcs = record
PyDateTime_TZInfo = {$IFDEF CPUX86}packed{$ENDIF} record // a pure abstract base clase
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
end;
@@ -848,7 +874,7 @@ PyBufferProcs = record
_PyDateTime_BaseTZInfo = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
hashcode : Integer;
@@ -872,7 +898,7 @@ PyBufferProcs = record
// Start of _PyDateTime_TIMEHEAD
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
hashcode : Integer;
@@ -887,7 +913,7 @@ PyBufferProcs = record
// Start of _PyDateTime_TIMEHEAD
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
hashcode : Integer;
@@ -909,7 +935,7 @@ PyBufferProcs = record
PyDateTime_Date = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
hashcode : Integer;
@@ -928,7 +954,7 @@ PyBufferProcs = record
_PyDateTime_BaseDateTime = {$IFDEF CPUX86}packed{$ENDIF} record // hastzinfo false
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
hashcode : Integer;
@@ -942,7 +968,7 @@ PyBufferProcs = record
// Start of _PyDateTime_DATETIMEHEAD
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
- ob_refcnt : NativeInt;
+ ob_refcnt : NativeUInt;
ob_type : PPyTypeObject;
// End of the Head of an object
hashcode : Integer;
@@ -957,7 +983,7 @@ PyBufferProcs = record
//bytearrayobject.h
PyByteArrayObject = {$IFDEF CPUX86}packed{$ENDIF} record
- ob_refcnt: NativeInt;
+ ob_refcnt: NativeUInt;
ob_type: PPyTypeObject;
ob_alloc: Py_ssize_t;
ob_bytes: PAnsiChar;
@@ -966,6 +992,7 @@ PyBufferProcs = record
end;
//initconfig.h
+ //See https://docs.python.org/3/c-api/init_config.html
const
_PyStatus_TYPE_OK = 0;
@@ -982,6 +1009,80 @@ PyBufferProcs = record
exitcode: Integer;
end;
+ PPyWideStringList = ^PyWideStringList;
+ PyWideStringList = {$IFDEF CPUX86}packed{$ENDIF} record
+ length: Py_ssize_t;
+ items: PPWCharT;
+ end;
+
+ PPyConfig = ^PyConfig;
+ PyConfig = record
+ // The definition of PyConfig has been changing in every python version
+ // So we make this structure opaque and we access its fields through
+ // the ConfigOffsets below
+ Filler: array [0..1000] of Byte;
+ end;
+
+ // Opaque structure PEP 741
+ PPyInitConfig = Pointer;
+
+{$SCOPEDENUMS ON}
+ TConfigFields = (
+ use_environment,
+ parse_argv,
+ argv,
+ site_import,
+ interactive,
+ optimization_level,
+ parser_debug,
+ verbose,
+ pathconfig_warnings,
+ program_name,
+ home,
+ module_search_paths_set,
+ module_search_paths,
+ executable);
+{$SCOPEDENUMS OFF}
+
+ TConfigOffsets = array [8..13] of array [TConfigFields] of Integer;
+
+ // The followng needs updating when new versions are added
+ const
+ ConfigOffests: TConfigOffsets =
+ {$IFDEF MSWINDOWS}
+ {$IFDEF CPU64BITS}
+ ((8, 80, 88, 144, 156, 160, 164, 172, 224, 104, 240, 248, 256, 272),
+ (8, 80, 88, 144, 156, 160, 164, 172, 224, 104, 240, 248, 256, 272),
+ (8, 80, 104, 152, 168, 172, 176, 184, 240, 248, 264, 280, 288, 304),
+ (8, 96, 120, 168, 184, 188, 192, 200, 264, 272, 288, 304, 312, 336),
+ (8, 96, 120, 168, 184, 188, 192, 200, 268, 272, 288, 304, 312, 336),
+ (8, 96, 120, 168, 184, 188, 192, 200, 272, 280, 296, 312, 320, 344));
+ {$ELSE}
+ ((8, 68, 72, 100, 112, 116, 120, 128, 164, 80, 172, 176, 180, 188),
+ (8, 68, 72, 100, 112, 116, 120, 128, 164, 80, 172, 176, 180, 188),
+ (8, 64, 76, 100, 116, 120, 124, 132, 168, 172, 180, 188, 192, 200),
+ (8, 72, 84, 108, 124, 128, 132, 140, 184, 188, 196, 204, 208, 220),
+ (8, 76, 88, 112, 128, 132, 136, 144, 192, 196, 204, 212, 216, 228),
+ (8, 76, 88, 112, 128, 132, 136, 144, 196, 200, 208, 216, 220, 232));
+ {$ENDIF}
+ {$ELSE}
+ {$IFDEF CPU64BITS}
+ ((8, 88, 96, 152, 164, 168, 172, 180, 224, 112, 240, 248, 256, 272),
+ (8, 88, 96, 152, 164, 168, 172, 180, 224, 112, 240, 248, 256, 272),
+ (8, 80, 104, 152, 168, 172, 176, 184, 232, 240, 256, 272, 280, 296),
+ (8, 96, 120, 168, 184, 188, 192, 200, 256, 264, 280, 296, 304, 328),
+ (8, 104, 128, 176, 192, 196, 200, 208, 268, 272, 288, 304, 312, 336),
+ (8, 104, 128, 176, 192, 196, 200, 208, 272, 280, 296, 312, 320, 344));
+ {$ELSE}
+ ((8, 68, 72, 100, 112, 116, 120, 128, 160, 80, 168, 172, 176, 184),
+ (8, 68, 72, 100, 112, 116, 120, 128, 160, 80, 168, 172, 176, 184),
+ (8, 64, 76, 100, 116, 120, 124, 132, 164, 168, 176, 184, 188, 196),
+ (8, 72, 84, 108, 124, 128, 132, 140, 180, 184, 192, 200, 204, 216),
+ (8, 76, 88, 112, 128, 132, 136, 144, 188, 192, 200, 208, 212, 224),
+ (8, 76, 88, 112, 128, 132, 136, 144, 192, 196, 204, 212, 216, 228));
+ {$ENDIF}
+ {$ENDIF}
+
//#######################################################
//## ##
//## GIL related ##
@@ -999,7 +1100,7 @@ PyBufferProcs = record
PyInterpreterConfig_SHARED_GIL = 1;
PyInterpreterConfig_OWN_GIL = 2;
- type
+type
PPyInterpreterConfig = ^PyInterpreterConfig;
PyInterpreterConfig = {$IFDEF CPUX86}packed{$ENDIF} record
use_main_obmalloc: Integer;
@@ -1011,7 +1112,7 @@ PyBufferProcs = record
gil: Integer;
end;
-const
+var
_PyInterpreterConfig_INIT: PyInterpreterConfig =
( use_main_obmalloc: 0;
allow_fork: 0;
@@ -1355,15 +1456,6 @@ TPythonInterface=class(TDynamicDll)
procedure CheckPython;
public
- // define Python flags. See file pyDebug.h
- Py_DebugFlag: PInteger;
- Py_VerboseFlag: PInteger;
- Py_InteractiveFlag: PInteger;
- Py_OptimizeFlag: PInteger;
- Py_NoSiteFlag: PInteger;
- Py_FrozenFlag: PInteger;
- Py_IgnoreEnvironmentFlag: PInteger;
-
PyImport_FrozenModules: PP_frozen;
Py_None: PPyObject;
@@ -1446,6 +1538,7 @@ TPythonInterface=class(TDynamicDll)
PySuper_Type: PPyTypeObject;
PyTraceBack_Type: PPyTypeObject;
PyUnicode_Type: PPyTypeObject;
+ PyGetSetDescr_Type: PPyTypeObject;
PyWrapperDescr_Type: PPyTypeObject;
_PyWeakref_RefType: PPyTypeObject;
_PyWeakref_ProxyType: PPyTypeObject;
@@ -1467,6 +1560,9 @@ TPythonInterface=class(TDynamicDll)
PyCallable_Check: function(ob : PPyObject): integer; cdecl;
PyModule_Create2: function(moduledef: PPyModuleDef; Api_Version: Integer):PPyObject; cdecl;
+ PyModuleDef_Init: function(moduledef: PPyModuleDef):PPyObject; cdecl;
+ PyModule_ExecDef: function(module: PPyObject; moduledef: PPyModuleDef):Integer; cdecl;
+ PyModule_FromDefAndSpec2: function(moduledef: PPyModuleDef; spec: PPyObject; Api_Version: Integer):PPyObject; cdecl;
PyErr_BadArgument: function: integer; cdecl;
PyErr_BadInternalCall: procedure; cdecl;
PyErr_CheckSignals: function: integer; cdecl;
@@ -1517,7 +1613,6 @@ TPythonInterface=class(TDynamicDll)
PyBytes_AsString: function( ob: PPyObject): PAnsiChar; cdecl;
PyBytes_AsStringAndSize: function( ob: PPyObject; var buffer: PAnsiChar; var size: NativeInt): integer; cdecl;
PyByteArray_AsString: function(ob: PPyObject): PAnsiChar; cdecl;
- PySys_SetArgv: procedure( argc: Integer; argv: PPWCharT); cdecl;
PyCFunction_NewEx: function(md:PPyMethodDef;self, ob:PPyObject):PPyObject; cdecl;
@@ -1532,14 +1627,10 @@ TPythonInterface=class(TDynamicDll)
len: Py_ssize_t; readonly: Integer; flags: Integer): Integer; cdecl;
PyBuffer_Release: procedure(view: PPy_buffer); cdecl;
- // Removed. Use PyEval_CallObjectWithKeywords with third argument nil
- // PyEval_CallObject: function(callable_obj, args:PPyObject):PPyObject; cdecl;
- PyEval_CallObjectWithKeywords:function (callable_obj, args, kw:PPyObject):PPyObject; cdecl;
PyEval_GetFrame:function :PPyObject; cdecl;
PyEval_GetGlobals:function :PPyObject; cdecl;
PyEval_GetLocals:function :PPyObject; cdecl;
- PyEval_InitThreads:procedure; cdecl;
PyEval_RestoreThread:procedure( tstate: PPyThreadState); cdecl;
PyEval_SaveThread:function :PPyThreadState; cdecl;
@@ -1580,6 +1671,7 @@ TPythonInterface=class(TDynamicDll)
PyLong_FromLongLong:function(val:Int64): PPyObject; cdecl;
PyLong_FromUnsignedLongLong:function(val:UInt64) : PPyObject; cdecl;
PyLong_AsLongLong:function(ob:PPyObject): Int64; cdecl;
+ PyLong_AsVoidPtr:function(ob:PPyObject): Pointer; cdecl;
PyLong_FromVoidPtr:function(p: Pointer): PPyObject; cdecl;
PyMapping_Check:function (ob:PPyObject):integer; cdecl;
PyMapping_GetItemString:function (ob:PPyObject;key:PAnsiChar):PPyObject; cdecl;
@@ -1695,7 +1787,6 @@ TPythonInterface=class(TDynamicDll)
PySet_Size: function(anyset: PPyObject): Py_ssize_t; cdecl;
PySys_GetObject:function (s:PAnsiChar):PPyObject; cdecl;
PySys_SetObject:function (s:PAnsiChar;ob:PPyObject):integer; cdecl;
- PySys_SetPath:procedure(path:PAnsiChar); cdecl;
PyTraceBack_Here:function (p:pointer):integer; cdecl;
PyTraceBack_Print:function (ob1,ob2:PPyObject):integer; cdecl;
PyTuple_GetItem:function (ob:PPyObject;i:NativeInt):PPyObject; cdecl;
@@ -1738,25 +1829,19 @@ TPythonInterface=class(TDynamicDll)
Py_GetCopyright : function : PAnsiChar; cdecl;
Py_GetExecPrefix : function : PWCharT; cdecl;
Py_GetPath : function : PWCharT; cdecl;
- Py_SetPath : procedure (path: PWCharT); cdecl;
- Py_SetPythonHome : procedure (home : PWCharT); cdecl;
Py_GetPythonHome : function : PWCharT; cdecl;
Py_GetPrefix : function : PWCharT; cdecl;
Py_GetProgramName : function : PWCharT; cdecl;
- PyParser_SimpleParseStringFlags : function ( str : PAnsiChar; start, flags : Integer) : PNode; cdecl;
- PyNode_Free : procedure( n : PNode ); cdecl;
- PyErr_NewException : function ( name : PAnsiChar; base, dict : PPyObject ) : PPyObject; cdecl;
- PyMem_Malloc : function ( size : NativeUInt ) : Pointer;
+ PyErr_NewException : function (name : PAnsiChar; base, dict : PPyObject): PPyObject; cdecl;
+ PyMem_Malloc : function (size: NativeUInt): Pointer; cdecl;
+ PyMem_Free : procedure (P: Pointer); cdecl;
- Py_SetProgramName : procedure( name: PWCharT); cdecl;
Py_IsInitialized : function : integer; cdecl;
Py_GetProgramFullPath : function : PAnsiChar; cdecl;
Py_NewInterpreter : function : PPyThreadState; cdecl;
Py_NewInterpreterFromConfig : function( tstate: PPyThreadState; config: PPyInterpreterConfig): PyStatus; cdecl;
Py_EndInterpreter : procedure( tstate: PPyThreadState); cdecl;
- PyEval_AcquireLock : procedure; cdecl;
- PyEval_ReleaseLock : procedure; cdecl;
PyEval_AcquireThread : procedure( tstate: PPyThreadState); cdecl;
PyEval_ReleaseThread : procedure( tstate: PPyThreadState); cdecl;
PyInterpreterState_New : function : PPyInterpreterState; cdecl;
@@ -1771,11 +1856,29 @@ TPythonInterface=class(TDynamicDll)
PyGILState_Ensure : function() : PyGILstate_STATE; cdecl;
PyGILState_Release : procedure(gilstate : PyGILState_STATE); cdecl;
- // Not exported in Python 3.8 and implemented as functions - this has been fixed
- // TODO - deal with the following:
- // the PyParser_* functions are deprecated in python 3.9 and will be removed in
- // Python 3.10
- function PyParser_SimpleParseString(str : PAnsiChar; start : Integer) : PNode; cdecl;
+ // PEP 587 Initialization functions
+ PyWideStringList_Append : function(list: PPyWideStringList; item: PWCharT): PyStatus; cdecl;
+ PyWideStringList_Insert : function(list: PPyWideStringList; index: Py_ssize_t; item: PWCharT): PyStatus; cdecl;
+ PyConfig_InitPythonConfig : procedure(var config: PyConfig); cdecl;
+ PyConfig_InitIsolatedConfig : procedure(var config: PyConfig); cdecl;
+ PyConfig_Clear : procedure(var config: PyConfig); cdecl;
+ PyConfig_SetString : function(var config: PyConfig; config_str: PPWCharT; str: PWCharT): PyStatus; cdecl;
+ PyConfig_Read : function(var config: PyConfig): PyStatus; cdecl;
+ PyConfig_SetArgv : function(var config: PyConfig; argc: Py_ssize_t; argv: PPWCharT): PyStatus; cdecl;
+ PyConfig_SetWideStringList : function(var config: PyConfig; list: PPyWideStringList; length: Py_ssize_t; items: PPWCharT): PyStatus; cdecl;
+ Py_InitializeFromConfig : function({$IFDEF FPC}constref{$ELSE}[Ref] const{$ENDIF} config: PyConfig): PyStatus; cdecl;
+
+ // PEP 741 Initialization functions - python 3.14+
+ PyInitConfig_Create : function(): PPyInitConfig; cdecl;
+ PyInitConfig_Free : procedure(config: PPyInitConfig); cdecl;
+ Py_InitializeFromInitConfig : function(config: PPyInitConfig): Integer; cdecl;
+ PyInitConfig_SetInt : function(config: PPyInitConfig; name: PAnsiChar; value: Int64): Integer; cdecl;
+ PyInitConfig_SetStr : function(config: PPyInitConfig; name: PAnsiChar; value: PAnsiChar): Integer; cdecl;
+ PyInitConfig_SetStrList : function(config: PPyInitConfig; name: PAnsiChar; Lenght: Py_ssize_t; value: PPAnsiChar): Integer; cdecl;
+ PyInitConfig_GetError : function(config: PPyInitConfig; err_msg: PPAnsiChar): integer; cdecl;
+ PyConfig_Get : function(name: PAnsiChar): PPyObject; cdecl;
+ PyConfig_Set : function(name: PAnsiChar; value: PPyObject): Integer; cdecl;
+
function Py_CompileString(str,filename:PAnsiChar;start:integer) : PPyObject; cdecl;
// functions redefined in Delphi
@@ -1851,7 +1954,6 @@ TPythonInterface=class(TDynamicDll)
function PyWeakref_CheckProxy( obj : PPyObject ) : Boolean;
function PyBool_Check( obj : PPyObject ) : Boolean;
function PyEnum_Check( obj : PPyObject ) : Boolean;
- function Py_InitModule( const md : PyModuleDef) : PPyObject;
// The following are defined as non-exported inline functions in object.h
function Py_Type(ob: PPyObject): PPyTypeObject; inline;
@@ -1880,15 +1982,26 @@ TPythonInterface=class(TDynamicDll)
//--------------------------------------------------------
type
TDatetimeConversionMode = (dcmToTuple, dcmToDatetime);
+ TPythonFlag = (pfDebug, pfInteractive, pfNoSite, pfOptimize, pfVerbose,
+ pfFrozen, pfIgnoreEnvironment, pfNoUserSiteDirectory,
+ pfDontWriteBytecode, pfIsolated);
+ TPythonFlags = set of TPythonFlag;
+
const
DEFAULT_DATETIME_CONVERSION_MODE = dcmToTuple;
+ DEFAULT_FLAGS =
+ {$IFDEF IOS}
+ [pfIsolated, pfNoUserSiteDirectory, pfIgnoreEnvironment,
+ pfDontWriteBytecodeFlag]
+ {$ELSE}
+ []
+ {$ENDIF IOS};
+
type
TEngineClient = class;
- TPathInitializationEvent = procedure ( Sender : TObject; var Path : string ) of Object;
- TSysPathInitEvent = procedure ( Sender : TObject; PathList : PPyObject ) of Object;
- TPythonFlag = (pfDebug, pfInteractive, pfNoSite, pfOptimize, pfVerbose,
- pfFrozenFlag, pfIgnoreEnvironmentFlag);
- TPythonFlags = set of TPythonFlag;
+ TSysPathInitEvent = procedure(Sender: TObject; PathList: PPyObject) of object;
+ // Config will be either PPyConfig if version < 3.14 or PPyInitConfig
+ TConfigInitEvent = procedure(Sender: TObject; Config: Pointer) of object;
TTracebackItem = class
@@ -1925,7 +2038,7 @@ TPythonType = class; //forward declaration
{$IFEND}
TPythonEngine = class(TPythonInterface)
private
- FVenvPythonExe: string;
+ FPythonExecutable: string;
FInitScript: TStrings;
FIO: TPythonInputOutput;
FRedirectIO: Boolean;
@@ -1933,12 +2046,11 @@ TPythonEngine = class(TPythonInterface)
FClients: TList;
FExecModule: AnsiString;
FAutoFinalize: Boolean;
- FProgramName: WCharTString;
- FPythonHome: WCharTString;
- FPythonPath: WCharTString;
- FInitThreads: Boolean;
- FOnPathInitialization: TPathInitializationEvent;
+ FProgramName: UnicodeString;
+ FPythonHome: UnicodeString;
+ FPythonPath: UnicodeString;
FOnSysPathInit: TSysPathInitEvent;
+ FOnConfigInit: TConfigInitEvent;
FTraceback: TPythonTraceback;
FUseWindowsConsole: Boolean;
FGlobalVars: PPyObject;
@@ -1955,10 +2067,6 @@ TPythonEngine = class(TPythonInterface)
FPyDateTime_TZInfoType: PPyObject;
FPyDateTime_TimeTZType: PPyObject;
FPyDateTime_DateTimeTZType: PPyObject;
- function GetPythonHome: UnicodeString;
- function GetProgramName: UnicodeString;
- function GetPythonPath: UnicodeString;
- procedure SetPythonPath(const Value: UnicodeString);
protected
procedure Initialize;
@@ -1968,20 +2076,16 @@ TPythonEngine = class(TPythonInterface)
procedure DoOpenDll(const aDllName : string); override;
procedure SetInitScript(Value: TStrings);
function GetThreadState: PPyThreadState;
- procedure SetInitThreads(Value: Boolean);
function GetClientCount : Integer;
function GetClients( idx : Integer ) : TEngineClient;
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
- procedure CheckRegistry;
- procedure SetProgramArgs;
procedure InitWinConsole;
procedure SetUseWindowsConsole( const Value : Boolean );
procedure SetGlobalVars(const Value: PPyObject);
procedure SetLocalVars(const Value: PPyObject);
procedure SetPyFlags(const Value: TPythonFlags);
procedure SetIO(InputOutput: TPythonInputOutput);
- procedure AssignPyFlags;
public
// Constructors & Destructors
@@ -1994,11 +2098,8 @@ TPythonEngine = class(TPythonInterface)
function Run_CommandAsString(const command: AnsiString; mode: Integer; const FileName: string = ''): string;
function Run_CommandAsObject(const command: AnsiString; mode: Integer; const FileName: string = ''): PPyObject;
function Run_CommandAsObjectWithDict(const command: AnsiString; mode: Integer; locals, globals: PPyObject; const FileName: string = ''): PPyObject;
- function EncodeString (const str: UnicodeString): AnsiString; {$IFDEF FPC}overload;{$ENDIF}
- {$IFDEF FPC}
- overload;
- function EncodeString (const str: AnsiString): AnsiString; overload;
- {$ENDIF}
+ function EncodeString(const str: UnicodeString): AnsiString; overload;
+ function EncodeString(const str: AnsiString): AnsiString; overload;
function EncodeWindowsFilePath(const str: string): AnsiString;
procedure ExecString(const command: AnsiString; const FileName: string = ''); overload;
procedure ExecStrings(strings: TStrings; const FileName: string = ''); overload;
@@ -2037,6 +2138,7 @@ TPythonEngine = class(TPythonInterface)
function ArrayToPyDict( const items : array of const) : PPyObject;
function StringsToPyList( strings : TStrings ) : PPyObject;
function StringsToPyTuple( strings : TStrings ) : PPyObject;
+ function Py_InitModule( const md : PyModuleDef) : PPyObject;
procedure PyListToStrings(list: PPyObject; Strings: TStrings; ClearStrings: Boolean = True);
procedure PyTupleToStrings( tuple: PPyObject; strings : TStrings );
function GetSequenceItem( sequence : PPyObject; idx : Integer ) : Variant;
@@ -2079,22 +2181,25 @@ TPythonEngine = class(TPythonInterface)
property LocalVars : PPyObject read FLocalVars Write SetLocalVars;
property GlobalVars : PPyObject read FGlobalVars Write SetGlobalVars;
property IOPythonModule: TObject read FIOPythonModule; {TPythonModule}
- property PythonHome: UnicodeString read GetPythonHome write SetPythonHome;
- property ProgramName: UnicodeString read GetProgramName write SetProgramName;
- property PythonPath: UnicodeString read GetPythonPath write SetPythonPath;
+ property PythonHome: UnicodeString read FPythonHome write SetPythonHome;
+ property ProgramName: UnicodeString read FProgramName write SetProgramName;
+ // List of paths separated with the path delimiter
+ // If used with pfNoSite, it completely overwrites the pyhon path on initialization!
+ // For adding directories to sys.path use the OnSysPathInit event instead.
+ property PythonPath: UnicodeString read FPythonPath write FPythonPath;
published
property AutoFinalize: Boolean read FAutoFinalize write FAutoFinalize default True;
- property VenvPythonExe: string read FVenvPythonExe write FVenvPythonExe;
+ property PythonExecutable: string read FPythonExecutable write FPythonExecutable;
property DatetimeConversionMode: TDatetimeConversionMode read FDatetimeConversionMode write FDatetimeConversionMode default DEFAULT_DATETIME_CONVERSION_MODE;
property InitScript: TStrings read FInitScript write SetInitScript;
- property InitThreads: Boolean read FInitThreads write SetInitThreads default False;
property IO: TPythonInputOutput read FIO write SetIO;
- property PyFlags: TPythonFlags read FPyFlags write SetPyFlags default [];
+ property PyFlags: TPythonFlags read FPyFlags write SetPyFlags default DEFAULT_FLAGS;
property RedirectIO: Boolean read FRedirectIO write FRedirectIO default True;
- property UseWindowsConsole: Boolean read FUseWindowsConsole write FUseWindowsConsole default False;
+ property UseWindowsConsole: Boolean read FUseWindowsConsole write SetUseWindowsConsole default False;
property OnAfterInit: TNotifyEvent read FOnAfterInit write FOnAfterInit;
- property OnPathInitialization: TPathInitializationEvent read FOnPathInitialization write FOnPathInitialization;
property OnSysPathInit: TSysPathInitEvent read FOnSysPathInit write FOnSysPathInit;
+ property OnConfigInit: TConfigInitEvent read FOnConfigInit write FOnConfigInit;
+
end;
@@ -2199,7 +2304,6 @@ TMethodsContainer = class(TEngineClient)
FMethodCount : Integer;
FAllocatedMethodCount : Integer;
FMethods : PPyMethodDef;
- FModuleDef : PyModuleDef;
FEventDefs: TEventDefs;
procedure AllocMethods;
@@ -2243,7 +2347,6 @@ TMethodsContainer = class(TEngineClient)
property MethodCount : Integer read FMethodCount;
property Methods[ idx : Integer ] : PPyMethodDef read GetMethods;
property MethodsData : PPyMethodDef read FMethods;
- property ModuleDef : PyModuleDef read FModuleDef;
published
property Events: TEventDefs read fEventDefs write fEventDefs stored StoreEventDefs;
@@ -2372,8 +2475,8 @@ TError = class(TCollectionItem)
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
procedure BuildError( const ModuleName : AnsiString );
- procedure RaiseError( const msg : AnsiString );
- procedure RaiseErrorObj( const msg : AnsiString; obj : PPyObject );
+ procedure RaiseError(const msg : AnsiString);
+ procedure RaiseErrorObj(const msg : AnsiString; obj : PPyObject);
function Owner : TErrors;
property Error : PPyObject read FError write FError;
published
@@ -2398,65 +2501,71 @@ TErrors = class(TCollection)
property Items[Index: Integer]: TError read GetError write SetError; default;
end;
+ TMultIntperpretersSupport = (mmiSupported, mmiNotSupported, mmiPerInterpreterGIL);
+
{$IF not Defined(FPC) and (CompilerVersion >= 23)}
[ComponentPlatformsAttribute(pidSupportedPlatforms)]
{$IFEND}
TPythonModule = class(TMethodsContainer)
- protected
- FModuleName : AnsiString;
- FModule : PPyObject;
- FClients : TList;
- FErrors : TErrors;
- FOnAfterInitialization : TNotifyEvent;
- FDocString : TStringList;
-
- function GetClientCount : Integer;
- function GetClients( idx : Integer ) : TEngineClient;
- procedure SetErrors( val : TErrors );
- procedure SetModuleName( const val : AnsiString );
- procedure SetDocString( value : TStringList );
- public
- // Constructors & destructors
- constructor Create( AOwner : TComponent ); override;
- destructor Destroy; override;
+ private
+ FModuleDef : PyModuleDef;
+ FMultInterpretersSupport: TMultIntperpretersSupport;
+ FEncodedDocString: AnsiString;
+ FIsExtensionModule: Boolean;
+ function Exec_Module(module: PPyObject): Integer; cdecl; // used in the slot
+ protected
+ FModuleName : AnsiString;
+ FModule : PPyObject;
+ FSlots: TArray;
+ FClients : TList;
+ FErrors : TErrors;
+ FDocString : TStringList;
+ FOnAfterInitialization : TNotifyEvent;
+
+ function GetClientCount : Integer;
+ function GetClients( idx : Integer ) : TEngineClient;
+ procedure SetErrors( val : TErrors );
+ procedure SetModuleName( const val : AnsiString );
+ procedure SetDocString( value : TStringList );
+ public
+ // Constructors & destructors
+ constructor Create( AOwner : TComponent ); override;
+ destructor Destroy; override;
- // Public methods
- procedure MakeModule;
- procedure DefineDocString;
- procedure Initialize; override;
- procedure InitializeForNewInterpreter;
- procedure AddClient(Client : TEngineClient);
- procedure RemoveClient(Client : TEngineClient);
- function ErrorByName( const AName : AnsiString ) : TError;
- procedure RaiseError( const error, msg : AnsiString );
- procedure RaiseErrorFmt( const error, format : AnsiString; const Args : array of const );
- procedure RaiseErrorObj( const error, msg : AnsiString; obj : PPyObject );
- procedure BuildErrors;
- procedure SetVar( const varName : AnsiString; value : PPyObject );
- function GetVar( const varName : AnsiString ) : PPyObject;
- procedure DeleteVar( const varName : AnsiString );
- procedure ClearVars;
- procedure SetVarFromVariant( const varName : AnsiString; const value : Variant );
- function GetVarAsVariant( const varName: AnsiString ) : Variant;
+ // Public methods
+ procedure MakeModuleDef;
+ procedure Initialize; override;
+ procedure InitializeForNewInterpreter;
+ procedure AddClient(Client : TEngineClient);
+ procedure RemoveClient(Client : TEngineClient);
+ function ErrorByName( const AName : AnsiString ) : TError;
+ procedure RaiseError( const error, msg : AnsiString );
+ procedure RaiseErrorFmt( const error, format : AnsiString; const Args : array of const );
+ procedure RaiseErrorObj( const error, msg : AnsiString; obj : PPyObject );
+ procedure BuildErrors;
+ procedure SetVar( const varName : AnsiString; value : PPyObject );
+ function GetVar( const varName : AnsiString ) : PPyObject;
+ procedure DeleteVar( const varName : AnsiString );
+ procedure ClearVars;
+ procedure SetVarFromVariant( const varName : AnsiString; const value : Variant );
+ function GetVarAsVariant( const varName: AnsiString ) : Variant;
- // Public properties
- property Module : PPyObject read FModule;
- property Clients[ idx : Integer ] : TEngineClient read GetClients;
- property ClientCount : Integer read GetClientCount;
- published
- property DocString : TStringList read FDocString write SetDocString;
- property ModuleName : AnsiString read FModuleName write SetModuleName;
- property Errors : TErrors read FErrors write SetErrors;
- property OnAfterInitialization : TNotifyEvent read FOnAfterInitialization write FOnAfterInitialization;
+ // Public properties
+ property Module : PPyObject read FModule;
+ property ModuleDef : PyModuleDef read FModuleDef;
+ property IsExtensionModule: Boolean read FIsExtensionModule write FIsExtensionModule;
+ property Clients[ idx : Integer ] : TEngineClient read GetClients;
+ property ClientCount : Integer read GetClientCount;
+ published
+ property DocString : TStringList read FDocString write SetDocString;
+ property ModuleName : AnsiString read FModuleName write SetModuleName;
+ property MultInterpretersSupport: TMultIntperpretersSupport
+ read FMultInterpretersSupport write FMultInterpretersSupport;
+ property Errors : TErrors read FErrors write SetErrors;
+ property OnAfterInitialization : TNotifyEvent read FOnAfterInitialization write FOnAfterInitialization;
end;
-//-------------------------------------------------------
-//-- --
-//--class: TPythonType derived from TGetSetContainer --
-//-- --
-//-------------------------------------------------------
-
{
A B C
+-------------------++------------------------------------------------------+
@@ -2473,15 +2582,15 @@ TPythonModule = class(TMethodsContainer)
by GetSelf
- a Python object must start at A.
- - a Delphi class class must start at B
+ - a Delphi class must start at B
- TPyObject.InstanceSize will return C-B
- Sizeof(TPyObject) will return C-B
- The total memory allocated for a TPyObject instance will be C-A,
even if its InstanceSize is C-B.
- - When turning a Python object pointer into a Delphi instance pointer, PythonToDelphi
- will offset the pointer from A to B.
- - When turning a Delphi instance into a Python object pointer, GetSelf will offset
- Self from B to A.
+ - When turning a Python object pointer into a Delphi instance pointer,
+ PythonToDelphi will offset the pointer from A to B.
+ - When turning a Delphi instance into a Python object pointer, GetSelf
+ will offset Self from B to A.
- Properties ob_refcnt and ob_type will call GetSelf to access their data.
Further Notes:
@@ -2498,12 +2607,11 @@ TPythonModule = class(TMethodsContainer)
FreeInstance.
- This class is heart of the P4D library. Pure magic!!
}
- // The base class of all new Python types
TPyObject = class
private
- function Get_ob_refcnt: NativeInt;
+ function Get_ob_refcnt: NativeUInt;
function Get_ob_type: PPyTypeObject;
- procedure Set_ob_refcnt(const Value: NativeInt);
+ procedure Set_ob_refcnt(const Value: NativeUInt);
procedure Set_ob_type(const Value: PPyTypeObject);
public
PythonType : TPythonType;
@@ -2524,7 +2632,7 @@ TPyObject = class
procedure Adjust(PyPointer: Pointer);
function GetModule : TPythonModule;
- property ob_refcnt : NativeInt read Get_ob_refcnt write Set_ob_refcnt;
+ property ob_refcnt : NativeUInt read Get_ob_refcnt write Set_ob_refcnt;
property ob_type : PPyTypeObject read Get_ob_type write Set_ob_type;
// Type services
@@ -2668,8 +2776,15 @@ TTypeServices = class(TPersistent)
property Mapping : TMappingServices read FMapping write FMapping;
end;
- // The component that initializes the Python type and
- // that creates instances of itself.
+//-------------------------------------------------------
+//-- --
+//--class: TPythonType derived from TGetSetContainer --
+//-- --
+//-------------------------------------------------------
+
+ // The component that initializes a Python type and
+ // creates instances of itself.
+ // The base class of all new Python types
{$IF not Defined(FPC) and (CompilerVersion >= 23)}
[ComponentPlatformsAttribute(pidSupportedPlatforms)]
{$IFEND}
@@ -2857,9 +2972,9 @@ TPythonThread = class(TThread)
private class threadvar
f_savethreadstate: PPyThreadState;
+ protected
// Do not overwrite Execute! Use ExecuteWithPython instead!
procedure Execute; override;
- protected
procedure ExecuteWithPython; virtual; abstract;
function InterpreterConfig: PyInterpreterConfig; virtual;
public
@@ -2914,6 +3029,7 @@ procedure PythonVersionFromDLLName(LibName: string; out MajorVersion, MinorVersi
function PythonVersionFromRegVersion(const ARegVersion: string;
out AMajorVersion, AMinorVersion: integer): boolean;
function PyStatus_Exception(const APyStatus: PyStatus): Boolean;
+function StringToWCharTString(Str: string): WcharTString;
//#######################################################
//## ##
@@ -2971,9 +3087,8 @@ function CleanString(const s : UnicodeString; AppendLF : Boolean = True) : Unico
implementation
uses
-{$IFDEF FPC}
StrUtils,
-{$ELSE}
+{$IFNDEF FPC}
AnsiStrings,
{$ENDIF}
{$IFDEF MSWINDOWS}
@@ -2995,6 +3110,61 @@ implementation
SPyConvertionError = 'Conversion Error: %s expects a %s Python object';
SPyExcStopIteration = 'Stop Iteration';
SPyExcSystemError = 'Unhandled SystemExit exception. Code: %s';
+SPyInitFailed = 'Python initialization failed: %s';
+SPyInitFailedUnknown = 'Unknown initialization error';
+SCannotCreateMain = 'Run_CommandAsObject: can''t create __main__';
+SRaiseError = 'RaiseError: couldn''t fetch last exception';
+SMissingModuleDateTime = 'dcmToDatetime DatetimeConversionMode cannot be used with this version of python. Missing module datetime';
+SInvalidDateTimeConvMode = 'Invalid DatetimeConversionMode';
+SUnexpectedTypeInTimeObject = 'Unexpected type found in member %s of a time_struct object';
+SArguementTypeNotAllowed = 'Argument type not allowed';
+SCouldNotCreateTuple = 'Could not create a new tuple object';
+SCouldNotCreateList = 'Could not create a new list object';
+SCouldNotCreateDict = 'Could not create a new dict object';
+SArgumemntsShouldBeEven = 'You must provide an even number of arguments';
+SExpectedList = 'The python object is not a list';
+SExpectedTuple = 'The python object is not a tuple';
+SCouldNotSetVar = 'Could not set var "%s" in module "%s"';
+SCannotSetVarNoInit = 'Can''t set var "%s" in module "%s", because it is not yet initialized';
+SCannotGetDict = 'Can''t get __dict__ of module "%s"';
+SCannotDelVarNoInit = 'Can''t delete var "%s" in module "%s", because it is not yet initialized';
+SExpectedDelphiClass = 'Pytho;n object "%s" is not a Delphi class';
+SCannotCreateModule = 'CreateVar: can''t create module "%s"';
+SVarNotCreated = 'No variable was created';
+SVarExists = 'A variable "%s" already exists in the module "%s"';
+SCannotCreateThreadState = 'Could not create a new thread state';
+SCannotCreatePythonEngine = 'No Python engine was created';
+SCannotInitPythonEngine = 'The Python engine is not properly initialized';
+SThreadPythonExec = 'ThreadPythonExec should only be called from the main thread';
+SQuitMessage = 'Dll %s could not be loaded. We must quit.';
+SPythonQuitMessage = 'Python DLL %s could not be initialized. We must quit.';
+SErrCannotOpenDLL = 'Error %d: Could not open Dll "%s"';
+SPythonNoInit = 'Python is not initialized';
+SOnlyOnePythonEngine = 'You canott have more than one TPythonEngine component';
+SMoreThanOnePythonEngine = 'There is already one instance of TPythonEngine running';
+SGlobalVarsShouldBeDict = 'You must set a Python dictionary in the GlobalVars property';
+SLocalVarsShouldBeDict = 'You must set a Python dictionary in the LocalVars property';
+SCannotModifyFlags = 'You can''t modify Python flags after it has been initialized';
+SCannotFindType = 'Could not find type: %s';
+SCannotFindModule = 'Could not find module: %s';
+SCannotFindComponent = 'Could not find component: %s';
+SCannotHandleMoreThan3Dim = 'Can''t convert a variant array of more than 3 dimensions to a Python sequence';
+SNoEngineForComponent = 'No Engine defined for component "%s"';
+SIndexOutOfRange = '%s: Index %d out of range';
+SUnknownMemberType = 'Unknown member type';
+SUnknownMemberFlag = 'Unknown member flag';
+SDuplicateErrorName = 'In module "%s", there''s already an error named "%s"';
+SNoModuleWithParentClass = 'Could not find module containing the parent class of error "%s"';
+SCannotFindParentClass = 'Could not find the parent class "%s" of error "%s"';
+SObjectNotClass = 'The object "%s" in module "%s" is not a class';
+SErrorNotClass = 'Error without name in module "%s"';
+SCouldNotCreateError = 'Could not create error "%s"';
+STErrorCouldNotCreateInstance = 'TError.RaiseErrorObj: Could not create an instance of "%s"';
+STErrorCouldNotCreateTuple = 'TError.RaiseErrorObj: Could not create an empty tuple';
+STErrorNoInstance = 'TError.RaiseErrorObj: I didn''t get an instance';
+SCouldNotFindError = 'Could not find error "%s"';
+SCouldNotMapSymbol = 'Error %d: could not map symbol "%s"';
+SUndeterminedPythonVersion = 'Undetermined Python version';
(*******************************************************)
(** **)
@@ -3346,7 +3516,7 @@ procedure TDynamicDll.OpenDll(const aDllName : string);
if not IsHandleValid then begin
{$IFDEF MSWINDOWS}
- s := Format('Error %d: Could not open Dll "%s"',[GetLastError, DllName]);
+ s := Format(SErrCannotOpenDLL, [GetLastError, DllName]);
{$ELSE}
s := Format('Error: Could not open Dll "%s"',[DllName]);
{$ENDIF}
@@ -3394,7 +3564,7 @@ function TDynamicDll.Import(const funcname: AnsiString; canFail : Boolean = True
{$IFEND}
if (Result = nil) and canFail then begin
{$IFDEF MSWINDOWS}
- E := EDllImportError.CreateFmt('Error %d: could not map symbol "%s"', [GetLastError, funcname]);
+ E := EDllImportError.CreateFmt(SCouldNotMapSymbol, [GetLastError, funcname]);
E.ErrorCode := GetLastError;
{$ELSE}
E := EDllImportError.CreateFmt('Error: could not map symbol "%s"', [funcname]);
@@ -3489,7 +3659,7 @@ procedure TDynamicDll.LoadPythonInfoFromModule;
end;
if not LFound then
- raise EDLLLoadError.Create('Undetermined Python version from loaded module.');
+ raise EDLLLoadError.Create(SUndeterminedPythonVersion);
end;
procedure TDynamicDll.LoadDll;
@@ -3542,7 +3712,7 @@ procedure TDynamicDll.BeforeUnload;
function TDynamicDll.GetQuitMessage : string;
begin
- Result := Format( 'Dll %s could not be loaded. We must quit.', [DllName]);
+ Result := Format(SQuitMessage, [DllName]);
end;
function TDynamicDll.HasPythonSymbolsInLibrary: boolean;
@@ -3615,7 +3785,7 @@ procedure TPythonInterface.AfterLoad;
if not FInExtensionModule then
PythonVersionFromDLLName(DLLName, FMajorVersion, FMinorVersion)
else if not PythonVersionFromRegVersion(RegVersion, FMajorVersion, FMinorVersion) then
- raise EDLLLoadError.Create('Undetermined Python version.');
+ raise EDLLLoadError.Create(SUndeterminedPythonVersion);
FBuiltInModuleName := 'builtins';
@@ -3636,26 +3806,17 @@ procedure TPythonInterface.AfterLoad;
function TPythonInterface.GetQuitMessage : string;
begin
- Result := Format( 'Python could not be properly initialized. We must quit.', [DllName]);
+ Result := Format(SPythonQuitMessage, [DllName]);
end;
procedure TPythonInterface.CheckPython;
begin
if not Initialized then
- raise Exception.Create('Python is not properly initialized' );
+ raise Exception.Create(SPythonNoInit);
end;
procedure TPythonInterface.MapDll;
begin
- Py_DebugFlag := Import('Py_DebugFlag');
- Py_VerboseFlag := Import('Py_VerboseFlag');
- Py_InteractiveFlag := Import('Py_InteractiveFlag');
- Py_OptimizeFlag := Import('Py_OptimizeFlag');
- Py_NoSiteFlag := Import('Py_NoSiteFlag');
- Py_FrozenFlag := Import('Py_FrozenFlag');
-
- Py_IgnoreEnvironmentFlag := Import('Py_IgnoreEnvironmentFlag');
-
Py_None := Import('_Py_NoneStruct');
Py_Ellipsis := Import('_Py_EllipsisObject');
Py_False := Import('_Py_FalseStruct');
@@ -3738,6 +3899,7 @@ procedure TPythonInterface.MapDll;
PyStaticMethod_Type := Import('PyStaticMethod_Type');
PySuper_Type := Import('PySuper_Type');
PyTraceBack_Type := Import('PyTraceBack_Type');
+ PyGetSetDescr_Type := Import('PyGetSetDescr_Type');
PyWrapperDescr_Type := Import('PyWrapperDescr_Type');
_PyWeakref_RefType := Import('_PyWeakref_RefType');
_PyWeakref_ProxyType := Import('_PyWeakref_ProxyType');
@@ -3771,6 +3933,9 @@ procedure TPythonInterface.MapDll;
PyDict_SetItemString := Import('PyDict_SetItemString');
PyDictProxy_New := Import('PyDictProxy_New');
PyModule_Create2 := Import('PyModule_Create2');
+ PyModuleDef_Init := Import('PyModuleDef_Init');
+ PyModule_ExecDef := Import('PyModule_ExecDef');
+ PyModule_FromDefAndSpec2 := Import('PyModule_FromDefAndSpec2');
PyErr_Print := Import('PyErr_Print');
PyErr_SetNone := Import('PyErr_SetNone');
PyErr_SetObject := Import('PyErr_SetObject');
@@ -3798,7 +3963,6 @@ procedure TPythonInterface.MapDll;
PyRun_String := Import('PyRun_String');
PyRun_SimpleString := Import('PyRun_SimpleString');
PyDict_GetItemString := Import('PyDict_GetItemString');
- PySys_SetArgv := Import('PySys_SetArgv');
Py_Exit := Import('Py_Exit');
PyCFunction_NewEx := Import('PyCFunction_NewEx');
@@ -3813,11 +3977,9 @@ procedure TPythonInterface.MapDll;
if (FMajorVersion > 3) or (FMinorVersion > 9) then
PyBuffer_SizeFromFormat := Import('PyBuffer_SizeFromFormat');
- PyEval_CallObjectWithKeywords:= Import('PyEval_CallObjectWithKeywords');
PyEval_GetFrame := Import('PyEval_GetFrame');
PyEval_GetGlobals := Import('PyEval_GetGlobals');
PyEval_GetLocals := Import('PyEval_GetLocals');
- PyEval_InitThreads := Import('PyEval_InitThreads');
PyEval_RestoreThread := Import('PyEval_RestoreThread');
PyEval_SaveThread := Import('PyEval_SaveThread');
PyFile_GetLine := Import('PyFile_GetLine');
@@ -3858,6 +4020,7 @@ procedure TPythonInterface.MapDll;
PyLong_FromLongLong := Import('PyLong_FromLongLong');
PyLong_FromUnsignedLongLong := Import('PyLong_FromUnsignedLongLong');
PyLong_AsLongLong := Import('PyLong_AsLongLong');
+ PyLong_AsVoidPtr := Import('PyLong_AsVoidPtr');
PyLong_FromVoidPtr := Import('PyLong_FromVoidPtr');
PyMapping_Check := Import('PyMapping_Check');
PyMapping_GetItemString := Import('PyMapping_GetItemString');
@@ -3977,7 +4140,6 @@ procedure TPythonInterface.MapDll;
PySet_Size := Import('PySet_Size');
PySys_GetObject := Import('PySys_GetObject');
PySys_SetObject := Import('PySys_SetObject');
- PySys_SetPath := Import('PySys_SetPath');
PyTraceBack_Here := Import('PyTraceBack_Here');
PyTraceBack_Print := Import('PyTraceBack_Print');
PyTuple_GetItem := Import('PyTuple_GetItem');
@@ -4020,24 +4182,14 @@ procedure TPythonInterface.MapDll;
Py_GetCopyright := Import('Py_GetCopyright');
Py_GetExecPrefix := Import('Py_GetExecPrefix');
Py_GetPath := Import('Py_GetPath');
- Py_SetPath := Import('Py_SetPath');
- Py_SetPythonHome := Import('Py_SetPythonHome');
Py_GetPythonHome := Import('Py_GetPythonHome');
Py_GetPrefix := Import('Py_GetPrefix');
Py_GetProgramName := Import('Py_GetProgramName');
- if (FMajorVersion = 3) and (FMinorVersion < 10) then
- begin
- PyParser_SimpleParseStringFlags := Import('PyParser_SimpleParseStringFlags');
- PyNode_Free := Import('PyNode_Free');
- end;
+ PyErr_NewException := Import('PyErr_NewException');
+ PyMem_Malloc := Import ('PyMem_Malloc');
+ PyMem_Free := Import ('PyMem_Free');
- PyErr_NewException := Import('PyErr_NewException');
- try
- PyMem_Malloc := Import ('PyMem_Malloc');
- except
- end;
- Py_SetProgramName := Import('Py_SetProgramName');
Py_IsInitialized := Import('Py_IsInitialized');
Py_GetProgramFullPath := Import('Py_GetProgramFullPath');
Py_GetBuildInfo := Import('Py_GetBuildInfo');
@@ -4045,8 +4197,6 @@ procedure TPythonInterface.MapDll;
if (FMajorVersion > 3) or (FMinorVersion >= 12) then
Py_NewInterpreterFromConfig := Import('Py_NewInterpreterFromConfig');
Py_EndInterpreter := Import('Py_EndInterpreter');
- PyEval_AcquireLock := Import('PyEval_AcquireLock');
- PyEval_ReleaseLock := Import('PyEval_ReleaseLock');
PyEval_AcquireThread := Import('PyEval_AcquireThread');
PyEval_ReleaseThread := Import('PyEval_ReleaseThread');
PyInterpreterState_New := Import('PyInterpreterState_New');
@@ -4060,6 +4210,31 @@ procedure TPythonInterface.MapDll;
PyErr_SetInterrupt := Import('PyErr_SetInterrupt');
PyGILState_Ensure := Import('PyGILState_Ensure');
PyGILState_Release := Import('PyGILState_Release');
+
+ PyWideStringList_Append := Import('PyWideStringList_Append');
+ PyWideStringList_Insert := Import('PyWideStringList_Insert');
+ PyConfig_InitPythonConfig := Import('PyConfig_InitPythonConfig');
+ PyConfig_InitIsolatedConfig := Import('PyConfig_InitIsolatedConfig');
+ PyConfig_Clear := Import('PyConfig_Clear');
+ PyConfig_SetString := Import('PyConfig_SetString');
+ PyConfig_Read := Import('PyConfig_Read');
+ PyConfig_SetArgv := Import('PyConfig_SetArgv');
+ PyConfig_SetWideStringList := Import('PyConfig_SetWideStringList');
+ Py_InitializeFromConfig := Import('Py_InitializeFromConfig');
+
+ // PEP 741
+ if (MajorVersion > 3) or (MinorVersion >= 14) then
+ begin
+ PyInitConfig_Create := Import('PyInitConfig_Create');
+ PyInitConfig_Free := Import('PyInitConfig_Free');
+ Py_InitializeFromInitConfig := Import('Py_InitializeFromInitConfig');
+ PyInitConfig_SetInt := Import('PyInitConfig_SetInt');
+ PyInitConfig_SetStr := Import('PyInitConfig_SetStr');
+ PyInitConfig_SetStrList := Import('PyInitConfig_SetStrList');
+ PyInitConfig_GetError := Import('PyInitConfig_GetError');
+ PyConfig_Get := Import('PyConfig_Get');
+ PyConfig_Set := Import('PyConfig_Set');
+ end;
end;
function TPythonInterface.Py_CompileString(str,filename:PAnsiChar;start:integer):PPyObject;
@@ -4067,11 +4242,6 @@ function TPythonInterface.Py_CompileString(str,filename:PAnsiChar;start:integer)
Result := Py_CompileStringExFlags(str, filename, start, nil, -1);
end;
-function TPythonInterface.PyParser_SimpleParseString( str : PAnsiChar; start : integer) : PNode; cdecl;
-begin
- Result := PyParser_SimpleParseStringFlags(str, start, 0);
-end;
-
class procedure TPythonInterface.Py_INCREF(op: PPyObject);
begin
Inc(op^.ob_refcnt);
@@ -4290,21 +4460,6 @@ function TPythonInterface.PyObject_TypeCheck(obj: PPyObject; t: PPyTypeObject):
Result := IsType(obj, t) or (PyType_IsSubtype(obj^.ob_type, t) = 1);
end;
-function TPythonInterface.Py_InitModule(const md: PyModuleDef): PPyObject;
-Var
- modules : PPyObject;
-begin
- CheckPython;
- Result:= PyModule_Create2(@md, APIVersion);
- if not Assigned(Result) then
- GetPythonEngine.CheckError;
- // To emulate Py_InitModule4 we need to add the module to sys.modules
- modules := PyImport_GetModuleDict;
- if PyDict_SetItemString(modules, md.m_name, Result) <> 0 then
- GetPythonEngine.CheckError;
-end;
-
-
(*******************************************************)
(** **)
(** class TPythonTraceback **)
@@ -4364,7 +4519,7 @@ procedure TPythonTraceback.Clear;
* This method is automatically called by the Exec/Eval methods of
* TPythonEngine. But if you use the Python core API, then don't
* forget to refresh the traceback yourself. Or much better,
- * simply use the method CheckError wich will call PyErr_Print,
+ * simply use the method CheckError which will call PyErr_Print,
* Traceback.Refresh and RaiseError for you.
}
procedure TPythonTraceback.Refresh(pytraceback: PPyObject);
@@ -4481,17 +4636,16 @@ constructor TPythonEngine.Create(AOwner: TComponent);
FRedirectIO := True;
FExecModule := '__main__';
FAutoFinalize := True;
- FInitThreads := False;
FTraceback := TPythonTraceback.Create;
FUseWindowsConsole := False;
- FPyFlags := [];
+ FPyFlags := DEFAULT_FLAGS;
FDatetimeConversionMode := DEFAULT_DATETIME_CONVERSION_MODE;
if csDesigning in ComponentState then
begin
for i := 0 to AOwner.ComponentCount - 1 do
if (AOwner.Components[i] is TPythonEngine) and
(AOwner.Components[i] <> Self) then
- raise Exception.Create('You can''t drop more than one TPythonEngine component');
+ raise Exception.Create(SOnlyOnePythonEngine);
end;
end;
@@ -4596,45 +4750,250 @@ procedure TPythonEngine.DoOpenDll(const aDllName : string);
end;
end;
-procedure TPythonEngine.AssignPyFlags;
+procedure TPythonEngine.Initialize;
+
+ procedure ConfigPEP587(var ErrMsg: string);
+ // Initialize according to PEP587 available since python 3.8
+
+ procedure AssignPyFlags(var Config: PyConfig);
+ begin
+ PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.parser_debug])^ :=
+ IfThen(pfDebug in FPyFlags, 1, 0);
+ PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.verbose])^ :=
+ IfThen(pfVerbose in FPyFlags, 1, 0);
+ PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.interactive])^ :=
+ IfThen(pfInteractive in FPyFlags, 1, 0);
+ PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.optimization_level])^ :=
+ IfThen(pfOptimize in FPyFlags, 1, 0);
+ PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.site_import])^ :=
+ IfThen(pfNoSite in FPyFlags, 0, 1);
+ PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.pathconfig_warnings])^ :=
+ IfThen(pfFrozen in FPyFlags, 1, 0);
+ PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.use_environment])^ :=
+ IfThen(pfIgnoreEnvironment in FPyFlags, 0, 1);
+ end;
+
+ procedure SetProgramArgs(var Config: PyConfig);
+ var
+ I: Integer;
+ TempS: UnicodeString;
+ Str: WCharTString;
+
+ begin
+ // do not parse further
+ PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.parse_argv])^ := 0;
+ for I := 0 to ParamCount do
+ begin
+ {
+ ... the first entry should refer to the script file to be executed rather
+ than the executable hosting the Python interpreter. If there isn’t a
+ script that will be run, the first entry in argv can be an empty string.
+ }
+ if I = 0 then
+ TempS := ''
+ else
+ TempS := ParamStr(I);
+ {$IFDEF POSIX}
+ Str := UnicodeStringToUCS4String(TempS);
+ {$ELSE}
+ Str := TempS;
+ {$ENDIF}
+ PyWideStringList_Append(
+ PPyWideStringList(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.argv]),
+ PWCharT(Str));
+ end;
+ end;
+
+ procedure SetPythonPath(var Config: PyConfig);
+ var
+ Paths: TStringDynArray;
+ I: Integer;
+ PWSL: PPyWideStringList;
+ begin
+ if FPythonPath = '' then Exit;
+
+ PWSL := PPyWideStringList(PByte(@Config) + ConfigOffests[MinorVersion,
+ TConfigFields.module_search_paths]);
+ Paths := SplitString(string(FPythonPath), PathSep);
+ for I := 0 to Length(Paths) - 1 do
+ begin
+ if (Paths[I] = '') and (I > 0) then
+ Continue;
+ PyWideStringList_Append(PWSL, PWCharT(StringToWCharTString(Paths[I])));
+ end;
- procedure SetFlag( AFlag: PInteger; AValue : Boolean );
+ if PWSL^.length > 0 then
+ PInteger(PByte(@Config) + ConfigOffests[MinorVersion,
+ TConfigFields.module_search_paths_set])^ := 1;
+ end;
+
+ var
+ Config: PyConfig;
+ Status: PyStatus;
begin
- if AValue then
- AFlag^ := 1
+ // Fills Config with zeros and then sets some default values
+ if pfIsolated in FPyFlags then
+ PyConfig_InitIsolatedConfig(Config)
else
- AFlag^ := 0;
+ PyConfig_InitPythonConfig(Config);
+ try
+ AssignPyFlags(Config);
+
+ // Set programname and pythonhome if available
+ if FProgramName <> '' then
+ PyConfig_SetString(Config,
+ PPWcharT(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.program_name]),
+ PWCharT(StringToWCharTString(FProgramName)));
+ if FPythonHome <> '' then
+ PyConfig_SetString(Config,
+ PPWcharT(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.home]),
+ PWCharT(StringToWCharTString(FPythonHome)));
+ // Set venv executable if available
+ if FPythonExecutable <> '' then
+ PyConfig_SetString(Config,
+ PPWcharT(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.executable]),
+ PWCharT(StringToWCharTString(FPythonExecutable)));
+
+ // Set program arguments (sys.argv)
+ SetProgramArgs(Config);
+
+ // PythonPath
+ SetPythonPath(Config);
+
+ // Fine tune Config
+ if Assigned(FOnConfigInit) then
+ FOnConfigInit(Self, @Config);
+
+ Status := Py_InitializeFromConfig(Config);
+ FInitialized := Py_IsInitialized() <> 0;
+
+ if PyStatus_Exception(Status) then
+ ErrMsg := Format(SPyInitFailed, [string(Status.err_msg)])
+ else if not FInitialized then
+ ErrMsg := Format(SPyInitFailed, [SPyInitFailedUnknown]);
+
+ finally
+ PyConfig_Clear(Config);
+ end;
end;
-begin
- // define each Python flag. See file pyDebug.h
- SetFlag(Py_DebugFlag, pfDebug in FPyFlags);
- SetFlag(Py_VerboseFlag, pfVerbose in FPyFlags);
- SetFlag(Py_InteractiveFlag, pfInteractive in FPyFlags);
- SetFlag(Py_OptimizeFlag, pfOptimize in FPyFlags);
- SetFlag(Py_NoSiteFlag, pfNoSite in FPyFlags);
- SetFlag(Py_FrozenFlag, pfFrozenFlag in FPyFlags);
- SetFlag(Py_IgnoreEnvironmentFlag, pfIgnoreEnvironmentFlag in FPyFlags);
-end;
+ procedure ConfigPEP741(var ErrMsg: string);
+ // Initialize according to PEP587 available since python 3.8
-procedure TPythonEngine.Initialize;
+ procedure AssignPyFlags(Config: PPyInitConfig);
+ begin
+ PyInitConfig_SetInt(Config, 'isolated', IfThen(pfIsolated in FPyFlags, 1, 0));
+ PyInitConfig_SetInt(Config, 'parser_debug', IfThen(pfDebug in FPyFlags, 1, 0));
+ PyInitConfig_SetInt(Config, 'verbose', IfThen(pfVerbose in FPyFlags, 1, 0));
+ PyInitConfig_SetInt(Config, 'interactive', IfThen(pfInteractive in FPyFlags, 1, 0));
+ PyInitConfig_SetInt(Config, 'optimization_level', IfThen(pfOptimize in FPyFlags, 1, 0));
+ PyInitConfig_SetInt(Config, 'site_import', IfThen(pfNoSite in FPyFlags, 0, 1));
+ PyInitConfig_SetInt(Config, 'pathconfig_warnings', IfThen(pfFrozen in FPyFlags, 1, 0));
+ PyInitConfig_SetInt(Config, 'use_environment', IfThen(pfIgnoreEnvironment in FPyFlags, 0, 1));
+ PyInitConfig_SetInt(Config, 'user_site_directory', IfThen(pfNoUserSiteDirectory in FPyFlags, 0, 1));
+ PyInitConfig_SetInt(Config, 'write_bytecode', IfThen(pfDontWriteBytecode in FPyFlags, 0, 1));
+ end;
+
+ procedure SetProgramArgs(Config: PPyInitConfig);
+ var
+ I: Integer;
+ Params: TArray;
+ PParams: TArray;
+ begin
+ // do not parse further
+ PyInitConfig_SetInt(Config, 'parse_argv', 0);
+
+ SetLength(Params, ParamCount + 1);
+ SetLength(PParams, ParamCount + 1);
+ for I := 0 to ParamCount do
+ begin
+ {
+ ... the first entry should refer to the script file to be executed rather
+ than the executable hosting the Python interpreter. If there isn’t a
+ script that will be run, the first entry in argv can be an empty string.
+ }
+ if I = 0 then
+ Params[I] := ''
+ else
+ Params[I] := EncodeString(ParamStr(I));
+ PParams[I] := PAnsiChar(Params[I])
+ end;
+ PyInitConfig_SetStrList(Config, 'argv', ParamCount + 1, @PParams[0]);
+ end;
+
+ procedure SetPythonPath(Config: PPyInitConfig);
+ var
+ Paths: TStringDynArray;
+ I: Integer;
+ Utf8Paths: TArray;
+ PUtf8Paths: TArray;
+ begin
+ if FPythonPath = '' then Exit;
+
+ Paths := SplitString(string(FPythonPath), PathSep);
+
+ if Length(Paths) = 0 then Exit;
+
+ SetLength(Utf8Paths, Length(Paths));
+ SetLength(PUtf8Paths, Length(Paths));
+
+ for I := 0 to Length(Paths) - 1 do
+ begin
+ Utf8Paths[I] := EncodeString(Paths[I]);
+ PUtf8Paths[I] := PAnsiChar(Utf8Paths[I]);
+ end;
+
+ // The following Also sets module_search_paths_set
+ PyInitConfig_SetStrList(Config, 'module_search_paths', Length(Paths), @PUtf8Paths[0]);
+ end;
+
+ var
+ Config: PPyInitConfig;
+ PErrMsg: PAnsiChar;
+ begin
+ Config := PyInitConfig_Create;
+ try
+ AssignPyFlags(Config);
+
+ // Set programname and pythonhome if available
+ if FProgramName <> '' then
+ PyInitConfig_SetStr(Config, 'program_name', PAnsiChar(EncodeString(FProgramName)));
+ if FPythonHome <> '' then
+ PyInitConfig_SetStr(Config, 'home', PAnsiChar(EncodeString(FPythonHome)));
+ // Set venv executable if available
+ if FPythonExecutable <> '' then
+ PyInitConfig_SetStr(Config, 'executable', PAnsiChar(EncodeString(FPythonExecutable)));
+
+ // Set program arguments (sys.argv)
+ SetProgramArgs(Config);
+
+ // PythonPath
+ SetPythonPath(Config);
+
+ // Fine tune Config
+ if Assigned(FOnConfigInit) then
+ FOnConfigInit(Self, Config);
+
+ if Py_InitializeFromInitConfig(Config) <> 0 then
+ begin
+ FInitialized := False;
+ PyInitConfig_GetError(Config, @PErrMsg);
+ if PErrMsg <> nil then
+ ErrMsg := Format(SPyInitFailed, [UTF8ToString(AnsiString(PErrMsg))]);
+ end
+ else
+ FInitialized := Py_IsInitialized() <> 0;
+ if not FInitialized and (ErrMsg = '') then
+ ErrMsg := Format(SPyInitFailed, [SPyInitFailedUnknown]);
+ finally
+ PyInitConfig_Free(Config);
+ end;
+ end;
procedure InitSysPath;
var
_path : PPyObject;
- const Script =
- 'import sys' + sLineBreak +
- 'sys.executable = r"%s"' + sLineBreak +
- 'path = sys.path' + sLineBreak +
- 'for i in range(len(path)-1, -1, -1):' + sLineBreak +
- ' if path[i].find("site-packages") > 0:' + sLineBreak +
- ' path.pop(i)' + sLineBreak +
- 'import site' + sLineBreak +
- 'site.main()' + sLineBreak +
- 'del sys, path, i, site';
begin
- if VenvPythonExe <> '' then
- ExecString(AnsiString(Format(Script, [VenvPythonExe])));
_path := PySys_GetObject('path');
if Assigned(FOnSysPathInit) then
FOnSysPathInit(Self, _path);
@@ -4689,9 +5048,10 @@ procedure TPythonEngine.Initialize;
var
i : Integer;
+ ErrMsg: string;
begin
if Assigned(gPythonEngine) then
- raise Exception.Create('There is already one instance of TPythonEngine running' );
+ raise Exception.Create(SMoreThanOnePythonEngine);
gPythonEngine := Self;
@@ -4700,21 +5060,26 @@ procedure TPythonEngine.Initialize;
FInitialized := True
else
begin
- CheckRegistry;
- if Assigned(Py_SetProgramName) and (Length(FProgramName) > 0) then
- Py_SetProgramName(PWCharT(FProgramName));
- AssignPyFlags;
- if Length(FPythonHome) > 0 then
- Py_SetPythonHome(PWCharT(FPythonHome));
- Py_Initialize;
- if Assigned(Py_IsInitialized) then
- FInitialized := Py_IsInitialized() <> 0
+ if (MajorVersion > 3) or (MinorVersion >= 14) then
+ ConfigPEP741(ErrMsg)
else
- FInitialized := True;
+ ConfigPEP587(ErrMsg);
+
+ if not FInitialized then
+ begin
+ if FatalMsgDlg then
+ {$IFDEF MSWINDOWS}
+ MessageBox( GetActiveWindow, PChar(ErrMsg), 'Error', MB_TASKMODAL or MB_ICONSTOP );
+ {$ELSE}
+ WriteLn(ErrOutput, ErrMsg);
+ {$ENDIF}
+ if FatalAbort then
+ Quit
+ else
+ raise Exception.Create(ErrMsg);
+ end;
+
InitSysPath;
- SetProgramArgs;
- if InitThreads and Assigned(PyEval_InitThreads) then
- PyEval_InitThreads;
if RedirectIO and Assigned(FIO) then
DoRedirectIO;
end;
@@ -4727,6 +5092,19 @@ procedure TPythonEngine.Initialize;
if not Initialized then
Initialize;
+ {$IFDEF MSWINDOWS}
+ // fix #504
+ if not FRedirectIO and UseWindowsConsole then
+ PyRun_SimpleString(
+ 'import sys, io'#10 +
+ 'sys.stdout = io.TextIOWrapper(open("CONOUT$", "wb", buffering=0), ' +
+ 'encoding="utf-8", errors="replace", line_buffering=True)'#10 +
+ 'sys.stderr = io.TextIOWrapper(open("CONOUT$", "wb", buffering=0), ' +
+ 'encoding="utf-8", errors="replace", line_buffering=False)'#10 +
+ 'sys.stdin = io.TextIOWrapper(open("CONIN$", "rb", buffering=0), ' +
+ 'encoding="utf-8", errors="replace", line_buffering=True)'#10);
+ {$ENDIF}
+
if InitScript.Count > 0 then
ExecStrings(InitScript);
if Assigned(FOnAfterInit) then
@@ -4746,16 +5124,6 @@ function TPythonEngine.GetThreadState: PPyThreadState;
Result := nil;
end;
-procedure TPythonEngine.SetInitThreads(Value: Boolean);
-begin
- if Value <> FInitThreads then
- begin
- if Value and Assigned(PyEval_InitThreads) then
- PyEval_InitThreads;
- FInitThreads := Value;
- end;
-end;
-
procedure TPythonEngine.SetIO(InputOutput: TPythonInputOutput);
begin
if InputOutput <> fIO then
@@ -4786,106 +5154,18 @@ procedure TPythonEngine.Notification( AComponent: TComponent;
IO := nil
end;
-procedure TPythonEngine.CheckRegistry;
-{$IFDEF MSWINDOWS}
-var
- key : string;
- Path : string;
- NewPath : string;
-{$IFDEF CPUX86}
- LMajorVersion : integer;
- LMinorVersion : integer;
-{$ENDIF}
- VersionSuffix: string;
-{$ENDIF}
-begin
-{$IFDEF MSWINDOWS}
- if Assigned( FOnPathInitialization ) then
- try
- with TRegistry.Create(KEY_ALL_ACCESS and not KEY_NOTIFY) do
- try
- VersionSuffix := '';
-{$IFDEF CPUX86}
- PythonVersionFromRegVersion(RegVersion, LMajorVersion, LMinorVersion);
- if (LMajorVersion > 3) or ((LMajorVersion = 3) and (LMinorVersion >= 5)) then
- VersionSuffix := '-32';
-{$ENDIF}
- key := Format('\Software\Python\PythonCore\%s%s\PythonPath', [RegVersion, VersionSuffix]);
-
- RootKey := HKEY_LOCAL_MACHINE;
- if not KeyExists( key ) then
- begin
- // try a current user installation
- RootKey := HKEY_CURRENT_USER;
- if not KeyExists( key ) then Exit;
- end;
- // Key found
- OpenKey( key, True );
- try
- Path := ReadString('');
- NewPath := Path;
- FOnPathInitialization( Self, NewPath );
- if NewPath <> Path then
- begin
- WriteString( '', NewPath );
- end;
- finally
- CloseKey;
- end;
- finally
- Free;
- end;
- except
- // under WinNT, with a user without admin rights, the access to the
- // LocalMachine keys would raise an exception.
- end;
-{$ENDIF}
-end;
-
-procedure TPythonEngine.SetProgramArgs;
-var
- I, argc : Integer;
- wargv : array of PWCharT;
- WL : array of WCharTString;
- TempS: UnicodeString;
-begin
- // we build a string list of the arguments, because ParamStr returns a volatile string
- // and we want to build an array of PWCharT, pointing to valid strings.
- argc := ParamCount;
- SetLength(wargv, argc + 1);
- // build the PWCharT array
- SetLength(WL, argc+1);
- for I := 0 to argc do begin
- {
- ... the first entry should refer to the script file to be executed rather
- than the executable hosting the Python interpreter. If there isn’t a
- script that will be run, the first entry in argv can be an empty string.
- }
- if I = 0 then
- TempS := ''
- else
- TempS := ParamStr(I);
- {$IFDEF POSIX}
- WL[I] := UnicodeStringToUCS4String(TempS);
- {$ELSE}
- WL[I] := UnicodeString(TempS);
- {$ENDIF}
- wargv[I] := PWCharT(WL[I]);
- end;
- // set the argv list of the sys module with the application arguments
- PySys_SetArgv( argc + 1, PPWCharT(wargv) );
-end;
-
procedure TPythonEngine.InitWinConsole;
begin
{$IFDEF MSWINDOWS}
FreeConsole;
AllocConsole;
SetConsoleTitle( 'Python console' );
+ SetConsoleOutputCP(CP_UTF8);
+ SetConsoleCP(CP_UTF8);
{$ENDIF}
end;
-procedure TPythonEngine.SetUseWindowsConsole( const Value : Boolean );
+procedure TPythonEngine.SetUseWindowsConsole(const Value: Boolean);
begin
FUseWindowsConsole := Value;
if (csDesigning in ComponentState) then
@@ -4903,7 +5183,7 @@ procedure TPythonEngine.SetGlobalVars(const Value: PPyObject);
else
begin
FGlobalVars := nil;
- raise Exception.Create('You must set a Python dictionary in the GlobalVars property');
+ raise Exception.Create(SGlobalVarsShouldBeDict);
end
else
FGlobalVars := nil;
@@ -4921,7 +5201,7 @@ procedure TPythonEngine.SetLocalVars(const Value: PPyObject);
else
begin
FLocalVars := nil;
- raise Exception.Create('You must set a Python dictionary in the LocalVars property');
+ raise Exception.Create(SLocalVarsShouldBeDict);
end
else
FLocalVars := nil;
@@ -4933,35 +5213,11 @@ procedure TPythonEngine.SetPyFlags(const Value: TPythonFlags);
if FPyFlags <> Value then
begin
if Initialized then
- raise Exception.Create('You can''t modify Python flags after it has been initialized');
+ raise Exception.Create(SCannotModifyFlags);
FPyFlags := Value;
end; // of if
end;
-function TPythonEngine.GetPythonHome: UnicodeString;
-begin
-{$IFDEF POSIX}
- if Length(FPythonHome) = 0 then
- Result := ''
- else
- Result := UCS4StringToUnicodeString(FPythonHome);
-{$ELSE}
- Result := FPythonHome;
-{$ENDIF}
-end;
-
-function TPythonEngine.GetPythonPath: UnicodeString;
-begin
-{$IFDEF POSIX}
- if (Length(FPythonPath) > 0) then
- Result := UCS4StringToUnicodeString(FPythonPath)
- else
- Result := '';
-{$ELSE}
- Result := FPythonPath;
-{$ENDIF}
-end;
-
function TPythonEngine.GetSequenceItem(sequence: PPyObject;
idx: Integer): Variant;
var
@@ -4975,43 +5231,14 @@ function TPythonEngine.GetSequenceItem(sequence: PPyObject;
end;
end;
-function TPythonEngine.GetProgramName: UnicodeString;
-begin
-{$IFDEF POSIX}
- if Length(FProgramName) = 0 then
- Result := ''
- else
- Result := UCS4StringToUnicodeString(FProgramName);
-{$ELSE}
- Result := FProgramName;
-{$ENDIF}
-end;
-
procedure TPythonEngine.SetPythonHome(const PythonHome: UnicodeString);
begin
-{$IFDEF POSIX}
- FPythonHome := UnicodeStringToUCS4String(PythonHome);
-{$ELSE}
FPythonHome := PythonHome;
-{$ENDIF}
-end;
-
-procedure TPythonEngine.SetPythonPath(const Value: UnicodeString);
-begin
-{$IFDEF POSIX}
- FPythonPath := UnicodeStringToUCS4String(Value);
-{$ELSE}
- FPythonPath := Value;
-{$ENDIF}
end;
procedure TPythonEngine.SetProgramName(const ProgramName: UnicodeString);
begin
-{$IFDEF POSIX}
- FProgramName := UnicodeStringToUCS4String(ProgramName);
-{$ELSE}
FProgramName := ProgramName;
-{$ENDIF}
end;
function TPythonEngine.EvalPyFunction(pyfunc, pyargs:PPyObject): Variant;
@@ -5021,7 +5248,7 @@ function TPythonEngine.EvalPyFunction(pyfunc, pyargs:PPyObject): Variant;
Result := -1;
if pyfunc = nil then exit;
try
- presult := PyEval_CallObjectWithKeywords(pyfunc,pyargs, nil);
+ presult := PyObject_Call(pyfunc,pyargs, nil);
CheckError(False);
if presult = nil then
// should not happen since an exception would have been raised
@@ -5127,7 +5354,7 @@ function TPythonEngine.Run_CommandAsObjectWithDict(const command: AnsiString;
m := GetMainModule;
if m = nil then
- raise EPythonError.Create('Run_CommandAsObject: can''t create __main__');
+ raise EPythonError.Create(SCannotCreateMain);
if Assigned(locals) then
_locals := locals
@@ -5233,22 +5460,11 @@ function TPythonEngine.CheckExecSyntax( const str : AnsiString ) : Boolean;
function TPythonEngine.CheckSyntax( const str : AnsiString; mode : Integer ) : Boolean;
var
- n : PNode;
PyCode: PPyObject;
begin
- if (FMajorVersion = 3) and (MinorVersion < 10) then
- begin
- n := PyParser_SimpleParseString( PAnsiChar(str), mode );
- result := Assigned(n);
- if Assigned( n ) then
- PyNode_Free(n);
- end
- else
- begin
- PyCode := Py_CompileString(PAnsiChar(str), '', mode);
- Result := Assigned(PyCode);
- Py_XDECREF(PyCode);
- end;
+ PyCode := Py_CompileString(PAnsiChar(str), '', mode);
+ Result := Assigned(PyCode);
+ Py_XDECREF(PyCode);
end;
procedure TPythonEngine.RaiseError;
@@ -5389,9 +5605,7 @@ procedure TPythonEngine.RaiseError;
s_type := GetTypeAsString(err_type);
s_value := PyObjectAsString(err_value);
- if (PyErr_GivenExceptionMatches(err_type, PyExc_SystemExit^) <> 0) then
- raise Define( EPySystemExit.Create(''), s_type, s_value )
- else if (PyErr_GivenExceptionMatches(err_type, PyExc_StopIteration^) <> 0) then
+ if (PyErr_GivenExceptionMatches(err_type, PyExc_StopIteration^) <> 0) then
raise Define( EPyStopIteration.Create(''), s_type, s_value )
else if (PyErr_GivenExceptionMatches(err_type, PyExc_KeyboardInterrupt^) <> 0) then
raise Define( EPyKeyboardInterrupt.Create(''), s_type, s_value )
@@ -5482,31 +5696,28 @@ procedure TPythonEngine.RaiseError;
raise Define( EPyExecError.Create(''), s_type, s_value );
end
else
- raise EPythonError.Create('RaiseError: couldn''t fetch last exception');
+ raise EPythonError.Create(SRaiseError);
end;
function TPythonEngine.PyObjectAsString( obj : PPyObject ) : string;
var
S : PPyObject;
- W : UnicodeString;
begin
Result := '';
if not Assigned( obj ) then
Exit;
if PyUnicode_Check(obj) then
+ Result := string(PyUnicodeAsString(obj))
+ else if PyBytes_Check(obj) then
+ Result := string(UTF8ToString(PyBytesAsAnsiString(obj)))
+ else
begin
- W := PyUnicodeAsString(obj);
- Result := string(W);
- Exit;
- end;
- S := PyObject_Str( obj );
- if Assigned(S) and PyUnicode_Check(S) then
- begin
- W := PyUnicodeAsString(S);
- Result := string(W);
+ S := PyObject_Str( obj );
+ if Assigned(S) and PyUnicode_Check(S) then
+ Result := string(PyUnicodeAsString(S));
+ Py_XDECREF(S);
end;
- Py_XDECREF(S);
end;
procedure TPythonEngine.DoRedirectIO;
@@ -5588,17 +5799,15 @@ function TPythonEngine.FindClient( const aName : string ) : TEngineClient;
end;
end;
-function TPythonEngine.EncodeString(const str: UnicodeString): AnsiString; {$IFDEF FPC}overload;{$ENDIF}
+function TPythonEngine.EncodeString(const str: UnicodeString): AnsiString;
begin
- Result := UTF8Encode(str)
+ Result := UTF8Encode(str);
end;
-{$IFDEF FPC}
-function TPythonEngine.EncodeString (const str: AnsiString): AnsiString; overload;
+function TPythonEngine.EncodeString(const str: AnsiString): AnsiString;
begin
- Result := str;
+ Result := UTF8Encode(str);
end;
-{$ENDIF}
function TPythonEngine.EncodeWindowsFilePath(const str: string): AnsiString;
{PEP 529}
@@ -5621,22 +5830,22 @@ function TPythonEngine.TypeByName( const aTypeName : AnsiString ) : PPyTypeObjec
Result := TheTypePtr;
Exit;
end;
- raise Exception.CreateFmt('Could not find type: %s', [aTypeName]);
+ raise Exception.CreateFmt(SCannotFindType, [aTypeName]);
end;
-function TPythonEngine.ModuleByName( const aModuleName : AnsiString ) : PPyObject;
+function TPythonEngine.ModuleByName( const aModuleName : AnsiString ) : PPyObject;
var
i : Integer;
begin
for i := 0 to ClientCount - 1 do
if Clients[i] is TPythonModule then
- with TPythonModule( Clients[i] ) do
+ with TPythonModule(Clients[i]) do
if ModuleName = aModuleName then
begin
Result := Module;
Exit;
end;
- raise Exception.CreateFmt('Could not find module: %s', [aModuleName]);
+ raise Exception.CreateFmt(SCannotFindModule, [aModuleName]);
end;
function TPythonEngine.MethodsByName( const aMethodsContainer: string ) : PPyMethodDef;
@@ -5651,7 +5860,7 @@ function TPythonEngine.MethodsByName( const aMethodsContainer: string ) : PPyMet
Result := MethodsData;
Exit;
end;
- raise Exception.CreateFmt('Could not find component: %s', [aMethodsContainer]);
+ raise Exception.CreateFmt(SCannotFindComponent, [aMethodsContainer]);
end;
function TPythonEngine.VariantAsPyObject( const V : Variant ) : PPyObject;
@@ -5771,17 +5980,17 @@ function TPythonEngine.VariantAsPyObject( const V : Variant ) : PPyObject;
else if (DatetimeConversionMode = dcmToDatetime) then
begin
if not Assigned(FPyDateTime_DateTimeType) then
- raise EPythonError.Create('dcmToDatetime DatetimeConversionMode cannot be used with this version of python. Missing module datetime');
+ raise EPythonError.Create(SMissingModuleDateTime);
args := ArrayToPyTuple([y, m, d, h, mi, sec, ms*1000]);
try
- Result := PyEval_CallObjectWithKeywords(FPyDateTime_DateTimeType, args, nil);
+ Result := PyObject_Call(FPyDateTime_DateTimeType, args, nil);
CheckError(False);
finally
Py_DecRef(args);
end;
end
else
- raise EPythonError.Create('Invalid DatetimeConversionMode');
+ raise EPythonError.Create(SInvalidDateTimeConvMode);
end;
varOleStr:
begin
@@ -5809,7 +6018,7 @@ function TPythonEngine.VariantAsPyObject( const V : Variant ) : PPyObject;
2: Result := ArrayVarDim2;
3: Result := ArrayVarDim3;
else
- raise Exception.Create('Can''t convert a variant array of more than 3 dimensions to a Python sequence');
+ raise Exception.Create(SCannotHandleMoreThan3Dim);
end;
end
else if VarIsNull(DeRefV) or VarIsEmpty(DeRefV) then
@@ -5835,7 +6044,7 @@ function TPythonEngine.PyObjectAsVariant( obj : PPyObject ) : Variant;
if PyLong_Check(member) then
Result := PyLong_AsLong(member)
else
- raise EPythonError.CreateFmt('Unexpected type found in member %s of a time_struct object', [AMember]);
+ raise EPythonError.CreateFmt(SUnexpectedTypeInTimeObject, [AMember]);
Py_XDecRef(member);
end;
@@ -6025,7 +6234,7 @@ function TPythonEngine.VarRecAsPyObject( const v : TVarRec ) : PPyObject;
Result := PyUnicodeFromString('');
end;
else
- Raise Exception.Create('Argument type not allowed');
+ Raise Exception.Create(SArguementTypeNotAllowed);
end;
end;
@@ -6038,7 +6247,7 @@ function TPythonEngine.MakePyTuple( const objects : array of PPyObject ) : PPyOb
begin
Result := PyTuple_New( High(objects)+1 );
if not Assigned(Result) then
- raise EPythonError.Create('Could not create a new tuple object');
+ raise EPythonError.Create(SCouldNotCreateTuple);
for i := Low(objects) to High(objects) do
begin
Py_XINCREF( objects[i] );
@@ -6055,7 +6264,7 @@ function TPythonEngine.MakePyList( const objects : array of PPyObject ) : PPyObj
begin
Result := PyList_New( High(objects)+1 );
if not Assigned(Result) then
- raise EPythonError.Create('Could not create a new list object');
+ raise EPythonError.Create(SCouldNotCreateList);
for i := Low(objects) to High(objects) do
begin
Py_XIncRef( objects[i] );
@@ -6069,7 +6278,7 @@ function TPythonEngine.ArrayToPyTuple( const items : array of const) : PPyObject
begin
Result := PyTuple_New( High(items)+1 );
if not Assigned(Result) then
- raise EPythonError.Create('Could not create a new tuple object');
+ raise EPythonError.Create(SCouldNotCreateTuple);
for i := Low(items) to High(items) do
PyTuple_SetItem( Result, i, VarRecAsPyObject( items[i] ) );
end;
@@ -6080,7 +6289,7 @@ function TPythonEngine.ArrayToPyList( const items : array of const) : PPyObject;
begin
Result := PyList_New( High(items)+1 );
if not Assigned(Result) then
- raise EPythonError.Create('Could not create a new list object');
+ raise EPythonError.Create(SCouldNotCreateList);
for i := Low(items) to High(items) do
PyList_SetItem( Result, i, VarRecAsPyObject( items[i] ) );
end;
@@ -6136,7 +6345,7 @@ function TPythonEngine.ArrayToPyDict( const items : array of const) : PPyObject;
Result := '';
end;
else
- Raise Exception.Create('Argument type not allowed');
+ Raise Exception.Create(SArguementTypeNotAllowed);
end;
end;
@@ -6146,10 +6355,10 @@ function TPythonEngine.ArrayToPyDict( const items : array of const) : PPyObject;
obj : PPyObject;
begin
if ((High(items)+1) mod 2) <> 0 then
- raise Exception.Create('You must provide an even number of arguments');
+ raise Exception.Create(SArgumemntsShouldBeEven);
Result := PyDict_New;
if not Assigned(Result) then
- raise EPythonError.Create('Could not create a new dict object');
+ raise EPythonError.Create(SCouldNotCreateDict);
i := Low(items);
try
while i <= High(items) do
@@ -6174,7 +6383,7 @@ function TPythonEngine.StringsToPyList( strings : TStrings ) : PPyObject;
begin
Result := PyList_New( strings.Count );
if not Assigned(Result) then
- raise EPythonError.Create('Could not create a new list object');
+ raise EPythonError.Create(SCouldNotCreateList);
for i := 0 to strings.Count - 1 do
PyList_SetItem( Result, i,
PyUnicodeFromString(strings.Strings[i]));
@@ -6186,7 +6395,7 @@ function TPythonEngine.StringsToPyTuple( strings : TStrings ) : PPyObject;
begin
Result := PyTuple_New( strings.Count );
if not Assigned(Result) then
- raise EPythonError.Create('Could not create a new tuple object');
+ raise EPythonError.Create(SCouldNotCreateTuple);
for i := 0 to strings.Count - 1 do
PyTuple_SetItem( Result, i,
PyUnicodeFromString(strings.Strings[i]));
@@ -6198,7 +6407,7 @@ procedure TPythonEngine.PyListToStrings(list: PPyObject; Strings: TStrings;
i : Integer;
begin
if not PyList_Check(list) then
- raise EPythonError.Create('the python object is not a list');
+ raise EPythonError.Create(SExpectedList);
if ClearStrings then
Strings.Clear;
for i := 0 to PyList_Size( list ) - 1 do
@@ -6210,7 +6419,7 @@ procedure TPythonEngine.PyTupleToStrings( tuple: PPyObject; strings : TStrings )
i : Integer;
begin
if not PyTuple_Check(tuple) then
- raise EPythonError.Create('the python object is not a tuple');
+ raise EPythonError.Create(SExpectedTuple);
strings.Clear;
for i := 0 to PyTuple_Size( tuple ) - 1 do
strings.Add( PyObjectAsString( PyTuple_GetItem( tuple, i ) ) );
@@ -6430,6 +6639,7 @@ procedure TPythonEngine.CheckError(ACatchStopEx : Boolean = False);
var
errtype, errvalue, errtraceback: PPyObject;
SErrValue: string;
+ SystemExit: EPySystemExit;
begin
// PyErr_Fetch clears the error. The returned python objects are new references
PyErr_Fetch(errtype, errvalue, errtraceback);
@@ -6438,7 +6648,11 @@ procedure TPythonEngine.CheckError(ACatchStopEx : Boolean = False);
Py_XDECREF(errtype);
Py_XDECREF(errvalue);
Py_XDECREF(errtraceback);
- raise EPySystemExit.CreateResFmt(@SPyExcSystemError, [SErrValue]);
+
+ SystemExit := EPySystemExit.CreateResFmt(@SPyExcSystemError, [SErrValue]);
+ SystemExit.EValue := SErrValue;
+ SystemExit.EName := 'SystemExit';
+ raise SystemExit;
end;
var
@@ -6530,6 +6744,64 @@ function TPythonEngine.PyUnicodeFromString(const AString: AnsiString): PPyObject
end;
+function TPythonEngine.Py_InitModule(const md: PyModuleDef): PPyObject;
+// Implements multi-phase module intialization
+var
+ modules, importlib, spec_func, module_name, args, spec: PPyObject;
+begin
+ CheckPython;
+
+ importlib := nil;
+ spec_func := nil;
+ module_name := nil;
+ args := nil;
+ spec := nil;
+
+ try
+ // We need a spec and for that we need importlib;
+ importlib := PyImport_ImportModule('importlib.util');
+ if not Assigned(importlib) then CheckError;
+
+ // Get spec_from_loader function
+ spec_func := PyObject_GetAttrString(importlib, 'spec_from_loader');
+ if not Assigned(spec_func) then CheckError;
+
+ // Create module name
+ module_name := PyUnicode_FromString(md.m_name);
+ if not Assigned(module_name) then CheckError;
+
+ // Create arguments tuple for spec_from_loader(name, loader)
+ args := MakePyTuple([module_name, Py_None]);
+
+ // Create the module specification
+ spec := PyObject_CallObject(spec_func, args);
+ if not Assigned(spec) then CheckError;
+
+ // Create the module from the definition and spec
+ Result := PyModule_FromDefAndSpec2(@md, spec, APIVersion);
+ if not Assigned(spec) then CheckError;
+
+ // Execute the module (triggers Py_mod_exec slot)
+ if (PyModule_ExecDef(Result, @md) < 0) then
+ begin
+ Py_DECREF(Result);
+ CheckError;
+ end;
+
+ finally
+ Py_XDECREF(importlib);
+ Py_XDECREF(spec_func);
+ Py_XDECREF(module_name);
+ Py_XDECREF(args);
+ Py_XDECREF(spec);
+ end;
+
+ // We need to add the module to sys.modules
+ modules := PyImport_GetModuleDict;
+ if PyDict_SetItemString(modules, md.m_name, Result) <> 0 then
+ GetPythonEngine.CheckError;
+end;
+
(*******************************************************)
(** **)
(** class TEngineClient **)
@@ -6612,7 +6884,7 @@ procedure TEngineClient.ClearEngine;
procedure TEngineClient.CheckEngine;
begin
if not Assigned(FEngine) then
- raise Exception.CreateFmt('No Engine defined for component "%s"', [Name]);
+ raise Exception.CreateFmt(SNoEngineForComponent, [Name]);
end;
@@ -6758,7 +7030,7 @@ procedure TMethodsContainer.ReallocMethods;
function TMethodsContainer.GetMethods( idx : Integer ) : PPyMethodDef;
begin
if (idx < 0) or (idx > MethodCount) then
- raise Exception.CreateFmt('%s: Index %d out of range', [ClassName, idx]);
+ raise Exception.CreateFmt(SIndexOutOfRange, [ClassName, idx]);
Result := @( FMethods[idx] );
end;
@@ -6891,7 +7163,7 @@ procedure TMembersContainer.AddMember(MemberName: PAnsiChar; MemberType : TPyMe
mtStringInplace: _type := T_STRING_INPLACE;
mtObjectEx: _type := T_OBJECT_EX;
else
- raise Exception.Create('Unknown member type');
+ raise Exception.Create(SUnknownMemberType);
end;
offset := MemberOffset + GetMembersStartOffset;
case MemberFlags of
@@ -6901,9 +7173,9 @@ procedure TMembersContainer.AddMember(MemberName: PAnsiChar; MemberType : TPyMe
mfWriteRestricted: flags := PY_WRITE_RESTRICTED;
mfRestricted: flags := RESTRICTED;
else
- raise Exception.Create('Unknown member flag');
+ raise Exception.Create(SUnknownMemberFlag);
end;
- doc := MemberDoc;
+ doc := MemberDoc;
end;
Inc( FMemberCount );
end;
@@ -6954,7 +7226,7 @@ procedure TMembersContainer.FreeMembers;
function TMembersContainer.GetMembers(idx: Integer): PPyMemberDef;
begin
if (idx < 0) or (idx > MemberCount) then
- raise Exception.CreateFmt('%s: Index %d out of range', [ClassName, idx]);
+ raise Exception.CreateFmt(SIndexOutOfRange, [ClassName, idx]);
Result := @( FMembers[idx] );
end;
@@ -7031,7 +7303,7 @@ procedure TGetSetContainer.FreeGetSets;
function TGetSetContainer.GetGetSet(idx: Integer): PPyGetSetDef;
begin
if (idx < 0) or (idx > GetSetCount) then
- raise Exception.CreateFmt('%s: Index %d out of range', [ClassName, idx]);
+ raise Exception.CreateFmt(SIndexOutOfRange, [ClassName, idx]);
Result := @( FGetSets[idx] );
end;
@@ -7068,7 +7340,8 @@ procedure TParentClassError.AssignTo( Dest: TPersistent );
function TError.GetDisplayName: string;
begin
Result := string(Name);
- if Result = '' then Result := inherited GetDisplayName;
+ if Result = '' then
+ Result := inherited GetDisplayName;
end;
procedure TError.SetName( const Value : AnsiString );
@@ -7086,8 +7359,8 @@ procedure TError.SetName( const Value : AnsiString );
for i := 0 to Count - 1 do
with Items[i] do
if Name = Value then
- raise Exception.CreateFmt( 'In module "%s", there''s already an error named "%s"',
- [m.ModuleName, Value]);
+ raise Exception.CreateFmt(SDuplicateErrorName,
+ [m.ModuleName, Value]);
end;
end;
@@ -7197,13 +7470,13 @@ procedure TError.BuildError( const ModuleName : AnsiString );
else
m := FindModule( ModuleName );
if not Assigned(m) then
- raise Exception.CreateFmt('Could not find module containing the parent class of error "%s"', [Self.Name]);
+ raise Exception.CreateFmt(SNoModuleWithParentClass, [Self.Name]);
d := PyModule_GetDict(m);
Result := PyDict_GetItemString( d, PAnsiChar(ParentClass.Name) );
if not Assigned(Result) then
- raise Exception.CreateFmt('Could not find the parent class "%s" of error "%s"', [ParentClass.Name, Self.Name]);
+ raise Exception.CreateFmt(SCannotFindParentClass, [ParentClass.Name, Self.Name]);
if not PyClass_Check( Result ) and not PyType_CheckExact( Result ) then
- raise Exception.CreateFmt('The object "%s" in module "%s" is not a class', [ParentClass.Name, ParentClass.Module] );
+ raise Exception.CreateFmt(SObjectNotClass, [ParentClass.Name, ParentClass.Module] );
end;
end;
@@ -7214,7 +7487,7 @@ procedure TError.BuildError( const ModuleName : AnsiString );
Exit;
if Name = '' then
with GetOwner as TPythonModule do
- raise Exception.CreateFmt( 'Error without name in module "%s"', [ModuleName] );
+ raise Exception.CreateFmt(SErrorNotClass, [ModuleName] );
if Text = '' then
Text := Name;
Owner.Owner.CheckEngine;
@@ -7234,17 +7507,17 @@ procedure TError.BuildError( const ModuleName : AnsiString );
end;
end;
if not Assigned(Error) then
- raise Exception.CreateFmt( 'Could not create error "%s"', [Name] );
+ raise Exception.CreateFmt(SCouldNotCreateError, [Name]);
end;
-procedure TError.RaiseError( const msg : AnsiString );
+procedure TError.RaiseError(const msg : AnsiString);
begin
Owner.Owner.CheckEngine;
with Owner.Owner.Engine do
- PyErr_SetString( Error, PAnsiChar(msg) );
+ PyErr_SetString(Error, PAnsiChar(EncodeString(msg)));
end;
-procedure TError.RaiseErrorObj( const msg : AnsiString; obj : PPyObject );
+procedure TError.RaiseErrorObj(const msg : AnsiString; obj : PPyObject);
var
args, res, str : PPyObject;
i : Integer;
@@ -7258,24 +7531,20 @@ procedure TError.RaiseErrorObj( const msg : AnsiString; obj : PPyObject );
// instance.
if PyDict_Check( obj ) then
begin
- args := PyTuple_New(0);
- if not Assigned(args) then
- raise Exception.Create('TError.RaiseErrorObj: Could not create an empty tuple');
- res := PyEval_CallObjectWithKeywords(Error, args, nil);
- Py_DECREF(args);
+ res := PyObject_CallObject(Error, nil);
if not Assigned(res) then
- raise Exception.CreateFmt('TError.RaiseErrorObj: Could not create an instance of "%s"', [Self.Name]);
+ raise Exception.CreateFmt(STErrorCouldNotCreateInstance, [Self.Name]);
if PyObject_TypeCheck(res, PPyTypeObject(PyExc_Exception^)) then
begin
args := PyTuple_New(1);
if not Assigned(args) then
- raise Exception.Create('TError.RaiseErrorObj: Could not create an empty tuple');
+ raise Exception.Create(STErrorCouldNotCreateTuple);
str := PyUnicodeFromString(msg);
PyTuple_SetItem(args, 0, str);
- res := PyEval_CallObjectWithKeywords(Error, args, nil);
+ res := PyObject_Call(Error, args, nil);
Py_DECREF(args);
if not Assigned(res) then
- raise Exception.CreateFmt('TError.RaiseErrorObj: Could not create an instance of "%s"', [Self.Name]);
+ raise Exception.CreateFmt(STErrorCouldNotCreateInstance, [Self.Name]);
keys := PyDict_Keys(obj);
for i := 0 to PySequence_Length(keys)-1 do
begin
@@ -7291,11 +7560,12 @@ procedure TError.RaiseErrorObj( const msg : AnsiString; obj : PPyObject );
Py_XDECREF(keys);
end
else
- raise Exception.Create('TError.RaiseErrorObj: I didn''t get an instance' );
- PyErr_SetObject( Error, res );
+ raise Exception.Create(STErrorNoInstance);
+ PyErr_SetObject(Error, res);
+ Py_XDECREF(res);
end
else
- PyErr_SetObject( Error, obj );
+ PyErr_SetObject(Error, obj);
end;
function TError.Owner : TErrors;
@@ -7394,6 +7664,7 @@ constructor TPythonModule.Create( AOwner : TComponent );
FClients := TList.Create;
FErrors := TErrors.Create(Self);
FDocString := TStringList.Create;
+ FDocString.TrailingLineBreak := False;
end;
destructor TPythonModule.Destroy;
@@ -7409,52 +7680,59 @@ procedure TPythonModule.SetDocString( value : TStringList );
FDocString.Assign( value );
end;
-procedure TPythonModule.DefineDocString;
+procedure TPythonModule.MakeModuleDef;
var
- doc : PPyObject;
+ P: Pointer;
begin
- with Engine do
- begin
- if DocString.Text <> '' then
- begin
- doc :=
- PyUnicodeFromString(CleanString(FDocString.Text, False));
- PyObject_SetAttrString( FModule, '__doc__', doc );
- Py_XDecRef(doc);
- CheckError(False);
- end;
- end;
-end;
+ FillChar(FModuleDef, SizeOf(FModuleDef), 0);
+ FModuleDef.m_base.ob_refcnt := 1;
+ FModuleDef.m_name := PAnsiChar(ModuleName);
+ FModuleDef.m_methods := MethodsData;
+ FModuleDef.m_size := 0;
-procedure TPythonModule.MakeModule;
-begin
- CheckEngine;
- if Assigned(FModule) then
- Exit;
- with Engine do
- begin
- FillChar(FModuleDef, SizeOf(FModuleDef), 0);
- FModuleDef.m_base.ob_refcnt := 1;
- FModuleDef.m_name := PAnsiChar(ModuleName);
- FModuleDef.m_methods := MethodsData;
- FModuleDef.m_size := -1;
- FModule := Py_InitModule( ModuleDef );
- DefineDocString;
+ // Doc string
+ if FDocString.Count > 0 then
+ begin
+ FEncodedDocString := UTF8Encode(CleanString(FDocString.Text, False));
+ FModuleDef.m_doc := PAnsiChar(FEncodedDocString);
+ end;
+
+ // Fill the m_slots for multi-phase initialization
+ FSlots := [PyModuleDef_Slot.Make(Py_mod_exec,
+ GetCallBack(Self, @TPythonModule.Exec_Module, 1, DEFAULT_CALLBACK_TYPE))];
+
+ if (Engine.MajorVersion > 3) or (Engine.MinorVersion >= 12) then
+ begin
+ case FMultInterpretersSupport of
+ mmiNotSupported: P := Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED;
+ mmiPerInterpreterGIL: P := Py_MOD_PER_INTERPRETER_GIL_SUPPORTED;
+ else
+ P := Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED;
end;
+ FSlots := FSlots + [PyModuleDef_Slot.Make(Py_mod_multiple_interpreters, P)];
+ end;
+ FSlots := FSlots + [PyModuleDef_Slot.Make(0, nil)];
+
+ FModuleDef.m_slots := @FSlots[0];
end;
procedure TPythonModule.Initialize;
-var
- i : Integer;
begin
inherited;
- FModule := nil;
- MakeModule;
- for i := 0 to ClientCount - 1 do
- Clients[i].ModuleReady(Self);
- BuildErrors;
- if Assigned(FOnAfterInitialization) then
- FOnAfterInitialization( Self );
+
+ if Assigned(FModule) then Exit;
+
+ MakeModuleDef;
+ // Py_InitModule will call Exec_Module which will
+ // - Set FModule
+ // - initialize clients
+ // - Call OnInitialized
+ CheckEngine;
+
+ // Extension modules are intilized directly from ModuleDef
+ if FIsExtensionModule then Exit;
+
+ FModule := Engine.Py_InitModule(FModuleDef);
end;
procedure TPythonModule.InitializeForNewInterpreter;
@@ -7490,7 +7768,22 @@ function TPythonModule.ErrorByName( const AName : AnsiString ) : TError;
Result := Errors.Items[i];
Exit;
end;
- raise Exception.CreateFmt( 'Could not find error "%s"', [AName] );
+ raise Exception.CreateFmt(SCouldNotFindError, [AName] );
+end;
+
+function TPythonModule.Exec_Module(module: PPyObject): Integer;
+// Executed via the m_slots of PyModuleDef as part of the
+// multi-phase module initialization
+var
+ I : Integer;
+begin
+ FModule := module;
+ for I := 0 to ClientCount - 1 do
+ Clients[I].ModuleReady(Self);
+ BuildErrors;
+ if Assigned(FOnAfterInitialization) then
+ FOnAfterInitialization(Self);
+ Result := 0;
end;
procedure TPythonModule.RaiseError( const error, msg : AnsiString );
@@ -7522,7 +7815,7 @@ procedure TPythonModule.BuildErrors;
CheckEngine;
with Engine do
begin
- d := PyModule_GetDict( Module );
+ d := PyModule_GetDict(FModule);
if not Assigned(d) then
Exit;
for i := 0 to Errors.Count - 1 do
@@ -7541,11 +7834,11 @@ procedure TPythonModule.SetVar( const varName : AnsiString; value : PPyObject );
begin
if Assigned(FEngine) and Assigned( FModule ) then
begin
- if Engine.PyObject_SetAttrString(Module, PAnsiChar(varName), value ) <> 0 then
- raise EPythonError.CreateFmt( 'Could not set var "%s" in module "%s"', [varName, ModuleName] );
+ if Engine.PyObject_SetAttrString(FModule, PAnsiChar(varName), value ) <> 0 then
+ raise EPythonError.CreateFmt(SCouldNotSetVar, [varName, ModuleName]);
end
else
- raise EPythonError.CreateFmt( 'Can''t set var "%s" in module "%s", because it is not yet initialized', [varName, ModuleName] );
+ raise EPythonError.CreateFmt(SCannotSetVarNoInit, [varName, ModuleName]);
end;
// warning, this function will increase the refcount of value,
@@ -7555,26 +7848,27 @@ function TPythonModule.GetVar( const varName : AnsiString ) : PPyObject;
begin
if Assigned(FEngine) and Assigned( FModule ) then
begin
- Result := Engine.PyObject_GetAttrString(Module, PAnsiChar(varName) );
+ Result := Engine.PyObject_GetAttrString(FModule, PAnsiChar(varName) );
Engine.PyErr_Clear;
end
else
- raise EPythonError.CreateFmt( 'Can''t get var "%s" in module "%s", because it is not yet initialized', [varName, ModuleName] );
+ raise EPythonError.CreateFmt(SCannotSetVarNoInit, [varName, ModuleName]);
end;
-procedure TPythonModule.DeleteVar( const varName : AnsiString );
+procedure TPythonModule.DeleteVar(const varName : AnsiString);
var
dict : PPyObject;
begin
if Assigned(FEngine) and Assigned( FModule ) then
with Engine do
begin
- dict := PyModule_GetDict( Module );
- if not Assigned(dict) then raise EPythonError.CreateFmt( 'Can''t get __dict__ of module "%s"', [ModuleName] );
+ dict := PyModule_GetDict(FModule);
+ if not Assigned(dict) then
+ raise EPythonError.CreateFmt(SCannotGetDict, [ModuleName] );
PyDict_DelItemString( dict, PAnsiChar(varName) );
end
else
- raise EPythonError.CreateFmt( 'Can''t delete var "%s" in module "%s", because it is not yet initialized', [varName, ModuleName] );
+ raise EPythonError.CreateFmt(SCannotDelVarNoInit, [varName, ModuleName]);
end;
procedure TPythonModule.ClearVars;
@@ -7583,7 +7877,7 @@ procedure TPythonModule.ClearVars;
begin
if Assigned(FEngine) and Assigned( FModule ) then
with Engine do begin
- dict := PyModule_GetDict( Module );
+ dict := PyModule_GetDict(FModule);
PyDict_Clear(dict);
end;
end;
@@ -7706,7 +8000,7 @@ function TPyObject.GetModule : TPythonModule;
Result := nil;
end;
-function TPyObject.Get_ob_refcnt: NativeInt;
+function TPyObject.Get_ob_refcnt: NativeUInt;
begin
Result := GetSelf^.ob_refcnt;
end;
@@ -7716,7 +8010,7 @@ function TPyObject.Get_ob_type: PPyTypeObject;
Result := GetSelf^.ob_type;
end;
-procedure TPyObject.Set_ob_refcnt(const Value: NativeInt);
+procedure TPyObject.Set_ob_refcnt(const Value: NativeUInt);
begin
GetSelf^.ob_refcnt := Value;
end;
@@ -7755,8 +8049,8 @@ function TPyObject.SetAttr(key : PAnsiChar; value : PPyObject) : Integer;
with GetPythonEngine do
begin
Result := -1;
- PyErr_SetString (PyExc_AttributeError^,
- PAnsiChar(AnsiString(Format('Unknown attribute "%s"',[key]))));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format('Unknown attribute "%s"',[key]))));
end;
end;
@@ -7793,7 +8087,7 @@ function TPyObject.GetBuffer(view: PPy_buffer; flags: Integer): Integer;
begin
view^.obj := nil;
with GetPythonEngine do
- PyErr_SetObject(PyExc_BufferError^, PyUnicodeFromString(''));
+ PyErr_SetString(PyExc_BufferError^, '');
Result := -1;
end;
@@ -8142,7 +8436,7 @@ function PythonToDelphi( obj : PPyObject ) : TPyObject;
if IsDelphiObject( obj ) then
Result := TPyObject(PAnsiChar(obj)+Sizeof(PyObject))
else
- raise EPythonError.CreateFmt( 'Python object "%s" is not a Delphi class', [GetPythonEngine.PyObjectAsString(obj)] );
+ raise EPythonError.CreateFmt(SExpectedDelphiClass, [GetPythonEngine.PyObjectAsString(obj)]);
end;
procedure PyObjectDestructor( pSelf : PPyObject); cdecl;
@@ -8426,7 +8720,6 @@ function TPythonType.NewSubtypeInst( aType: PPyTypeObject; args, kwds : PPyObje
begin
Engine.Py_DECREF(Result);
Result := nil;
- obj.Free;
end;
end;
end;
@@ -8716,7 +9009,7 @@ procedure TPythonType.InitServices;
begin
tp_init := TPythonType_InitSubtype;
tp_alloc := FEngine.PyType_GenericAlloc;
- tp_new := GetCallBack( Self, @TPythonType.NewSubtypeInst, 3, DEFAULT_CALLBACK_TYPE);
+ tp_new := GetCallBack(Self, @TPythonType.NewSubtypeInst, 3, DEFAULT_CALLBACK_TYPE);
tp_free := FEngine.PyObject_Free;
tp_methods := MethodsData;
tp_members := MembersData;
@@ -8994,7 +9287,7 @@ procedure TPythonDelphiVar.CreateVar;
// Add a reference to this var in the module
m := PyImport_AddModule(PAnsiChar(Module));
if m = nil then
- raise EPythonError.CreateFmt('CreateVar: can''t create module "%s"', [Module]);
+ raise EPythonError.CreateFmt(SCannotCreateModule, [Module]);
d := PyModule_GetDict(m);
if @PyDict_SetItemString = nil then
raise Exception.Create('nil');
@@ -9008,7 +9301,7 @@ function TPythonDelphiVar.GetValue : Variant;
with TPyVar(PythonToDelphi(FVarObject)) do
Result := GetValueAsVariant
else
- raise Exception.Create('No variable was created' );
+ raise Exception.Create(SVarNotCreated);
end;
procedure TPythonDelphiVar.SetValue( const val : Variant );
@@ -9017,7 +9310,7 @@ procedure TPythonDelphiVar.SetValue( const val : Variant );
with TPyVar(PythonToDelphi(FVarObject)) do
SetValueFromVariant(val)
else
- raise Exception.Create('No variable was created' );
+ raise Exception.Create(SVarNotCreated);
end;
// Warning: GetValueAsPyObject returns a preincremented object !
@@ -9027,7 +9320,7 @@ function TPythonDelphiVar.GetValueAsPyObject : PPyObject;
with TPyVar(PythonToDelphi(FVarObject)) do
Result := GetValue
else
- raise Exception.Create('No variable was created' );
+ raise Exception.Create(SVarNotCreated);
end;
procedure TPythonDelphiVar.SetValueFromPyObject( val : PPyObject );
@@ -9036,7 +9329,7 @@ procedure TPythonDelphiVar.SetValueFromPyObject( val : PPyObject );
with TPyVar(PythonToDelphi(FVarObject)) do
SetValue(val)
else
- raise Exception.Create('No variable was created' );
+ raise Exception.Create(SVarNotCreated);
end;
function TPythonDelphiVar.IsVariantOk( const v : Variant ) : Boolean;
@@ -9089,7 +9382,7 @@ procedure TPythonDelphiVar.SetVarName( const val : AnsiString );
if Owner.Components[i] is TPythonDelphiVar then
with TPythonDelphiVar(Owner.Components[i]) do
if (VarName = val) and (Module = Self.Module) then
- raise Exception.CreateFmt('A variable "%s" already exists in the module "%s"',[val, Module]);
+ raise Exception.CreateFmt(SVarExists, [val, Module]);
end;
begin
@@ -9358,7 +9651,7 @@ procedure TPythonThread.Execute;
finally
PyGILState_Release(gilstate);
end;
- end else {fThreadExecMode}
+ end else
begin
gilstate := PyGILState_Ensure();
global_state := PyThreadState_Get;
@@ -9381,8 +9674,8 @@ procedure TPythonThread.Execute;
PyThreadState_Swap(global_state);
PyGILState_Release(gilstate);
end else
- raise EPythonError.Create( 'Could not create a new thread state');
- end; {withinterp}
+ raise EPythonError.Create(SCannotCreateThreadState);
+ end;
end;
end;
@@ -9589,9 +9882,9 @@ function pyio_GetTypesStats(self, args : PPyObject) : PPyObject;
function GetPythonEngine : TPythonEngine;
begin
if not Assigned( gPythonEngine ) then
- raise Exception.Create( 'No Python engine was created' );
+ raise Exception.Create(SCannotCreatePythonEngine);
if not gPythonEngine.Finalizing and not gPythonEngine.Initialized then
- raise Exception.Create( 'The Python engine is not properly initialized' );
+ raise Exception.Create(SCannotInitPythonEngine);
Result := gPythonEngine;
end;
@@ -9829,6 +10122,15 @@ function PyStatus_Exception(const APyStatus: PyStatus): Boolean;
Result := APyStatus._type <> _PyStatus_TYPE_OK;
end;
+function StringToWCharTString(Str: string): WcharTString;
+begin
+ {$IFDEF POSIX}
+ Result := UnicodeStringToUCS4String(UnicodeString(Str));
+ {$ELSE}
+ Result := WcharTString(Str);
+ {$ENDIF}
+end;
+
{ TPyEngineAndGIL - Internal class for SafePythonEngine }
type
@@ -9935,7 +10237,7 @@ procedure ThreadPythonExec(ExecuteProc : TProc; TerminateProc : TProc;
Thread: TAnonymousPythonThread;
begin
if GetCurrentThreadId <> MainThreadID then
- raise Exception.Create('ThreadPythonExec should only be called from the main thread');
+ raise Exception.Create(SThreadPythonExec);
Thread := TAnonymousPythonThread.Create(ExecuteProc, TerminateProc, WaitToFinish, ThreadExecMode);
if WaitToFinish then
begin
@@ -9948,5 +10250,14 @@ procedure ThreadPythonExec(ExecuteProc : TProc; TerminateProc : TProc;
{$ENDIF FPC}
+{ PyModuleDef_Slot }
+
+class function PyModuleDef_Slot.Make(slot: integer;
+ value: Pointer): PyModuleDef_Slot;
+begin
+ Result.slot := slot;
+ Result.value := value;
+end;
+
end.
diff --git a/Source/PythonVersions.pas b/Source/PythonVersions.pas
index 569ba52f..ea79ed84 100644
--- a/Source/PythonVersions.pas
+++ b/Source/PythonVersions.pas
@@ -33,7 +33,7 @@ TPythonVersion = record
function GetDisplayName: string;
function GetApiVersion: integer;
function GetSysArchitecture: string;
- function GetPythonExecutable: string;
+ function GetPythonExecutable(Index: Integer): string;
public
IsRegistered: Boolean;
IsAllUsers: Boolean;
@@ -46,7 +46,8 @@ TPythonVersion = record
function Is_virtualenv: Boolean;
function Is_conda: Boolean;
procedure AssignTo(PythonEngine: TPersistent);
- property PythonExecutable: string read GetPythonExecutable;
+ property PythonExecutable: string index 0 read GetPythonExecutable;
+ property PythonFreeThreadedExecutable: string index 1 read GetPythonExecutable;
property DLLName: string read GetDLLName;
property SysArchitecture: string read GetSysArchitecture;
property IsPython3K: Boolean read GetIsPython3K;
@@ -127,7 +128,7 @@ procedure TPythonVersion.AssignTo(PythonEngine: TPersistent);
TPythonEngine(PythonEngine).DllPath := DLLPath;
TPythonEngine(PythonEngine).APIVersion := ApiVersion;
if Is_venv then begin
- TPythonEngine(PythonEngine).VenvPythonExe := PythonExecutable;
+ TPythonEngine(PythonEngine).PythonExecutable := PythonExecutable;
TPythonEngine(PythonEngine).SetPythonHome(DLLPath);
end else
{
@@ -204,11 +205,18 @@ function TPythonVersion.GetIsPython3K: Boolean;
end;
end;
-function TPythonVersion.GetPythonExecutable: string;
+function TPythonVersion.GetPythonExecutable(Index: Integer): string;
+var
+ ExeName: string;
begin
- Result := IncludeTrailingPathDelimiter(InstallPath) + 'python.exe';
+ if Index = 0 then
+ ExeName := 'python.exe'
+ else
+ ExeName := Format('python%st.exe', [SysVersion]);
+
+ Result := IncludeTrailingPathDelimiter(InstallPath) + ExeName;
if not FileExists(Result) then begin
- Result := IncludeTrailingPathDelimiter(InstallPath) + 'Scripts' + PathDelim + 'python.exe';
+ Result := IncludeTrailingPathDelimiter(InstallPath) + 'Scripts' + PathDelim + ExeName;
if not FileExists(Result) then Result := '';
end;
end;
diff --git a/Source/VarPyth.pas b/Source/VarPyth.pas
index fd69085f..52607cf0 100644
--- a/Source/VarPyth.pas
+++ b/Source/VarPyth.pas
@@ -1604,7 +1604,7 @@ function TPythonVariantType.EvalPython(const V: TVarData;
PyDict_SetItemString(_KW, LNamedParams[i].Name, ArgAsPythonObject(LNamedParams[i].Index));
// call the func or method, with or without named parameters (KW)
- Result := PyEval_CallObjectWithKeywords(_obj, _Args, _KW);
+ Result := PyObject_Call(_obj, _Args, _KW);
CheckError(True);
finally
Py_XDecRef(_Args);
@@ -2154,7 +2154,7 @@ procedure VarPyToStrings(const AValue : Variant; const AStrings: TStrings);
V: Variant;
begin
for V in VarPyIterate(AValue) do
- AStrings.Add(V)
+ AStrings.Add(VarPythonAsString(V))
end;
initialization
diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas
index 6ec11c1f..03961972 100644
--- a/Source/WrapDelphi.pas
+++ b/Source/WrapDelphi.pas
@@ -553,16 +553,16 @@ TPyDelphiObject = class (TPyInterfacedObject, IFreeNotificationSubscriber)
class function ExcludedExposedMembers(APythonType: TPythonType): TArray; virtual;
class procedure ExposeMethods(AClass: TClass; NearestAncestorClass: TClass;
APythonType: TPythonType; APyDelphiWrapper: TPyDelphiWrapper;
- AExcludedMethodNames: TArray = []);
+ AExcludedMethodNames: TArray = nil);
class procedure ExposeFields(AClass: TClass; NearestAncestorClass: TClass;
APythonType: TPythonType; APyDelphiWrapper: TPyDelphiWrapper;
- AExcludedFieldNames: TArray = []);
+ AExcludedFieldNames: TArray = nil);
class procedure ExposeProperties(AClass: TClass; NearestAncestorClass: TClass;
APythonType: TPythonType; APyDelphiWrapper: TPyDelphiWrapper;
- AExcludedPropertyNames: TArray = []);
+ AExcludedPropertyNames: TArray = nil);
class procedure ExposeIndexedProperties(AClass: TClass; NearestAncestorClass: TClass;
APythonType: TPythonType; APyDelphiWrapper: TPyDelphiWrapper;
- AExcludedPropertyNames: TArray = []);
+ AExcludedPropertyNames: TArray = nil);
{$ENDIF EXTENDED_RTTI}
public
PyDelphiWrapper : TPyDelphiWrapper;
@@ -616,25 +616,26 @@ TPyDelphiObjectClass = class of TPyDelphiObject;
Generic wrapper for pascal classes
Can be used from unit wrappers as follows:
- APyDelphiWrapper.RegisterDelphiWrapper(TPyClassWrapper);
+ PyDelphiWrapper1.RegisterDelphiWrapper(TPyClassWrapper);
or at runtime (e.g. inside the FormCreate handler:
PyDelphiWrapper1.RegisterDelphiWrapper(TPyClassWrapper).Initialize;
if you want your class to capable of being instantiated from python then do:
- TTestWrapper = class(TPyClassWrapper)
+ TMyClassWrapper = class(TPyClassWrapper)
constructor CreateWith(APythonType: TPythonType; args, kwds: PPyObject); overload; override;
end;
- constuctor TTestWrapper.CreateWith(APythonType: TPythonType; args, kwds: PPyObject);
+ constuctor TMyClassWrapper.CreateWith(APythonType: TPythonType; args, kwds: PPyObject);
begin
Create(APythonType);
- DelphiObject := TTest.Create;
+ DelphiObject := TMyClass.Create;
end;
- PyDelphiWrapper1.RegisterDelphiWrapper(TTestWrapper).Initialize;
+ PyDelphiWrapper1.RegisterDelphiWrapper(TMyClassWrapper).Initialize;
}
TPyClassWrapper = class(TPyDelphiObject)
+ private
function GetDelphiObject: T;
procedure SetDelphiObject(const Value: T);
public
@@ -991,6 +992,8 @@ TPyDelphiWrapper = class(TEngineClient, IFreeNotificationSubscriber)
{$IFDEF EXTENDED_RTTI}
function CreateVarParam(PyDelphiWrapper : TPyDelphiWrapper;
const AValue: TValue) : PPyObject; overload;
+ function SimpleValueToPython(const Value: TValue;
+ out ErrMsg: string): PPyObject;
function TValueToPyObject(const Value: TValue;
DelphiWrapper: TPyDelphiWrapper; out ErrMsg: string): PPyObject;
function PyObjectToTValue(PyArg : PPyObject; ArgType: TRttiType;
@@ -1000,7 +1003,7 @@ TPyDelphiWrapper = class(TEngineClient, IFreeNotificationSubscriber)
implementation
-Uses
+uses
Math,
StrUtils,
RTLConsts,
@@ -1021,12 +1024,13 @@ implementation
rs_ErrCheckBound = 'Delphi wrapper %s is not bound';
rs_ErrSequence = 'Wrapper %s does not support sequences';
rs_ErrInvalidArgs = '"%s" called with invalid arguments.'#$A'Error: %s';
- rs_ErrInvalidRet = 'Call "%s" returned a value that could not be coverted to Python'#$A'Error: %s';
- rs_IncompatibleArguments = 'Expected and actual arguements are incompatible';
+ rs_ErrInvalidRet = 'Call "%s" returned a value that could not be converted to Python'#$A'Error: %s';
+ rs_IncompatibleArguments = 'Expected and actual arguments are incompatible';
rs_ErrAttrGet = 'Error in getting property "%s".'#$A'Error: %s';
rs_UnknownAttribute = 'Unknown attribute';
rs_ErrIterSupport = 'Wrapper %s does not support iterators';
- rs_ErrAttrSetr = 'Error in setting property %s'#$A'Error: %s';
+ rs_ErrAttrSet = 'Error in setting property %s'#$A'Error: %s';
+ rs_ErrObjectDestroyed = 'Trying to access a destroyed pascal object';
rs_IncompatibleClasses = 'Incompatible classes';
rs_IncompatibleRecords = 'Incompatible record types';
rs_IncompatibleInterfaces = 'Incompatible interfaces';
@@ -1038,6 +1042,7 @@ implementation
rs_ExpectedNil = 'In static methods Self should be nil';
rs_ExpectedInterface = 'Expected a Pascal interface';
rs_ExpectedSequence = 'Expected a python sequence';
+ rsExpectedPointer = 'Expected a Pointer';
rs_InvalidClass = 'Invalid class';
rs_ErrEventNotReg = 'No Registered EventHandler for events of type "%s';
rs_ErrEventNoSuport = 'Class %s does not support events because it must '+
@@ -1523,8 +1528,8 @@ function TExposedGetSet.GetterWrapper(AObj: PPyObject; AContext : Pointer): PPyO
if not Assigned(Result) then
with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrAttrGet, [FRttiMember.Name, LOutMsg])));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrAttrGet, [FRttiMember.Name, LOutMsg]))));
end;
function TExposedGetSet.SetterWrapper(AObj, AValue: PPyObject; AContext: Pointer): Integer; cdecl;
@@ -1548,8 +1553,8 @@ function TExposedGetSet.SetterWrapper(AObj, AValue: PPyObject; AContext: Pointer
if Result <> 0 then
with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrAttrSetr, [FRttiMember.Name, ErrMsg])));
+ PyErr_SetString (PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrAttrSet, [FRttiMember.Name, ErrMsg]))));
end;
{ TExposedField }
@@ -1644,8 +1649,8 @@ function TExposedEvent.SetterWrapper(AObj, AValue: PPyObject; AContext: Pointer)
if Result <> 0 then
with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrAttrSetr, [FRttiMember.Name, ErrMsg])));
+ PyErr_SetString (PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrAttrSet, [FRttiMember.Name, ErrMsg]))));
end;
{ TExposedIndexedProperty }
@@ -1741,7 +1746,7 @@ function TPyIndexedProperty.MpAssSubscript(obj1, obj2: PPyObject) : Integer;
if not FProperty.IsWritable then
begin
with Engine do
- PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString(rs_NotWritable));
+ PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString(rs_NotWritable)));
Exit;
end;
@@ -1865,8 +1870,8 @@ class procedure TRttiEventHandler.ImplCallback(UserData: Pointer;
if Assigned(PyResult) and (EventHandler.MethodType.ReturnType <> nil) and
not PyObjectToTValue(PyResult, EventHandler.MethodType.ReturnType, Result, ErrMsg)
then
- Engine.PyErr_SetObject(Engine.PyExc_TypeError^, Engine.PyUnicodeFromString(
- Format(rs_ErrInvalidRet, [string(EventHandler.PropertyInfo.Name), ErrMsg])));
+ Engine.PyErr_SetString(Engine.PyExc_TypeError^, PAnsiChar(Engine.EncodeString(
+ Format(rs_ErrInvalidRet, [string(EventHandler.PropertyInfo.Name), ErrMsg]))));
Engine.Py_XDECREF(PyResult);
finally
Engine.Py_XDECREF(PyArgs);
@@ -1900,9 +1905,8 @@ function GlobalDelphiWrapper: TPyDelphiWrapper;
procedure InvalidArguments(const MethName, ErrMsg : string);
begin
with GetPythonEngine do
- PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString(
- Format(rs_ErrInvalidArgs,
- [MethName, ErrMsg])));
+ PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString(
+ Format(rs_ErrInvalidArgs, [MethName, ErrMsg]))));
end;
function ValidateClassRef(PyValue: PPyObject; RefClass: TClass;
@@ -2032,8 +2036,16 @@ function SimplePythonToValue(PyValue: PPyObject; TypeInfo: PTypeInfo;
end
else
ErrMsg := rs_ErrPythonToValue;
- tkString, tkWString, tkUString,
- tkLString, tkChar, tkWChar:
+ tkString, tkLString, tkChar:
+ begin
+ if GetPythonEngine.PyBytes_Check(PyValue) then
+ V := TValue.From(GetPythonEngine.PyBytesAsAnsiString(PyValue))
+ else
+ V := GetPythonEngine.PyObjectAsString(PyValue);
+ Value := V.Cast(TypeInfo);
+ Result := True;
+ end;
+ tkWString, tkUString, tkWChar:
begin
V := GetPythonEngine.PyObjectAsString(PyValue);
Value := V.Cast(TypeInfo);
@@ -2176,6 +2188,40 @@ function ValidateDynArray(PyValue: PPyObject; const RttiType: TRttiType;
end;
end;
+function ValidatePointer(PyValue: PPyObject; const RttiType: TRttiType;
+ out ParamValue: TValue; out ErrMsg: string): Boolean;
+var
+ RefType: TRttiType;
+ PyEngine: TPythonEngine;
+ P: Pointer;
+begin
+ Result := False;
+ PyEngine := GetPythonEngine;
+
+ if (RTTIType is TRttiPointerType) then
+ begin
+ RefType := TRttiPointerType(RTTIType).ReferredType;
+ if Assigned(RefType) and (RefType.Name = 'PyObject') then
+ begin
+ Result := True;
+ ParamValue := TValue.From(PyValue);
+ end
+ else if PyEngine.PyLong_Check(PyValue) then
+ begin
+ P := PyEngine.PyLong_AsVoidPtr(PyValue);
+ if PyEngine.PyErr_Occurred = nil then
+ begin
+ Result := True;
+ ParamValue := TValue.From(P);
+ end
+ else
+ PyEngine.PyErr_Clear;
+ end;
+ end;
+ if not Result then
+ ErrMsg := rsExpectedPointer;
+end;
+
function PyObjectToTValue(PyArg: PPyObject; ArgType: TRttiType;
out Arg: TValue; out ErrMsg: string): Boolean;
var
@@ -2205,7 +2251,9 @@ function PyObjectToTValue(PyArg: PPyObject; ArgType: TRttiType;
tkRecord{$IFDEF MANAGED_RECORD}, tkMRecord{$ENDIF}:
Result := ValidateRecordProperty(PyArg, ArgType.Handle, Arg, ErrMsg);
tkDynArray:
- Result := ValidateDynArray(PyArg, ArgType, Arg, ErrMsg)
+ Result := ValidateDynArray(PyArg, ArgType, Arg, ErrMsg);
+ tkPointer:
+ Result := ValidatePointer(PyArg, ArgType, Arg, ErrMsg);
else
Result := SimplePythonToValue(PyArg, ArgType.Handle, Arg, ErrMsg);
end;
@@ -2244,7 +2292,7 @@ function TValueToPyObject(const Value: TValue;
DelphiWrapper: TPyDelphiWrapper; out ErrMsg: string): PPyObject;
begin
if Value.IsEmpty then
- Result := GetPythonEngine.ReturnNone
+ Result := DelphiWrapper.Engine.ReturnNone
else
case Value.Kind of
tkClass: Result := DelphiWrapper.Wrap(Value.AsObject);
@@ -2254,6 +2302,11 @@ function TValueToPyObject(const Value: TValue;
Result := DelphiWrapper.WrapRecord(Value);
tkArray, tkDynArray:
Result := DynArrayToPython(Value, DelphiWrapper, ErrMsg);
+ tkPointer:
+ if Value.TypeInfo = TypeInfo(PPyObject) then
+ Result := Value.AsType
+ else
+ Result := DelphiWrapper.Engine.PyLong_FromVoidPtr(Value.AsType);
else
Result := SimpleValueToPython(Value, ErrMsg);
end;
@@ -2313,8 +2366,8 @@ function CheckIndex(AIndex, ACount : Integer; const AIndexName : string = 'Index
with GetPythonEngine do
begin
Result := False;
- PyErr_SetObject (PyExc_IndexError^, PyUnicodeFromString(
- Format(rs_ErrCheckIndex,[AIndexName, AIndex])));
+ PyErr_SetString(PyExc_IndexError^, PAnsiChar(EncodeString(
+ Format(rs_ErrCheckIndex,[AIndexName, AIndex]))));
end
else
Result := True;
@@ -2331,8 +2384,8 @@ function CheckIntAttribute(AAttribute : PPyObject; const AAttributeName : string
begin
Result := False;
with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrCheckInt, [AAttributeName])));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrCheckInt, [AAttributeName]))));
end;
end;
@@ -2347,8 +2400,8 @@ function CheckFloatAttribute(AAttribute : PPyObject; const AAttributeName : stri
begin
Result := False;
with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrCheckFloat, [AAttributeName])));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrCheckFloat, [AAttributeName]))));
end;
end;
@@ -2369,8 +2422,8 @@ function CheckStrAttribute(AAttribute : PPyObject; const AAttributeName : string
begin
Result := False;
with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrCheckStr, [AAttributeName])));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrCheckStr, [AAttributeName]))));
end;
end;
@@ -2382,8 +2435,8 @@ function CheckCallableAttribute(AAttribute : PPyObject; const AAttributeName : s
begin
Result := False;
with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrCheckCallable, [AAttributeName])));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrCheckCallable, [AAttributeName]))));
end;
end;
@@ -2395,9 +2448,9 @@ function CheckEnum(const AEnumName : string; AValue, AMinValue, AMaxValue : Int
begin
Result := False;
with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrCheckEnum,
- [AEnumName, AMinValue, AMaxValue, AValue])));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrCheckEnum,
+ [AEnumName, AMinValue, AMaxValue, AValue]))));
end;
end;
@@ -2420,8 +2473,8 @@ function CheckObjAttribute(AAttribute : PPyObject; const AAttributeName : string
begin
Result := False;
with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrCheckObjOfType, [AAttributeName, AExpectedClass.ClassName])));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrCheckObjOfType, [AAttributeName, AExpectedClass.ClassName]))));
end
else
begin
@@ -2433,8 +2486,8 @@ function CheckObjAttribute(AAttribute : PPyObject; const AAttributeName : string
begin
Result := False;
with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrCheckObj, [AAttributeName])));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrCheckObj, [AAttributeName]))));
end;
end;
@@ -2774,8 +2827,8 @@ function TPyDelphiContainer.SqAssItem(idx: NativeInt;
begin
Result := -1;
with GetPythonEngine do
- PyErr_SetObject( PyExc_SystemError^,
- PyUnicodeFromString(Format(rs_ErrSqAss, [fContainerAccess.Name])) );
+ PyErr_SetString( PyExc_SystemError^,
+ PAnsiChar(EncodeString(Format(rs_ErrSqAss, [fContainerAccess.Name]))));
end;
end;
@@ -2792,8 +2845,8 @@ function TPyDelphiContainer.SqContains(obj: PPyObject): integer;
begin
Result := -1;
with GetPythonEngine do
- PyErr_SetObject( PyExc_SystemError^,
- PyUnicodeFromString(Format(rs_ErrSqContains, [fContainerAccess.Name])) );
+ PyErr_SetString(PyExc_SystemError^,
+ PAnsiChar(EncodeString(Format(rs_ErrSqContains, [fContainerAccess.Name]))));
end;
end;
@@ -2887,8 +2940,8 @@ function TPyDelphiObject.CheckBound: Boolean;
Result := Assigned(DelphiObject);
if not Result then
with GetPythonEngine do
- PyErr_SetObject(PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrCheckBound, [ClassName])));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrCheckBound, [ClassName]))));
end;
function TPyDelphiObject.Compare(obj: PPyObject): Integer;
@@ -2918,8 +2971,8 @@ constructor TPyDelphiObject.Create(APythonType: TPythonType);
constructor TPyDelphiObject.CreateWith(APythonType: TPythonType; args, kwds: PPyObject);
begin
with APythonType.Engine do
- PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString(
- Format(rs_CannotCreate, [APythonType.TypeName])));
+ PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString(
+ Format(rs_CannotCreate, [APythonType.TypeName]))));
end;
function TPyDelphiObject.CreateContainerAccess: TContainerAccess;
@@ -3148,8 +3201,8 @@ function RttiCall(ParentAddress: pointer; DelphiWrapper: TPyDelphiWrapper;
if Result = nil then
with DelphiWrapper.Engine do
- PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString(
- Format(rs_ErrInvalidRet, [Method.Name, ErrMsg])));
+ PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString(
+ Format(rs_ErrInvalidRet, [Method.Name, ErrMsg]))));
except
on E: Exception do begin
Result := nil;
@@ -3364,8 +3417,8 @@ function TPyRttiObject.GetAttrO(key: PPyObject): PPyObject;
Result := GetRttiAttr(fAddr, RttiType, KeyName, PyDelphiWrapper, ErrMsg);
if not Assigned(Result) then
with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrAttrGet,[KeyName, ErrMsg])));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrAttrGet,[KeyName, ErrMsg]))));
end;
class procedure TPyRttiObject.RegisterMethods(PythonType: TPythonType);
@@ -3395,8 +3448,8 @@ function TPyRttiObject.SetAttrO(key, value: PPyObject): Integer;
if Result <> 0 then
with GetPythonEngine do
- PyErr_SetObject(PyExc_AttributeError^, PyUnicodeFromString(
- Format(rs_ErrAttrSetr, [KeyName, ErrMsg])));
+ PyErr_SetString(PyExc_AttributeError^, PAnsiChar(EncodeString(
+ Format(rs_ErrAttrSet, [KeyName, ErrMsg]))));
end;
function TPyRttiObject.SetProps(args, keywords: PPyObject): PPyObject;
@@ -3505,6 +3558,7 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject;
var
KeyName: string;
ErrMsg : string;
+ PyEngine: TPythonEngine;
{$IFNDEF EXTENDED_RTTI}
{$IFNDEF FPC}
Info: PMethodInfoHeader;
@@ -3516,16 +3570,24 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject;
RttiType: TRttiStructuredType;
{$ENDIF}
begin
- Result := inherited GetAttrO(key);
- if GetPythonEngine.PyErr_Occurred = nil then Exit; // We found what we wanted
+ Result := nil;
+ PyEngine := GetPythonEngine;
- // should not happen
- if not (Assigned(DelphiObject) and
- CheckStrAttribute(Key, 'GetAttrO key parameter', KeyName))
- then
+ // If DelphiObject is nil exit immediately with an error
+ if not Assigned(DelphiObject) then
+ begin
+ PyEngine.PyErr_SetString(PyEngine.PyExc_AttributeError^,
+ PAnsiChar(PyEngine.EncodeString(rs_ErrObjectDestroyed)));
Exit;
+ end;
+
+ if not CheckStrAttribute(Key, 'GetAttrO key parameter', KeyName) then
+ Exit; // should not happen
+
+ Result := inherited GetAttrO(key);
+ if PyEngine.PyErr_Occurred = nil then Exit; // We found what we wanted
- GetPythonEngine.PyErr_Clear;
+ PyEngine.PyErr_Clear;
{$IFDEF EXTENDED_RTTI}
// Use RTTI
if Assigned(DelphiObject) then begin
@@ -3582,17 +3644,17 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject;
{$ELSE FPC}
if GetTypeData(PropInfo^.PropType^)^.BaseType^ = TypeInfo(Boolean) then
{$ENDIF FPC}
- Result := GetPythonEngine.VariantAsPyObject(Boolean(GetOrdProp(Self.DelphiObject, PropInfo)))
+ Result := PyEngine.VariantAsPyObject(Boolean(GetOrdProp(Self.DelphiObject, PropInfo)))
else
{$IFDEF FPC}
- Result := GetPythonEngine.PyUnicodeFromString(GetEnumName(PropInfo^.PropType,
+ Result := PyEngine.PyUnicodeFromString(GetEnumName(PropInfo^.PropType,
{$ELSE FPC}
- Result := GetPythonEngine.PyUnicodeFromString(GetEnumName(PropInfo^.PropType^,
+ Result := PyEngine.PyUnicodeFromString(GetEnumName(PropInfo^.PropType^,
{$ENDIF FPC}
GetOrdProp(Self.DelphiObject, PropInfo)));
end
end else
- Result := GetPythonEngine.VariantAsPyObject(GetPropValue(DelphiObject, PropInfo));
+ Result := PyEngine.VariantAsPyObject(GetPropValue(DelphiObject, PropInfo));
end;
except
on E: Exception do begin
@@ -3602,9 +3664,8 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject;
end;
{$ENDIF}
if not Assigned(Result) then
- with GetPythonEngine do
- PyErr_SetObject (PyExc_AttributeError^,
- PyUnicodeFromString(Format(rs_ErrAttrGet,[KeyName, ErrMsg])));
+ PyEngine.PyErr_SetString(PyEngine.PyExc_AttributeError^,
+ PAnsiChar(PyEngine.EncodeString(Format(rs_ErrAttrGet,[KeyName, ErrMsg]))));
end;
function TPyDelphiObject.GetContainerAccess: TContainerAccess;
@@ -3767,9 +3828,9 @@ function TPyDelphiObject.Iter: PPyObject;
begin
Result := nil;
with GetPythonEngine do
- PyErr_SetObject( PyExc_SystemError^,
- PyUnicodeFromString(Format(rs_ErrIterSupport,
- [Self.ClassName])) );
+ PyErr_SetString(PyExc_SystemError^,
+ PAnsiChar(EncodeString(Format(rs_ErrIterSupport,
+ [Self.ClassName]))));
end;
end;
@@ -3788,7 +3849,7 @@ class procedure TPyDelphiObject.RegisterGetSets(PythonType: TPythonType);
PythonType.AddGetSet('__bound__', @TPyDelphiObject.Get_Bound, nil,
'Returns True if the wrapper is still bound to the Delphi instance.', nil);
PythonType.AddGetSet('__owned__', @TPyDelphiObject.Get_Owned, @TPyDelphiObject.Set_Owned,
- 'Returns True if the wrapper owns the Delphi instance.', nil);
+ 'Boolean read/write property that determines weather the wrapper owns the Delphi instance.', nil);
end;
class procedure TPyDelphiObject.RegisterMethods(PythonType: TPythonType);
@@ -3906,11 +3967,16 @@ function TPyDelphiObject.SetAttrO(key, value: PPyObject): Integer;
Result := -1;
PyEngine := GetPythonEngine;
- // should not happen
- if not (Assigned(DelphiObject) and
- CheckStrAttribute(Key, 'SetAttrO key parameter', KeyName))
- then
+ // If DelphiObject is nil exit immediately with an error
+ if not Assigned(DelphiObject) then
+ begin
+ PyEngine.PyErr_SetString(PyEngine.PyExc_AttributeError^,
+ PAnsiChar(PyEngine.EncodeString(rs_ErrObjectDestroyed)));
Exit;
+ end;
+
+ if not CheckStrAttribute(Key, 'SetAttrO key parameter', KeyName) then
+ Exit; // should not happen
// Only call the inherited method at this stage if the attribute exists
PyObj := PyEngine.PyObject_GenericGetAttr(GetSelf, key);
@@ -3949,10 +4015,6 @@ function TPyDelphiObject.SetAttrO(key, value: PPyObject): Integer;
// Subclasses have a __dict__ and can set extra fields
if Result <> 0 then
Result := inherited SetAttrO(key, value);
- if Result <> 0 then
- with PyEngine do
- PyErr_SetObject(PyEngine.PyExc_AttributeError^, PyUnicodeFromString(
- Format(rs_ErrAttrSetr, [KeyName, ErrMsg])));
end;
procedure TPyDelphiObject.SetDelphiObject(const Value: TObject);
@@ -4127,7 +4189,7 @@ class procedure TPyDelphiObject.ExposeMethods(AClass: TClass;
// Ignore methods with unhandled return type
if Assigned(LRttiMethod.ReturnType) and (LRttiMethod.ReturnType.TypeKind
- in [tkUnknown, tkMethod, tkPointer, tkProcedure])
+ in [tkUnknown, tkMethod, tkProcedure])
then
Continue;
@@ -4229,7 +4291,7 @@ class procedure TPyDelphiObject.ExposeFields(AClass: TClass;
Continue;
// Skip if the type cannot be handled
- if LRttiField.FieldType.TypeKind in [tkUnknown, tkMethod, tkPointer, tkProcedure] then
+ if LRttiField.FieldType.TypeKind in [tkUnknown, tkMethod, tkProcedure] then
Continue;
AddedFields := AddedFields + [LRttiField.Name];
@@ -4242,7 +4304,7 @@ class procedure TPyDelphiObject.ExposeFields(AClass: TClass;
if Assigned(PyDocServer) and PyDocServer.Initialized and
PyDocServer.ReadMemberDocStr(LRttiField, LDocStr)
then
- LExposedField.DocString := AnsiString(LDocStr);
+ LExposedField.DocString := Utf8Encode(LDocStr);
// Keep it alive until the Wrapper is Finalized
APyDelphiWrapper.fExposedMembers.Add(LExposedField);
@@ -4315,7 +4377,7 @@ class procedure TPyDelphiObject.ExposeProperties(AClass: TClass;
else
begin
// Skip if the type cannot be handled
- if LRttiProperty.PropertyType.TypeKind in [tkUnknown, tkPointer, tkMethod, tkProcedure] then
+ if LRttiProperty.PropertyType.TypeKind in [tkUnknown, tkMethod, tkProcedure] then
Continue;
// Create the exposed property
@@ -4329,7 +4391,7 @@ class procedure TPyDelphiObject.ExposeProperties(AClass: TClass;
if Assigned(PyDocServer) and PyDocServer.Initialized and
PyDocServer.ReadMemberDocStr(LRttiProperty, LDocStr)
then
- LExposedProperty.DocString := AnsiString(LDocStr);
+ LExposedProperty.DocString := Utf8Encode(LDocStr);
// Keep it alive until the Wrapper is Finalized
APyDelphiWrapper.fExposedMembers.Add(LExposedProperty);
@@ -4399,7 +4461,7 @@ class procedure TPyDelphiObject.ExposeIndexedProperties(AClass: TClass;
Continue;
// Skip if the type cannot be handled
- if LRttiProperty.PropertyType.TypeKind in [tkUnknown, tkPointer, tkMethod, tkProcedure] then
+ if LRttiProperty.PropertyType.TypeKind in [tkUnknown, tkMethod, tkProcedure] then
Continue;
AddedProperties := AddedProperties + [LRttiProperty.Name];
@@ -4412,7 +4474,7 @@ class procedure TPyDelphiObject.ExposeIndexedProperties(AClass: TClass;
if Assigned(PyDocServer) and PyDocServer.Initialized and
PyDocServer.ReadMemberDocStr(LRttiProperty, LDocStr)
then
- LExposedProperty.DocString := AnsiString(LDocStr);
+ LExposedProperty.DocString := Utf8Encode(LDocStr);
// Keep it alive until the Wrapper is Finalized
APyDelphiWrapper.fExposedMembers.Add(LExposedProperty);
@@ -4478,7 +4540,7 @@ function TPyDelphiObject.MpAssSubscript(obj1, obj2: PPyObject) : Integer;
if not Prop.IsWritable then
begin
with Engine do
- PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString(rs_NotWritable));
+ PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString(rs_NotWritable)));
Exit;
end;
@@ -4545,8 +4607,8 @@ function TPyDelphiObject.SqAssItem(idx: NativeInt; obj: PPyObject): integer;
begin
Result := -1;
with GetPythonEngine do
- PyErr_SetObject( PyExc_SystemError^,
- PyUnicodeFromString(Format(rs_ErrSqAss, [Self.ClassName])) );
+ PyErr_SetString( PyExc_SystemError^,
+ PAnsiChar(EncodeString(Format(rs_ErrSqAss, [Self.ClassName]))));
end;
end;
@@ -4576,8 +4638,8 @@ function TPyDelphiObject.SqItem(idx: NativeInt): PPyObject;
begin
Result := nil;
with GetPythonEngine do
- PyErr_SetObject( PyExc_SystemError^,
- PyUnicodeFromString(Format(rs_ErrSequence, [Self.ClassName])) );
+ PyErr_SetString(PyExc_SystemError^,
+ PAnsiChar(EncodeString(Format(rs_ErrSequence, [Self.ClassName]))));
end;
end;
@@ -4608,8 +4670,8 @@ function TPyDelphiObject.ToList_Wrapper(args: PPyObject): PPyObject;
begin
Result := nil;
with GetPythonEngine do
- PyErr_SetObject( PyExc_SystemError^,
- PyUnicodeFromString(Format(rs_ErrSequence, [Self.ClassName])) );
+ PyErr_SetString(PyExc_SystemError^,
+ PAnsiChar(EncodeString(Format(rs_ErrSequence, [Self.ClassName]))));
end
else if GetPythonEngine.PyArg_ParseTuple( args, ':ToList' ) <> 0 then
with GetPythonEngine do
@@ -4632,8 +4694,8 @@ function TPyDelphiObject.ToTuple_Wrapper(args: PPyObject): PPyObject;
begin
Result := nil;
with GetPythonEngine do
- PyErr_SetObject( PyExc_SystemError^,
- PyUnicodeFromString(Format(rs_ErrSequence, [Self.ClassName])) );
+ PyErr_SetString( PyExc_SystemError^,
+ PAnsiChar(EncodeString(Format(rs_ErrSequence, [Self.ClassName]))));
end
else if GetPythonEngine.PyArg_ParseTuple( args, ':ToTuple' ) <> 0 then
with GetPythonEngine do
@@ -4699,9 +4761,9 @@ function TPyDelphiMethodObject.Call(ob1, ob2: PPyObject): PPyObject;
on E: Exception do
begin
Result := nil;
- PyErr_SetObject (PyExc_TypeError^,
- PyUnicodeFromString(Format(rs_ErrInvalidArgs,
- [MethodInfo.Name, E.Message])));
+ PyErr_SetString(PyExc_TypeError^,
+ PAnsiChar(EncodeString(Format(rs_ErrInvalidArgs,
+ [MethodInfo.Name, E.Message]))));
end;
end;
end;
@@ -5177,9 +5239,8 @@ function TPyDelphiWrapper.CreateComponent(pself, args: PPyObject): PPyObject;
Klass := nil;
end;
if (Klass = nil) or not Klass.InheritsFrom(TComponent) then begin
- PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString(
- Format(rs_ErrInvalidArgs,
- ['CreateComponent', rs_InvalidClass])));
+ PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString(
+ Format(rs_ErrInvalidArgs, ['CreateComponent', rs_InvalidClass]))));
Exit;
end;
@@ -5194,9 +5255,8 @@ function TPyDelphiWrapper.CreateComponent(pself, args: PPyObject): PPyObject;
Ownership := soOwned;
Result := Self.Wrap(Component, Ownership);
end else
- PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString(
- Format(rs_ErrInvalidArgs,
- ['CreateComponent', ''])));
+ PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString(
+ Format(rs_ErrInvalidArgs, ['CreateComponent', '']))));
end;
end;
@@ -5359,12 +5419,11 @@ procedure TPyDelphiWrapper.Initialize;
with TPythonType(fHelperClassRegister.Objects[i]) do
if not Initialized then Initialize;
// Initialize module
- if Assigned(FModule) then begin
+ if Assigned(FModule) then
+ begin
+ CreateModuleFunctions;
if Module.Initialized then
- begin
- CreateModuleFunctions;
- CreateModuleVars;
- end
+ CreateModuleVars
else
Module.AddClient( Self );
end;
@@ -5373,7 +5432,6 @@ procedure TPyDelphiWrapper.Initialize;
procedure TPyDelphiWrapper.ModuleReady(Sender : TObject);
begin
inherited;
- CreateModuleFunctions;
CreateModuleVars;
end;
@@ -5482,13 +5540,13 @@ procedure TPyDelphiWrapper.SetModule(const Value: TPythonModule);
TPythonType(fHelperClassRegister.Objects[i]).Module := Value;
if Assigned(FModule) then
if Initialized and (ComponentState * [csDesigning, csLoading] = []) then
+ begin
+ CreateModuleFunctions;
if FModule.Initialized then
- begin
- CreateModuleFunctions;
- CreateModuleVars;
- end
+ CreateModuleVars
else
FModule.AddClient(Self);
+ end;
end;
end;
diff --git a/Source/WrapDelphiClasses.pas b/Source/WrapDelphiClasses.pas
index bfee8aa3..f7f57a86 100644
--- a/Source/WrapDelphiClasses.pas
+++ b/Source/WrapDelphiClasses.pas
@@ -1221,13 +1221,13 @@ function TPyDelphiComponent.MpSubscript(obj: PPyObject): PPyObject;
else
begin
Result := nil;
- PyErr_SetString (PyExc_KeyError^, PAnsiChar(AnsiString(_name)));
+ PyErr_SetString(PyExc_KeyError^, PAnsiChar(EncodeString(_name)));
end;
end
else
begin
Result := nil;
- PyErr_SetString (PyExc_KeyError^, 'Key must be a string');
+ PyErr_SetString(PyExc_KeyError^, 'Key must be a string');
end;
end;
end;
@@ -1329,7 +1329,7 @@ function TStringsAccess.SetItem(AIndex: Integer; AValue: PPyObject): Boolean;
else
begin
Result := False;
- PyErr_SetString (PyExc_AttributeError^, 'You can only assign strings to TStrings items');
+ PyErr_SetString(PyExc_AttributeError^, 'You can only assign strings to TStrings items');
end;
end
end;
@@ -1393,7 +1393,7 @@ function TStringsObjectsAccess.SetItem(AIndex: Integer; AValue: PPyObject): Bool
else
begin
Result := False;
- PyErr_SetString (PyExc_AttributeError^, 'You can only assign Delphi wrappers to Objects items');
+ PyErr_SetString(PyExc_AttributeError^, 'You can only assign Delphi wrappers to Objects items');
end;
end
end;
@@ -1617,11 +1617,11 @@ function TPyDelphiStrings.MpSubscript(obj: PPyObject): PPyObject;
else
Result := GetPythonEngine.ReturnNone;
end else with GetPythonEngine do begin
- PyErr_SetString (PyExc_KeyError^, PAnsiChar(AnsiString(S)));
+ PyErr_SetString(PyExc_KeyError^, PAnsiChar(EncodeString(S)));
Result := nil;
end;
end else with GetPythonEngine do begin
- PyErr_SetString (PyExc_KeyError^, '');
+ PyErr_SetString(PyExc_KeyError^, '');
Result := nil;
end;
end;
@@ -2445,7 +2445,7 @@ TResourceStreamClass = class of TResourceStream;
except
on E: Exception do
with GetPythonEngine do
- PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(AnsiString(E.Message)));
+ PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(EncodeString(E.Message)));
end;
//Maybe it was created on the next attempt...
diff --git a/Source/WrapDelphiTypes.pas b/Source/WrapDelphiTypes.pas
index e572b851..86f00e22 100644
--- a/Source/WrapDelphiTypes.pas
+++ b/Source/WrapDelphiTypes.pas
@@ -229,8 +229,8 @@ function CheckPointAttribute(AAttribute : PPyObject; const AAttributeName : stri
begin
Result := False;
with GetPythonEngine do
- PyErr_SetString (PyExc_AttributeError^,
- PAnsiChar(AnsiString(Format('%s receives only Point objects', [AAttributeName]))));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format('%s receives only Point objects', [AAttributeName]))));
end;
end;
end;
@@ -248,8 +248,8 @@ function CheckRectAttribute(AAttribute : PPyObject; const AAttributeName : strin
begin
Result := False;
with GetPythonEngine do
- PyErr_SetString (PyExc_AttributeError^,
- PAnsiChar(AnsiString(Format('%s receives only Rect objects', [AAttributeName]))));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format('%s receives only Rect objects', [AAttributeName]))));
end;
end;
end;
@@ -267,8 +267,8 @@ function CheckSizeAttribute(AAttribute : PPyObject; const AAttributeName : strin
begin
Result := False;
with GetPythonEngine do
- PyErr_SetString (PyExc_AttributeError^,
- PAnsiChar(AnsiString(Format('%s receives only Size objects', [AAttributeName]))));
+ PyErr_SetString(PyExc_AttributeError^,
+ PAnsiChar(EncodeString(Format('%s receives only Size objects', [AAttributeName]))));
end;
end;
end;
diff --git a/Source/WrapFireDAC.pas b/Source/WrapFireDAC.pas
index eefa7af9..76e64aec 100644
--- a/Source/WrapFireDAC.pas
+++ b/Source/WrapFireDAC.pas
@@ -597,7 +597,7 @@ function TPyDBField.CheckField : Boolean;
if not Assigned(DelphiObject) then begin
Result := False;
with GetPythonEngine do
- PyErr_SetString (PyExc_RuntimeError^, PAnsiChar('No field defined !') );
+ PyErr_SetString(PyExc_RuntimeError^, PAnsiChar('No field defined !') );
end
else
Result := True;
@@ -978,7 +978,7 @@ function TPyDBDataset.Do_Fields( args : PPyObject ): PPyObject;
Result := PyDelphiWrapper.Wrap(l_oDataset.Fields[idx])
else begin
Result := nil;
- PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Value out of range : %d', [idx]))));
+ PyErr_SetString(PyExc_AttributeError^, PAnsiChar(EncodeString(Format('Value out of range : %d', [idx]))));
end;
end
else
@@ -1011,7 +1011,7 @@ function TPyDBDataset.Do_FieldByName( args : PPyObject ) : PPyObject;
Result := PyDelphiWrapper.Wrap(fld)
else begin
Result := nil;
- PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown field "%s"', [String(s)]))) );
+ PyErr_SetString(PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown field "%s"', [String(s)]))) );
end;
end
else
@@ -1191,7 +1191,7 @@ function TPyDBDataset.Do_Locate( args : PPyObject ) : PPyObject;
try
if PyArg_ParseTuple( args, 'sOO:DBDataset.Locate',@keyFields, @keyValues, @options ) <> 0 then begin
if PySequence_Check(options) = 0 then
- PyErr_SetString (PyExc_AttributeError^, 'Third argument of Locate must be a sequence.')
+ PyErr_SetString(PyExc_AttributeError^, 'Third argument of Locate must be a sequence.')
else begin
// Prepare the locate options
ListToSet( options, @opt, sizeof(opt) );
@@ -1391,14 +1391,14 @@ function TPyDBTable.CheckActiveDBTable(aMustOpen: Boolean): Boolean;
if not aMustOpen then begin
Result := False;
with GetPythonEngine do
- PyErr_SetString (PyExc_RuntimeError^, PAnsiChar('DBTable is open!') );
+ PyErr_SetString(PyExc_RuntimeError^, PAnsiChar('DBTable is open!') );
end;
end
else begin
if aMustOpen then begin
Result := False;
with GetPythonEngine do
- PyErr_SetString (PyExc_RuntimeError^, PAnsiChar('DBTable is not open!') );
+ PyErr_SetString(PyExc_RuntimeError^, PAnsiChar('DBTable is not open!') );
end;
end;
end;
@@ -1838,10 +1838,10 @@ function TPyDBTable.Do_SetRange( args : PPyObject ) : PPyObject;
if l_oTable.Active and
(PyArg_ParseTuple( args, 'OO:FDTable.SetRange',@l_oPyStartValues, @l_oPyEndValues ) <> 0) then begin
if PySequence_Check(l_oPyStartValues) = 0 then begin
- PyErr_SetString (PyExc_AttributeError^, 'First argument of SetRange must be a sequence.');
+ PyErr_SetString(PyExc_AttributeError^, 'First argument of SetRange must be a sequence.');
end
else if PySequence_Check(l_oPyEndValues) = 0 then begin
- PyErr_SetString (PyExc_AttributeError^, 'Second argument of SetRange must be a sequence.');
+ PyErr_SetString(PyExc_AttributeError^, 'Second argument of SetRange must be a sequence.');
end
else begin
l_oTable.SetRangeStart;
@@ -1952,14 +1952,14 @@ function TPyDBQuery.CheckActiveDBQuery(aMustOpen: Boolean): Boolean;
if not aMustOpen then begin
Result := False;
with GetPythonEngine do
- PyErr_SetString (PyExc_RuntimeError^, PAnsiChar('DBQuery is open!') );
+ PyErr_SetString(PyExc_RuntimeError^, PAnsiChar('DBQuery is open!') );
end;
end
else begin
if aMustOpen then begin
Result := False;
with GetPythonEngine do
- PyErr_SetString (PyExc_RuntimeError^, PAnsiChar('DBQuery is not open!') );
+ PyErr_SetString(PyExc_RuntimeError^, PAnsiChar('DBQuery is not open!') );
end;
end;
end;
diff --git a/Source/fmx/WrapDelphiFmx.pas b/Source/fmx/WrapDelphiFmx.pas
index 0bcc5f45..92f11120 100644
--- a/Source/fmx/WrapDelphiFmx.pas
+++ b/Source/fmx/WrapDelphiFmx.pas
@@ -24,9 +24,7 @@ implementation
WrapDelphiWindows,
{$ENDIF MSWINDOWS}
WrapDelphiDataBind,
- {$IFNDEF LINUX}
WrapFmxDataBind,
- {$ENDIF LINUX}
WrapFmxTypes,
WrapFmxImgList,
WrapFmxControls,
diff --git a/Source/fmx/WrapFmxForms.pas b/Source/fmx/WrapFmxForms.pas
index f3a2b68e..906f14b5 100644
--- a/Source/fmx/WrapFmxForms.pas
+++ b/Source/fmx/WrapFmxForms.pas
@@ -466,7 +466,7 @@ function TPyDelphiCommonCustomForm.LoadProps_Wrapper(
except
on E: Exception do
with GetPythonEngine do
- PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(AnsiString(E.Message)));
+ PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(Utf8Encode(E.Message)));
end;
Result := nil;
end;
diff --git a/Source/fmx/WrapFmxTypes.pas b/Source/fmx/WrapFmxTypes.pas
index 53e36d9f..b7bbb8d5 100644
--- a/Source/fmx/WrapFmxTypes.pas
+++ b/Source/fmx/WrapFmxTypes.pas
@@ -505,7 +505,7 @@ function CheckPointFAttribute(AAttribute : PPyObject; const AAttributeName : str
Result := False;
with GetPythonEngine do
PyErr_SetString (PyExc_AttributeError^,
- PAnsiChar(AnsiString(Format('%s receives only PointF objects', [AAttributeName]))));
+ PAnsiChar(Utf8Encode(Format('%s receives only PointF objects', [AAttributeName]))));
end;
end;
end;
@@ -524,7 +524,7 @@ function CheckSizeFAttribute(AAttribute : PPyObject; const AAttributeName : stri
Result := False;
with GetPythonEngine do
PyErr_SetString (PyExc_AttributeError^,
- PAnsiChar(AnsiString(Format('%s receives only SizeF objects', [AAttributeName]))));
+ PAnsiChar(Utf8Encode(Format('%s receives only SizeF objects', [AAttributeName]))));
end;
end;
end;
@@ -543,7 +543,7 @@ function CheckRectFAttribute(AAttribute: PPyObject; const AAttributeName: string
Result := False;
with GetPythonEngine do
PyErr_SetString (PyExc_AttributeError^,
- PAnsiChar(AnsiString(Format('%s receives only RectF objects', [AAttributeName]))));
+ PAnsiChar(Utf8Encode(Format('%s receives only RectF objects', [AAttributeName]))));
end;
end;
end;
@@ -562,7 +562,7 @@ function CheckTouchAttribute(AAttribute: PPyObject; const AAttributeName: string
Result := False;
with GetPythonEngine do
PyErr_SetString (PyExc_AttributeError^,
- PAnsiChar(AnsiString(Format('%s receives only Touch objects', [AAttributeName]))));
+ PAnsiChar(Utf8Encode(Format('%s receives only Touch objects', [AAttributeName]))));
end;
end;
end;
diff --git a/Source/vcl/WrapVclComCtrls.pas b/Source/vcl/WrapVclComCtrls.pas
index 18c161e8..aff247eb 100644
--- a/Source/vcl/WrapVclComCtrls.pas
+++ b/Source/vcl/WrapVclComCtrls.pas
@@ -742,8 +742,10 @@ TPyDelphiListView = class(TPyDelphiCustomListView)
implementation
uses
- WrapDelphiTypes, WrapDelphiWindows,
- Vcl.ExtCtrls;
+ System.Rtti,
+ Vcl.ExtCtrls,
+ WrapDelphiTypes,
+ WrapDelphiWindows;
{ Register the wrappers, the globals and the constants }
type
@@ -781,30 +783,12 @@ function CustomDrawStageToPython(const ACustomDrawStage: TCustomDrawStage): PPyO
end;
function CustomDrawStateToPython(const ACustomDrawState: TCustomDrawState): PPyObject;
-
- procedure Append(const AList: PPyObject; const AString: string);
- var
- LItem: PPyObject;
- begin
- with GetPythonEngine do begin
- LItem := PyUnicodeFromString(AString);
- PyList_Append(AList, LItem);
- Py_XDecRef(LItem);
- end;
- end;
-
var
- LCompType: PTypeInfo;
- LMin: integer;
- LMax: integer;
- LState: integer;
+ ErrMsg: string;
+ Value: TValue;
begin
- Result := GetPythonEngine().PyList_New(0);
- LCompType := GetTypeData(TypeInfo(TCustomDrawState)).CompType^;
- LMin := LCompType^.TypeData^.MinValue;
- LMax := LCompType^.TypeData^.MaxValue;
- for LState := LMin to LMax do
- Append(Result, GetEnumName(LCompType, LState));
+ Value := TValue.From(ACustomDrawState);
+ Result := SimpleValueToPython(Value, ErrMsg);
end;
function ItemChangeToPython(const AItemChange: TItemChange): PPyObject;
diff --git a/Source/vcl/WrapVclForms.pas b/Source/vcl/WrapVclForms.pas
index 0a373dfa..b3d77bec 100644
--- a/Source/vcl/WrapVclForms.pas
+++ b/Source/vcl/WrapVclForms.pas
@@ -572,7 +572,7 @@ function TPyDelphiCustomForm.LoadProps_Wrapper(args: PPyObject): PPyObject;
except
on E: Exception do
with GetPythonEngine() do
- PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(AnsiString(E.Message)));
+ PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(EncodeString(E.Message)));
end;
Result := nil;
end;
@@ -1072,7 +1072,7 @@ class procedure TPyDelphiScreen.RegisterMethods(PythonType: TPythonType);
'Allows forms to be aligned in the screen.');
PythonType.AddMethod('Realign', @TPyDelphiScreen.Realign_Wrapper,
'TScreen.Realign()'#10 +
- 'Realigns the screen’s forms according to their Align properties.');
+ 'Realigns the screen''s forms according to their Align properties.');
PythonType.AddMethod('ResetFonts', @TPyDelphiScreen.ResetFonts_Wrapper,
'TScreen.ResetFonts()'#10 +
'Reinitializes the fonts listed in the Fonts property.');
diff --git a/Source/vcl/WrapVclGraphics.pas b/Source/vcl/WrapVclGraphics.pas
index 1479d5f6..21a54013 100644
--- a/Source/vcl/WrapVclGraphics.pas
+++ b/Source/vcl/WrapVclGraphics.pas
@@ -1057,7 +1057,7 @@ function TPyDelphiBitmap.Set_HandleType(AValue: PPyObject;
else
begin
with GetPythonEngine do
- PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown THandleType value "%s"', [_value]))));
+ PyErr_SetString(PyExc_AttributeError^, PAnsiChar(EncodeString(Format('Unknown THandleType value "%s"', [_value]))));
Result := -1;
Exit;
end;
@@ -1143,7 +1143,7 @@ function TPyDelphiBitmap.Set_PixelFormat(AValue: PPyObject;
DelphiObject.PixelFormat := pfCustom
else
begin
- PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown TPixelFormat value "%s"', [_value]))));
+ PyErr_SetString(PyExc_AttributeError^, PAnsiChar(EncodeString(Format('Unknown TPixelFormat value "%s"', [_value]))));
Result := -1;
Exit;
end;
@@ -1184,7 +1184,7 @@ function TPyDelphiBitmap.Set_TransparentMode(AValue: PPyObject;
else
begin
with GetPythonEngine do
- PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown TTransparentMode value "%s"', [_value]))));
+ PyErr_SetString(PyExc_AttributeError^, PAnsiChar(EncodeString(Format('Unknown TTransparentMode value "%s"', [_value]))));
Result := -1;
Exit;
end;
@@ -1615,7 +1615,7 @@ function TPyDelphiCanvas.PolyBezier_Wrapper(args: PPyObject): PPyObject;
else
begin
Result := nil;
- PyErr_SetString (PyExc_AttributeError^, 'PolyBezier accepts only a sequence of points as single parameter');
+ PyErr_SetString(PyExc_AttributeError^, 'PolyBezier accepts only a sequence of points as single parameter');
end;
end
else
@@ -1662,7 +1662,7 @@ function TPyDelphiCanvas.PolyBezierTo_Wrapper(args: PPyObject): PPyObject;
else
begin
Result := nil;
- PyErr_SetString (PyExc_AttributeError^, 'PolyBezierTo accepts only a sequence of points as single parameter');
+ PyErr_SetString(PyExc_AttributeError^, 'PolyBezierTo accepts only a sequence of points as single parameter');
end;
end
else
@@ -1709,7 +1709,7 @@ function TPyDelphiCanvas.Polygon_Wrapper(args: PPyObject): PPyObject;
else
begin
Result := nil;
- PyErr_SetString (PyExc_AttributeError^, 'Polygon accepts only a sequence of points as single parameter');
+ PyErr_SetString(PyExc_AttributeError^, 'Polygon accepts only a sequence of points as single parameter');
end;
end
else
@@ -1755,7 +1755,7 @@ function TPyDelphiCanvas.Polyline_Wrapper(args: PPyObject): PPyObject;
else
begin
Result := nil;
- PyErr_SetString (PyExc_AttributeError^, 'Polyline accepts only a sequence of points as single parameter');
+ PyErr_SetString(PyExc_AttributeError^, 'Polyline accepts only a sequence of points as single parameter');
end;
end
else
diff --git a/Tests/AutoWrapEventHandlerTest.pas b/Tests/AutoWrapEventHandlerTest.pas
index feb9656d..173794c2 100644
--- a/Tests/AutoWrapEventHandlerTest.pas
+++ b/Tests/AutoWrapEventHandlerTest.pas
@@ -71,7 +71,6 @@ procedure TTestAutoWrapEventHandlers.SetupFixture;
PythonEngine.FatalMsgDlg := True;
PythonEngine.UseLastKnownVersion := True;
PythonEngine.AutoFinalize := True;
- PythonEngine.InitThreads := True;
PythonEngine.PyFlags := [pfInteractive];
DelphiModule := TPythonModule.Create(nil);
DelphiModule.Name := 'DelphiModule';
diff --git a/Tests/FMX/Android/NumberServicesTest.pas b/Tests/FMX/Android/NumberServicesTest.pas
index 115ba066..3aee6737 100644
--- a/Tests/FMX/Android/NumberServicesTest.pas
+++ b/Tests/FMX/Android/NumberServicesTest.pas
@@ -288,7 +288,7 @@ constructor PyTRandomInteger.CreateWith(PythonType: TPythonType; args,
FRandomInteger.Value := PythonToTRandomInteger(val1).Value;
except
on e: Exception do
- PyErr_SetString(PyExc_Exception^, PAnsiChar(AnsiString(e.Message)));
+ PyErr_SetString(PyExc_Exception^, PAnsiChar(EncodeString(e.Message)));
end;
end;
end;
diff --git a/Tests/NumberServicesTest.pas b/Tests/NumberServicesTest.pas
index d1e1a3cf..0b100950 100644
--- a/Tests/NumberServicesTest.pas
+++ b/Tests/NumberServicesTest.pas
@@ -176,7 +176,6 @@ procedure TTestNumberServices.SetupFixture;
PythonEngine.UseLastKnownVersion := True;
PythonEngine.AutoFinalize := True;
- PythonEngine.InitThreads := True;
PythonEngine.PyFlags := [pfInteractive];
PythonEngine.LoadDll;
@@ -292,7 +291,7 @@ constructor PyTRandomInteger.CreateWith(PythonType: TPythonType; args,
FRandomInteger.Value := PythonToTRandomInteger(val1).Value;
except
on e: Exception do
- PyErr_SetString(PyExc_Exception^, PAnsiChar(AnsiString(e.Message)));
+ PyErr_SetString(PyExc_Exception^, PAnsiChar(EncodeString(e.Message)));
end;
end;
end;
diff --git a/Tests/VarPythTest.pas b/Tests/VarPythTest.pas
index 34e68f0a..f32fa7de 100644
--- a/Tests/VarPythTest.pas
+++ b/Tests/VarPythTest.pas
@@ -74,7 +74,6 @@ procedure TTestVarPyth.SetupFixture;
PythonEngine.UseLastKnownVersion := True;
PythonEngine.AutoFinalize := True;
- PythonEngine.InitThreads := True;
PythonEngine.PyFlags := [pfInteractive];
PythonEngine.LoadDll;
end;
diff --git a/Tests/WrapDelphiEventHandlerTest.pas b/Tests/WrapDelphiEventHandlerTest.pas
index c6cda4ce..efaf5b44 100644
--- a/Tests/WrapDelphiEventHandlerTest.pas
+++ b/Tests/WrapDelphiEventHandlerTest.pas
@@ -215,7 +215,6 @@ procedure TTestWrapDelphiEventHandlers.SetupFixture;
PythonEngine.FatalMsgDlg := True;
PythonEngine.UseLastKnownVersion := True;
PythonEngine.AutoFinalize := True;
- PythonEngine.InitThreads := True;
PythonEngine.PyFlags := [pfInteractive];
DelphiModule := TPythonModule.Create(nil);
DelphiModule.Name := 'DelphiModule';
diff --git a/Tests/WrapDelphiTest.pas b/Tests/WrapDelphiTest.pas
index ba7ff43e..d320f53a 100644
--- a/Tests/WrapDelphiTest.pas
+++ b/Tests/WrapDelphiTest.pas
@@ -55,6 +55,7 @@ TTestRttiAccess = class
ObjectField: TObject;
RecordField: TTestRecord;
InterfaceField: ITestInterface;
+ PointerField: Pointer;
ClassRef: TClass;
function GetData: TObject;
procedure BuyFruits(AFruits: TFruits);
@@ -71,6 +72,7 @@ TTestRttiAccess = class
procedure VarArgsProc1(var I: Integer);
function VarArgsFunc1(var I: Integer): Integer;
procedure VarArgsProc2(var I: Integer; var S: string);
+ function PlaceInNewList(PyObj: PPyObject): PPyObject;
property Indexed[I: Integer]: Integer read GetIndexed write SetIndexed;
property Indexed2[S1, S2: string]: string read GetIndexed2 write SetIndexed2; default;
class var ClassField: string;
@@ -157,6 +159,10 @@ TTestWrapDelphi = class(TObject)
procedure TestIndexedProperties;
[Test]
procedure TestVarArgs;
+ [Test]
+ procedure TestPPyObjects;
+ [Test]
+ procedure TestPointers;
end;
implementation
@@ -202,7 +208,6 @@ procedure TTestWrapDelphi.SetupFixture;
PythonEngine.UseLastKnownVersion := True;
PythonEngine.AutoFinalize := True;
- PythonEngine.InitThreads := True;
PythonEngine.PyFlags := [pfInteractive];
DelphiModule := TPythonModule.Create(nil);
@@ -428,6 +433,21 @@ procedure TTestWrapDelphi.TestPassVariantArray;
Assert.Pass;
end;
+procedure TTestWrapDelphi.TestPPyObjects;
+var
+ List: Variant;
+begin
+ List := rtti_var.PlaceInNewList('abc');
+ Assert.IsTrue(VarIsPythonList(List));
+ Assert.AreEqual(List.GetItem(0), 'abc');
+end;
+
+procedure TTestWrapDelphi.TestPointers;
+begin
+ rtti_var.PointerField := $FFFF;
+ Assert.AreEqual(rtti_var.PointerField, $FFFF);
+end;
+
procedure TTestWrapDelphi.TestRecord;
begin
Rtti_rec.StringField := 'abcd';
@@ -616,6 +636,16 @@ procedure TTestRttiAccess.PassVariantArray(const Value: Variant);
Assert.IsTrue(VarIsArray(Value) and (VarArrayHighBound(Value, 1) = 9));
end;
+function TTestRttiAccess.PlaceInNewList(PyObj: PPyObject): PPyObject;
+begin
+ with GetPythonEngine do
+ begin
+ Result := PyList_New(1);
+ Py_XIncRef(PyObj);
+ PyList_SetItem(Result, 0, PyObj);
+ end;
+end;
+
procedure TTestRttiAccess.SellFruits(const AFruits: TFruitDynArray);
var
Fruit: TFruit;
diff --git a/Tutorials/Webinar II/AnalyticsDemo/MainFormSVG.dfm b/Tutorials/Webinar II/AnalyticsDemo/MainFormSVG.dfm
index 15464024..1642832f 100644
--- a/Tutorials/Webinar II/AnalyticsDemo/MainFormSVG.dfm
+++ b/Tutorials/Webinar II/AnalyticsDemo/MainFormSVG.dfm
@@ -254,7 +254,6 @@ object Form1: TForm1
Top = 89
end
object PythonEngine1: TPythonEngine
- InitThreads = True
IO = PythonGUIInputOutput1
Left = 632
Top = 136
diff --git a/Tutorials/Webinar II/VizDemo/MainFormSVG.dfm b/Tutorials/Webinar II/VizDemo/MainFormSVG.dfm
index cda1daa9..0d78949a 100644
--- a/Tutorials/Webinar II/VizDemo/MainFormSVG.dfm
+++ b/Tutorials/Webinar II/VizDemo/MainFormSVG.dfm
@@ -10,17 +10,12 @@ object Form1: TForm1
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
- OldCreateOrder = False
OnCreate = FormCreate
- PixelsPerInch = 96
TextHeight = 13
object Splitter1: TSplitter
Left = 489
Top = 0
Height = 613
- ExplicitLeft = 528
- ExplicitTop = 280
- ExplicitHeight = 100
end
object SVGIconImage1: TSVGIconImage
Left = 960
@@ -35,8 +30,6 @@ object Form1: TForm1
Width = 543
Height = 613
AutoSize = False
- ParentDoubleBuffered = False
- DoubleBuffered = True
Align = alClient
end
object PageControl1: TPageControl
@@ -46,7 +39,7 @@ object Form1: TForm1
Height = 613
ActivePage = TabSheet1
Align = alLeft
- TabOrder = 2
+ TabOrder = 0
object TabSheet1: TTabSheet
Caption = 'matplotlib'
object Panel1: TPanel
@@ -63,8 +56,6 @@ object Form1: TForm1
Height = 3
Cursor = crVSplit
Align = alBottom
- ExplicitTop = 10
- ExplicitWidth = 492
end
object SynEdit1: TSynEdit
Left = 1
@@ -72,6 +63,7 @@ object Form1: TForm1
Width = 479
Height = 444
Align = alClient
+ CaseSensitive = True
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -13
@@ -85,6 +77,8 @@ object Form1: TForm1
Gutter.Font.Height = -11
Gutter.Font.Name = 'Consolas'
Gutter.Font.Style = []
+ Gutter.Font.Quality = fqClearTypeNatural
+ Gutter.Bands = <>
Highlighter = SynPythonSyn1
Lines.Strings = (
'from delphi_module import svg_image'
@@ -102,10 +96,16 @@ object Form1: TForm1
'# stores the date as an np.datetime64 with a day unit ('#39'D'#39') in t' +
'he date column.'
-
- 'price_data = (cbook.get_sample_data('#39'goog.npz'#39', np_load=True)['#39'p' +
- 'rice_data'#39']'
- ' .view(np.recarray))'
+ '# Load Google stock price data from Matplotlib'#39's sample data'
+ 'data = cbook.get_sample_data('#39'goog.npz'#39')'
+ ''
+ '# Handle different return types from get_sample_data'
+ 'if isinstance(data, np.lib.npyio.NpzFile):'
+ ' # Already an NpzFile, access price_data directly'
+ ' price_data = data['#39'price_data'#39'].view(np.recarray)'
+ 'else:'
+ ' # Assume data is a path or file-like object, use np.load'
+ ' price_data = np.load(data)['#39'price_data'#39'].view(np.recarray)'
'price_data = price_data[-250:] # get the most recent 250 tradin' +
'g days'
@@ -138,6 +138,7 @@ object Form1: TForm1
'svg_image.SvgText = figdata_svg'
''
'#plt.show()')
+ ScrollbarAnnotations = <>
end
object Panel2: TPanel
Left = 1
@@ -183,8 +184,6 @@ object Form1: TForm1
Height = 3
Cursor = crVSplit
Align = alBottom
- ExplicitTop = 151
- ExplicitWidth = 433
end
object SynEdit2: TSynEdit
Left = 1
@@ -192,6 +191,7 @@ object Form1: TForm1
Width = 479
Height = 376
Align = alClient
+ CaseSensitive = True
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -13
@@ -205,6 +205,8 @@ object Form1: TForm1
Gutter.Font.Height = -11
Gutter.Font.Name = 'Consolas'
Gutter.Font.Style = []
+ Gutter.Font.Quality = fqClearTypeNatural
+ Gutter.Bands = <>
Highlighter = SynPythonSyn1
Lines.Strings = (
'from delphi_module import svg_image'
@@ -222,6 +224,7 @@ object Form1: TForm1
''
'#plt.show()'
'')
+ ScrollbarAnnotations = <>
end
object Panel6: TPanel
Left = 1
@@ -252,9 +255,6 @@ object Form1: TForm1
end
end
object SynPythonSyn1: TSynPythonSyn
- Options.AutoDetectEnabled = False
- Options.AutoDetectLineLimit = 0
- Options.Visible = False
Left = 632
Top = 40
end
@@ -264,6 +264,10 @@ object Form1: TForm1
Top = 89
end
object PythonEngine1: TPythonEngine
+ DllName = 'python313.dll'
+ APIVersion = 1013
+ RegVersion = '3.13'
+ UseLastKnownVersion = False
IO = PythonGUIInputOutput1
Left = 632
Top = 136