From 6afe08111fe099609a445e8b6346e0c03bdf9c18 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sun, 8 Dec 2024 23:38:28 +0200 Subject: [PATCH 01/17] Support for Python 3.14. Implemented PEP741 initialization. --- Source/PythonEngine.pas | 427 +++++++++++++++++++++++++++------------- 1 file changed, 292 insertions(+), 135 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index c08ea1dc..93cfa6d2 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -73,47 +73,51 @@ TPythonVersionProp = record end; const {$IFDEF MSWINDOWS} - PYTHON_KNOWN_VERSIONS: array[1..6] of TPythonVersionProp = + PYTHON_KNOWN_VERSIONS: array[1..7] of TPythonVersionProp = ( (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: 'python313.dll'; RegVersion: '3.13'; 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..6] of TPythonVersionProp = + PYTHON_KNOWN_VERSIONS: array[1..7] of TPythonVersionProp = ( (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.13.so'; RegVersion: '3.13'; 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..6] of TPythonVersionProp = + PYTHON_KNOWN_VERSIONS: array[1..7] of TPythonVersionProp = ( (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.13.dylib'; RegVersion: '3.13'; 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[1..6] of TPythonVersionProp = + PYTHON_KNOWN_VERSIONS: array[1..7] of TPythonVersionProp = ( (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.13.so'; RegVersion: '3.13'; 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} @@ -176,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 { @@ -994,6 +998,9 @@ PyConfig = record Filler: array [0..1000] of Byte; end; + // Opaque structure PEP 741 + PPyInitConfig = Pointer; + {$SCOPEDENUMS ON} TConfigFields = ( use_environment, @@ -1796,8 +1803,9 @@ TPythonInterface=class(TDynamicDll) Py_GetPrefix : function : PWCharT; cdecl; Py_GetProgramName : function : PWCharT; 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_IsInitialized : function : integer; cdecl; Py_GetProgramFullPath : function : PAnsiChar; cdecl; @@ -1818,7 +1826,7 @@ TPythonInterface=class(TDynamicDll) PyGILState_Ensure : function() : PyGILstate_STATE; cdecl; PyGILState_Release : procedure(gilstate : PyGILState_STATE); cdecl; - // Initialization functions + // 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; @@ -1830,6 +1838,17 @@ TPythonInterface=class(TDynamicDll) 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 @@ -1939,7 +1958,8 @@ TPythonInterface=class(TDynamicDll) type TEngineClient = class; TSysPathInitEvent = procedure(Sender: TObject; PathList: PPyObject) of object; - TConfigInitEvent = procedure(Sender: TObject; var Config: PyConfig) of object; + // Config will be either PPyConfig if version < 3.14 or PPyInitConfig + TConfigInitEvent = procedure(Sender: TObject; Config: Pointer) of object; TPythonFlag = (pfDebug, pfInteractive, pfNoSite, pfOptimize, pfVerbose, pfFrozenFlag, pfIgnoreEnvironmentFlag, pfIsolated); TPythonFlags = set of TPythonFlag; @@ -2021,14 +2041,12 @@ TPythonEngine = class(TPythonInterface) function GetClients( idx : Integer ) : TEngineClient; procedure Notification(AComponent: TComponent; Operation: TOperation); override; - procedure SetProgramArgs(var Config: PyConfig); 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(var Config: PyConfig); public // Constructors & Destructors @@ -4060,11 +4078,10 @@ procedure TPythonInterface.MapDll; Py_GetPrefix := Import('Py_GetPrefix'); Py_GetProgramName := Import('Py_GetProgramName'); - PyErr_NewException := Import('PyErr_NewException'); - try - PyMem_Malloc := Import ('PyMem_Malloc'); - except - end; + PyErr_NewException := Import('PyErr_NewException'); + PyMem_Malloc := Import ('PyMem_Malloc'); + PyMem_Free := Import ('PyMem_Free'); + Py_IsInitialized := Import('Py_IsInitialized'); Py_GetProgramFullPath := Import('Py_GetProgramFullPath'); Py_GetBuildInfo := Import('Py_GetBuildInfo'); @@ -4096,6 +4113,20 @@ procedure TPythonInterface.MapDll; 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; @@ -4626,56 +4657,253 @@ procedure TPythonEngine.DoOpenDll(const aDllName : string); end; end; -procedure TPythonEngine.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(pfFrozenFlag in FPyFlags, 1, 0); - PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.use_environment])^ := - IfThen(pfIgnoreEnvironmentFlag in FPyFlags, 0, 1); -end; - procedure TPythonEngine.Initialize; - procedure InitSysPath; + procedure ConfgigPEP587(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(pfFrozenFlag in FPyFlags, 1, 0); + PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.use_environment])^ := + IfThen(pfIgnoreEnvironmentFlag 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; + + if PWSL^.length > 0 then + PInteger(PByte(@Config) + ConfigOffests[MinorVersion, + TConfigFields.module_search_paths_set])^ := 1; + end; + var - _path : PPyObject; + Config: PyConfig; + Status: PyStatus; begin - _path := PySys_GetObject('path'); - if Assigned(FOnSysPathInit) then - FOnSysPathInit(Self, _path); + // Fills Config with zeros and then sets some default values + if pfIsolated in FPyFlags then + PyConfig_InitIsolatedConfig(Config) + else + 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 FVenvPythonExe <> '' then + PyConfig_SetString(Config, + PPWcharT(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.executable]), + PWCharT(StringToWCharTString(FVenvPythonExe))); + + // 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; - procedure SetPythonPath(var Config: PyConfig); + procedure ConfgigPEP741(var ErrMsg: string); + // Initialize according to PEP587 available since python 3.8 + + procedure AssignPyFlags(Config: PPyInitConfig); + begin + 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, 'user_site_directory', IfThen(pfNoSite in FPyFlags, 0, 1)); + PyInitConfig_SetInt(Config, 'pathconfig_warnings', IfThen(pfFrozenFlag in FPyFlags, 1, 0)); + PyInitConfig_SetInt(Config, 'use_environment', IfThen(pfIgnoreEnvironmentFlag 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 - Paths: TStringDynArray; - I: Integer; - PWSL: PPyWideStringList; + Config: PPyInitConfig; + PErrMsg: PAnsiChar; begin - if FPythonPath = '' then Exit; + Config := PyInitConfig_Create; + try + PyInitConfig_SetInt(Config, 'isolated', IfThen(pfIsolated in FPyFlags, 1, 0)); - 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]))); + 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 FVenvPythonExe <> '' then + PyInitConfig_SetStr(Config, 'executable', PAnsiChar(EncodeString(FPythonHome))); + + // 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; - if PWSL^.length > 0 then - PInteger(PByte(@Config) + ConfigOffests[MinorVersion, - TConfigFields.module_search_paths_set])^ := 1; + procedure InitSysPath; + var + _path : PPyObject; + begin + _path := PySys_GetObject('path'); + if Assigned(FOnSysPathInit) then + FOnSysPathInit(Self, _path); end; function GetVal(AModule : PPyObject; AVarName : AnsiString) : PPyObject; @@ -4727,8 +4955,6 @@ procedure TPythonEngine.Initialize; var i : Integer; - Config: PyConfig; - Status: PyStatus; ErrMsg: string; begin if Assigned(gPythonEngine) then @@ -4741,51 +4967,13 @@ procedure TPythonEngine.Initialize; FInitialized := True else begin - // Fills Config with zeros and then sets some default values - if pfIsolated in FPyFlags then - PyConfig_InitIsolatedConfig(Config) + if (MajorVersion > 3) or (MinorVersion >= 14) then + ConfgigPEP741(ErrMsg) else - 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 FVenvPythonExe <> '' then - PyConfig_SetString(Config, - PPWcharT(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.executable]), - PWCharT(StringToWCharTString(FVenvPythonExe))); - - // 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 - finally - PyConfig_Clear(Config); - end; + ConfgigPEP587(ErrMsg); if not FInitialized then begin - if PyStatus_Exception(Status) then - ErrMsg := Format(SPyInitFailed, [string(Status.err_msg)]) - else - ErrMsg := Format(SPyInitFailed, [SPyInitFailedUnknown]); if FatalMsgDlg then {$IFDEF MSWINDOWS} MessageBox( GetActiveWindow, PChar(ErrMsg), 'Error', MB_TASKMODAL or MB_ICONSTOP ); @@ -4860,37 +5048,6 @@ procedure TPythonEngine.Notification( AComponent: TComponent; IO := nil end; -procedure TPythonEngine.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 TPythonEngine.InitWinConsole; begin {$IFDEF MSWINDOWS} From f9ab2dca4978778ca1277ff6265556f579268b4c Mon Sep 17 00:00:00 2001 From: pyscripter Date: Tue, 10 Dec 2024 02:00:45 +0200 Subject: [PATCH 02/17] Merged downstream from embarcadero/python4Delphi --- Packages/Delphi/Delphi 10.4+/Python.dproj | 25 +- Packages/Delphi/Delphi 10.4+/PythonFmx.dproj | 26 +- .../Delphi/Delphi 10.4+/PythonFmxLinux.dpk | 63 -- .../Delphi/Delphi 10.4+/PythonFmxLinux.dproj | 968 ------------------ Packages/Delphi/Delphi 10.4+/PythonVcl.dproj | 8 +- Packages/Delphi/Delphi 10.4+/dclPython.dproj | 4 +- .../Delphi/Delphi 10.4+/dclPythonFmx.dproj | 4 +- .../Delphi/Delphi 10.4+/dclPythonVcl.dproj | 4 +- .../Delphi/P4DLinuxComponentSuite.groupproj | 108 -- Source/PythonEngine.pas | 14 +- Source/fmx/WrapDelphiFmx.pas | 2 - 11 files changed, 59 insertions(+), 1167 deletions(-) delete mode 100644 Packages/Delphi/Delphi 10.4+/PythonFmxLinux.dpk delete mode 100644 Packages/Delphi/Delphi 10.4+/PythonFmxLinux.dproj delete mode 100644 Packages/Delphi/P4DLinuxComponentSuite.groupproj 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/PythonEngine.pas b/Source/PythonEngine.pas index 93cfa6d2..6102ed35 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -1953,16 +1953,20 @@ TPythonInterface=class(TDynamicDll) //-------------------------------------------------------- type TDatetimeConversionMode = (dcmToTuple, dcmToDatetime); + TPythonFlag = (pfDebug, pfInteractive, pfNoSite, pfOptimize, pfVerbose, + pfFrozenFlag, pfIgnoreEnvironmentFlag, + pfDontWriteBytecodeFlag, pfIsolated); + TPythonFlags = set of TPythonFlag; + const DEFAULT_DATETIME_CONVERSION_MODE = dcmToTuple; + DEFAULT_FLAGS = {$IFDEF IOS}[pfIsolated, pfDontWriteBytecodeFlag]{$ELSE}[]{$ENDIF IOS}; + type TEngineClient = class; 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; - TPythonFlag = (pfDebug, pfInteractive, pfNoSite, pfOptimize, pfVerbose, - pfFrozenFlag, pfIgnoreEnvironmentFlag, pfIsolated); - TPythonFlags = set of TPythonFlag; TTracebackItem = class @@ -2153,7 +2157,7 @@ TPythonEngine = class(TPythonInterface) property DatetimeConversionMode: TDatetimeConversionMode read FDatetimeConversionMode write FDatetimeConversionMode default DEFAULT_DATETIME_CONVERSION_MODE; property InitScript: TStrings read FInitScript write SetInitScript; 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 OnAfterInit: TNotifyEvent read FOnAfterInit write FOnAfterInit; @@ -4545,7 +4549,7 @@ constructor TPythonEngine.Create(AOwner: TComponent); FAutoFinalize := True; FTraceback := TPythonTraceback.Create; FUseWindowsConsole := False; - FPyFlags := []; + FPyFlags := DEFAULT_FLAGS; FDatetimeConversionMode := DEFAULT_DATETIME_CONVERSION_MODE; if csDesigning in ComponentState then begin 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, From 29aafb1ffde4c16d090c483ad7a25ca04ee1aad9 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Tue, 10 Dec 2024 02:08:08 +0200 Subject: [PATCH 03/17] Renamed VENVPythonExe to PythonExecutable --- Source/PythonEngine.pas | 12 ++++++------ Source/PythonVersions.pas | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 6102ed35..72a91647 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -2003,7 +2003,7 @@ TPythonType = class; //forward declaration {$IFEND} TPythonEngine = class(TPythonInterface) private - FVenvPythonExe: string; + FPythonExecutable: string; FInitScript: TStrings; FIO: TPythonInputOutput; FRedirectIO: Boolean; @@ -2153,7 +2153,7 @@ TPythonEngine = class(TPythonInterface) 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 IO: TPythonInputOutput read FIO write SetIO; @@ -4760,10 +4760,10 @@ procedure TPythonEngine.Initialize; PPWcharT(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.home]), PWCharT(StringToWCharTString(FPythonHome))); // Set venv executable if available - if FVenvPythonExe <> '' then + if FPythonExecutable <> '' then PyConfig_SetString(Config, PPWcharT(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.executable]), - PWCharT(StringToWCharTString(FVenvPythonExe))); + PWCharT(StringToWCharTString(FPythonExecutable))); // Set program arguments (sys.argv) SetProgramArgs(Config); @@ -4872,8 +4872,8 @@ procedure TPythonEngine.Initialize; if FPythonHome <> '' then PyInitConfig_SetStr(Config, 'home', PAnsiChar(EncodeString(FPythonHome))); // Set venv executable if available - if FVenvPythonExe <> '' then - PyInitConfig_SetStr(Config, 'executable', PAnsiChar(EncodeString(FPythonHome))); + if FPythonExecutable <> '' then + PyInitConfig_SetStr(Config, 'executable', PAnsiChar(EncodeString(FPythonExecutable))); // Set program arguments (sys.argv) SetProgramArgs(Config); diff --git a/Source/PythonVersions.pas b/Source/PythonVersions.pas index 569ba52f..71d38a84 100644 --- a/Source/PythonVersions.pas +++ b/Source/PythonVersions.pas @@ -127,7 +127,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 { From 4025534d9bcbda7e7af691b154bb706290e731dc Mon Sep 17 00:00:00 2001 From: pyscripter Date: Tue, 10 Dec 2024 02:46:24 +0200 Subject: [PATCH 04/17] Consistent naming of python flags --- Source/PythonEngine.pas | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 72a91647..9aad17bd 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -1954,13 +1954,19 @@ TPythonInterface=class(TDynamicDll) type TDatetimeConversionMode = (dcmToTuple, dcmToDatetime); TPythonFlag = (pfDebug, pfInteractive, pfNoSite, pfOptimize, pfVerbose, - pfFrozenFlag, pfIgnoreEnvironmentFlag, - pfDontWriteBytecodeFlag, pfIsolated); + pfFrozen, pfIgnoreEnvironment, pfNoUserSiteDirectory, + pfDontWriteBytecode, pfIsolated); TPythonFlags = set of TPythonFlag; const DEFAULT_DATETIME_CONVERSION_MODE = dcmToTuple; - DEFAULT_FLAGS = {$IFDEF IOS}[pfIsolated, pfDontWriteBytecodeFlag]{$ELSE}[]{$ENDIF IOS}; + DEFAULT_FLAGS = + {$IFDEF IOS} + [pfIsolated, pfNoUserSiteDirectory, pfIgnoreEnvironment, + pfDontWriteBytecodeFlag] + {$ELSE} + [] + {$ENDIF IOS}; type TEngineClient = class; @@ -4679,9 +4685,9 @@ procedure TPythonEngine.Initialize; PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.site_import])^ := IfThen(pfNoSite in FPyFlags, 0, 1); PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.pathconfig_warnings])^ := - IfThen(pfFrozenFlag in FPyFlags, 1, 0); + IfThen(pfFrozen in FPyFlags, 1, 0); PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.use_environment])^ := - IfThen(pfIgnoreEnvironmentFlag in FPyFlags, 0, 1); + IfThen(pfIgnoreEnvironment in FPyFlags, 0, 1); end; procedure SetProgramArgs(var Config: PyConfig); @@ -4793,14 +4799,16 @@ 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, 'user_site_directory', IfThen(pfNoSite in FPyFlags, 0, 1)); - PyInitConfig_SetInt(Config, 'pathconfig_warnings', IfThen(pfFrozenFlag in FPyFlags, 1, 0)); - PyInitConfig_SetInt(Config, 'use_environment', IfThen(pfIgnoreEnvironmentFlag 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); @@ -4862,8 +4870,6 @@ procedure TPythonEngine.Initialize; begin Config := PyInitConfig_Create; try - PyInitConfig_SetInt(Config, 'isolated', IfThen(pfIsolated in FPyFlags, 1, 0)); - AssignPyFlags(Config); // Set programname and pythonhome if available From 7b9ada223b5779e8739591d25e15eda3c69df952 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Tue, 10 Dec 2024 03:15:44 +0200 Subject: [PATCH 05/17] ob_refcnt should be unsigned integer (NativeUInt) --- Demos/Demo06/Unit1.pas | 2 +- Demos/Demo07/Unit1.pas | 2 +- Demos/FPC/Demo06/Unit1.pas | 2 +- Source/PythonEngine.pas | 46 +++++++++++++++++++------------------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Demos/Demo06/Unit1.pas b/Demos/Demo06/Unit1.pas index e038b4fa..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; diff --git a/Demos/Demo07/Unit1.pas b/Demos/Demo07/Unit1.pas index f33b8817..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; 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/Source/PythonEngine.pas b/Source/PythonEngine.pas index 9aad17bd..f579a420 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -474,7 +474,7 @@ TPythonVersionProp = record end; PyObject = {$IFDEF CPUX86}packed{$ENDIF} record - ob_refcnt: NativeInt; + ob_refcnt: NativeUInt; ob_type: PPyTypeObject; end; @@ -485,7 +485,7 @@ TPythonVersionProp = record end; PySliceObject = {$IFDEF CPUX86}packed{$ENDIF} record - ob_refcnt: NativeInt; + ob_refcnt: NativeUInt; ob_type: PPyTypeObject; start, stop, step: PPyObject; end; @@ -544,7 +544,7 @@ TPythonVersionProp = record 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; @@ -555,7 +555,7 @@ TPythonVersionProp = record 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; @@ -568,7 +568,7 @@ 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; @@ -581,7 +581,7 @@ 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; @@ -594,7 +594,7 @@ 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; @@ -607,7 +607,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; @@ -667,7 +667,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 @@ -814,7 +814,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 @@ -826,7 +826,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; @@ -849,7 +849,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; @@ -873,7 +873,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; @@ -888,7 +888,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; @@ -910,7 +910,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; @@ -929,7 +929,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; @@ -943,7 +943,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; @@ -958,7 +958,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; @@ -2576,9 +2576,9 @@ TPythonModule = class(TMethodsContainer) // 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; @@ -2599,7 +2599,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 @@ -7816,7 +7816,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; @@ -7826,7 +7826,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; From abbaeee55759277aa5c867a82dea1d1aad52935f Mon Sep 17 00:00:00 2001 From: pyscripter Date: Fri, 13 Dec 2024 18:12:04 +0200 Subject: [PATCH 06/17] Detect free-threaded python presence. --- Source/PythonVersions.pas | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Source/PythonVersions.pas b/Source/PythonVersions.pas index 71d38a84..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; @@ -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; From a1471e2b98cad83bb05a693373e6dc8496505fff Mon Sep 17 00:00:00 2001 From: pyscripter Date: Tue, 17 Dec 2024 01:55:40 +0200 Subject: [PATCH 07/17] Fix spelling --- Source/PythonEngine.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index f579a420..27c510a3 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -4436,7 +4436,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); From eac8094f7211dc88791bf7e3ce7014e95a47afe9 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sun, 29 Dec 2024 01:07:50 +0200 Subject: [PATCH 08/17] Refactored error messages as resource strings --- Source/PythonEngine.pas | 193 ++++++++++++++++++++++++++-------------- 1 file changed, 124 insertions(+), 69 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 27c510a3..18928cfa 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -3072,6 +3072,59 @@ implementation 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'; (*******************************************************) (** **) @@ -3423,7 +3476,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} @@ -3471,7 +3524,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]); @@ -3566,7 +3619,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; @@ -3619,7 +3672,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; @@ -3692,7 +3745,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'; @@ -3713,13 +3766,13 @@ 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; @@ -4562,7 +4615,7 @@ constructor TPythonEngine.Create(AOwner: TComponent); 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; @@ -4968,7 +5021,7 @@ procedure TPythonEngine.Initialize; ErrMsg: string; begin if Assigned(gPythonEngine) then - raise Exception.Create('There is already one instance of TPythonEngine running' ); + raise Exception.Create(SMoreThanOnePythonEngine); gPythonEngine := Self; @@ -5085,7 +5138,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; @@ -5103,7 +5156,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; @@ -5115,7 +5168,7 @@ 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; @@ -5256,7 +5309,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 @@ -5600,7 +5653,7 @@ 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; @@ -5734,7 +5787,7 @@ 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; @@ -5749,7 +5802,7 @@ function TPythonEngine.ModuleByName( const aModuleName : AnsiString ) : PPyObj 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; @@ -5764,7 +5817,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; @@ -5884,7 +5937,7 @@ 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 := PyObject_Call(FPyDateTime_DateTimeType, args, nil); @@ -5894,7 +5947,7 @@ function TPythonEngine.VariantAsPyObject( const V : Variant ) : PPyObject; end; end else - raise EPythonError.Create('Invalid DatetimeConversionMode'); + raise EPythonError.Create(SInvalidDateTimeConvMode); end; varOleStr: begin @@ -5922,7 +5975,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 @@ -5948,7 +6001,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; @@ -6138,7 +6191,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; @@ -6151,7 +6204,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] ); @@ -6168,7 +6221,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] ); @@ -6182,7 +6235,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; @@ -6193,7 +6246,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; @@ -6249,7 +6302,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; @@ -6259,10 +6312,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 @@ -6287,7 +6340,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])); @@ -6299,7 +6352,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])); @@ -6311,7 +6364,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 @@ -6323,7 +6376,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 ) ) ); @@ -6725,7 +6778,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; @@ -6871,7 +6924,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; @@ -7004,7 +7057,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 @@ -7014,9 +7067,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; @@ -7067,7 +7120,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; @@ -7144,7 +7197,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; @@ -7181,7 +7234,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 ); @@ -7199,8 +7253,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; @@ -7310,13 +7364,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; @@ -7327,7 +7381,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; @@ -7347,7 +7401,7 @@ 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); @@ -7373,18 +7427,18 @@ procedure TError.RaiseErrorObj(const msg : AnsiString; obj : PPyObject); begin 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 := 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 @@ -7400,7 +7454,7 @@ procedure TError.RaiseErrorObj(const msg : AnsiString; obj : PPyObject); Py_XDECREF(keys); end else - raise Exception.Create('TError.RaiseErrorObj: I didn''t get an instance' ); + raise Exception.Create(STErrorNoInstance); PyErr_SetObject(Error, res); Py_XDECREF(res); end @@ -7600,7 +7654,7 @@ 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; procedure TPythonModule.RaiseError( const error, msg : AnsiString ); @@ -7652,10 +7706,10 @@ procedure TPythonModule.SetVar( const varName : AnsiString; value : PPyObject ); 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] ); + 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, @@ -7669,7 +7723,7 @@ function TPythonModule.GetVar( const varName : AnsiString ) : PPyObject; 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 ); @@ -7680,11 +7734,12 @@ procedure TPythonModule.DeleteVar( const varName : AnsiString ); with Engine do begin dict := PyModule_GetDict( Module ); - if not Assigned(dict) then raise EPythonError.CreateFmt( 'Can''t get __dict__ of module "%s"', [ModuleName] ); + 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; @@ -8252,7 +8307,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; @@ -9103,7 +9158,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'); @@ -9117,7 +9172,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 ); @@ -9126,7 +9181,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 ! @@ -9136,7 +9191,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 ); @@ -9145,7 +9200,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; @@ -9198,7 +9253,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 @@ -9490,7 +9545,7 @@ procedure TPythonThread.Execute; PyThreadState_Swap(global_state); PyGILState_Release(gilstate); end else - raise EPythonError.Create('Could not create a new thread state'); + raise EPythonError.Create(SCannotCreateThreadState); end; end; end; @@ -9698,9 +9753,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; @@ -10053,7 +10108,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 From 189fb29322bdd95b492468cde0141368024ccdca Mon Sep 17 00:00:00 2001 From: pyscripter Date: Tue, 7 Jan 2025 13:20:47 +0200 Subject: [PATCH 09/17] Fix #493 --- Source/PythonEngine.pas | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 18928cfa..dd43d6eb 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -538,7 +538,8 @@ TPythonVersionProp = record {#define PyDescr_COMMON \ PyObject_HEAD \ PyTypeObject *d_type; \ - PyObject *d_name + PyObject *d_name \ + PyObject *d_qualname } PPyDescrObject = ^PyDescrObject; @@ -549,6 +550,7 @@ TPythonVersionProp = record // End of the Head of an object d_type : PPyTypeObject; d_name : PPyObject; + d_qualname : PPyObject; end; PPyMethodDescrObject = ^PyMethodDescrObject; @@ -560,6 +562,7 @@ TPythonVersionProp = record // End of the Head of an object d_type : PPyTypeObject; d_name : PPyObject; + d_qualname : PPyObject; // End of PyDescr_COMMON d_method : PPyMethodDef; end; @@ -573,6 +576,7 @@ TPythonVersionProp = record // End of the Head of an object d_type : PPyTypeObject; d_name : PPyObject; + d_qualname : PPyObject; // End of PyDescr_COMMON d_member : PPyMemberDef; end; @@ -586,6 +590,7 @@ TPythonVersionProp = record // End of the Head of an object d_type : PPyTypeObject; d_name : PPyObject; + d_qualname : PPyObject; // End of PyDescr_COMMON d_getset : PPyGetSetDef; end; @@ -599,6 +604,7 @@ TPythonVersionProp = record // 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 @@ -1513,6 +1519,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; @@ -3859,6 +3866,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'); From 4c42c6c636d97a9e72b012f3ec1338be2f547fbc Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sat, 8 Mar 2025 00:54:27 +0200 Subject: [PATCH 10/17] Fix #495 --- Source/PythonEngine.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index dd43d6eb..ec974172 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -1034,7 +1034,7 @@ PyConfig = record {$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, 232, 240, 256, 272, 280, 296), + (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)); @@ -4730,7 +4730,7 @@ procedure TPythonEngine.DoOpenDll(const aDllName : string); procedure TPythonEngine.Initialize; - procedure ConfgigPEP587(var ErrMsg: string); + procedure ConfigPEP587(var ErrMsg: string); // Initialize according to PEP587 available since python 3.8 procedure AssignPyFlags(var Config: PyConfig); @@ -4855,7 +4855,7 @@ procedure TPythonEngine.Initialize; end; end; - procedure ConfgigPEP741(var ErrMsg: string); + procedure ConfigPEP741(var ErrMsg: string); // Initialize according to PEP587 available since python 3.8 procedure AssignPyFlags(Config: PPyInitConfig); @@ -5039,9 +5039,9 @@ procedure TPythonEngine.Initialize; else begin if (MajorVersion > 3) or (MinorVersion >= 14) then - ConfgigPEP741(ErrMsg) + ConfigPEP741(ErrMsg) else - ConfgigPEP587(ErrMsg); + ConfigPEP587(ErrMsg); if not FInitialized then begin From e0164565660d44ca623cb08eccf2d5aa5ff8fa90 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Wed, 9 Apr 2025 17:28:47 +0300 Subject: [PATCH 11/17] Added PyLong_AsVoidPtr --- Source/PythonEngine.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index ec974172..ff16be8d 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -1649,6 +1649,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; PyLong_FromVoidPtr:function(p: Pointer): PPyObject; cdecl; PyMapping_Check:function (ob:PPyObject):integer; cdecl; PyMapping_GetItemString:function (ob:PPyObject;key:PAnsiChar):PPyObject; cdecl; @@ -3984,6 +3985,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'); From 83f6b5ee3e24d35a27c73bb3fbe433a78a391d15 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Thu, 10 Apr 2025 05:23:15 +0300 Subject: [PATCH 12/17] Handle Pointer fields, properties and parameters - stored as python integers. --- Source/PythonEngine.pas | 2 +- Source/WrapDelphi.pas | 32 ++++++++++++++++++++++---------- Tests/WrapDelphiTest.pas | 9 +++++++++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index ff16be8d..c15fbf48 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -1649,7 +1649,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; + 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; diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index bed385ea..a19bc718 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -1042,7 +1042,7 @@ implementation rs_ExpectedNil = 'In static methods Self should be nil'; rs_ExpectedInterface = 'Expected a Pascal interface'; rs_ExpectedSequence = 'Expected a python sequence'; - rsExpectedPPyObject = 'Expected a PPyObject'; + 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 '+ @@ -2188,12 +2188,16 @@ function ValidateDynArray(PyValue: PPyObject; const RttiType: TRttiType; end; end; -function ValidatePPyObject(PyValue: PPyObject; const RttiType: TRttiType; +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; @@ -2201,10 +2205,21 @@ function ValidatePPyObject(PyValue: PPyObject; const RttiType: TRttiType; 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 := rsExpectedPPyObject; + ErrMsg := rsExpectedPointer; end; function PyObjectToTValue(PyArg: PPyObject; ArgType: TRttiType; @@ -2238,7 +2253,7 @@ function PyObjectToTValue(PyArg: PPyObject; ArgType: TRttiType; tkDynArray: Result := ValidateDynArray(PyArg, ArgType, Arg, ErrMsg); tkPointer: - Result := ValidatePPyObject(PyArg, ArgType, Arg, ErrMsg); + Result := ValidatePointer(PyArg, ArgType, Arg, ErrMsg); else Result := SimplePythonToValue(PyArg, ArgType.Handle, Arg, ErrMsg); end; @@ -2277,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); @@ -2288,13 +2303,10 @@ function TValueToPyObject(const Value: TValue; tkArray, tkDynArray: Result := DynArrayToPython(Value, DelphiWrapper, ErrMsg); tkPointer: - if Value.IsType then + if Value.TypeInfo = TypeInfo(PPyObject) then Result := Value.AsType else - begin - Result := nil; - ErrMsg := rs_ErrValueToPython; - end; + Result := DelphiWrapper.Engine.PyLong_FromVoidPtr(Value.AsType); else Result := SimpleValueToPython(Value, ErrMsg); end; diff --git a/Tests/WrapDelphiTest.pas b/Tests/WrapDelphiTest.pas index 350b0bb2..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); @@ -160,6 +161,8 @@ TTestWrapDelphi = class(TObject) procedure TestVarArgs; [Test] procedure TestPPyObjects; + [Test] + procedure TestPointers; end; implementation @@ -439,6 +442,12 @@ procedure TTestWrapDelphi.TestPPyObjects; 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'; From 92717b84a747285b5cb932f71ec454317329239d Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sun, 13 Apr 2025 02:15:28 +0300 Subject: [PATCH 13/17] Fix #497 --- Source/VarPyth.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VarPyth.pas b/Source/VarPyth.pas index b16f91b8..52607cf0 100644 --- a/Source/VarPyth.pas +++ b/Source/VarPyth.pas @@ -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 From 179b7a666d3b2d765b0014681e2cc757097e1876 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Thu, 1 May 2025 16:15:52 +0300 Subject: [PATCH 14/17] Made python code compatible with recent versions of numpy and matplotlib. --- Tutorials/Webinar II/VizDemo/MainFormSVG.dfm | 42 +++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) 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 From 8b4a78f5b6d62822db65fae543b61ce99a208007 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sat, 21 Jun 2025 23:17:48 +0300 Subject: [PATCH 15/17] EPySystemExit was not fully specified. --- Source/PythonEngine.pas | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index c15fbf48..422146b0 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -5570,9 +5570,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 ) @@ -6606,6 +6604,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); @@ -6614,7 +6613,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 From 20dfc9afa298bc7071eea13206e8ec1dc68db7ff Mon Sep 17 00:00:00 2001 From: pyscripter Date: Wed, 9 Jul 2025 05:15:52 +0300 Subject: [PATCH 16/17] Fix #504 Import stuff needed for Multi-phase module initialization --- Source/PythonEngine.pas | 67 ++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 422146b0..9e149a8c 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -344,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 ## @@ -643,6 +657,10 @@ TPythonVersionProp = record 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; @@ -1541,6 +1559,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; @@ -2173,7 +2194,7 @@ TPythonEngine = class(TPythonInterface) property IO: TPythonInputOutput read FIO write SetIO; 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 OnSysPathInit: TSysPathInitEvent read FOnSysPathInit write FOnSysPathInit; property OnConfigInit: TConfigInitEvent read FOnConfigInit write FOnConfigInit; @@ -2534,12 +2555,6 @@ TPythonModule = class(TMethodsContainer) end; -//------------------------------------------------------- -//-- -- -//--class: TPythonType derived from TGetSetContainer -- -//-- -- -//------------------------------------------------------- - { A B C +-------------------++------------------------------------------------------+ @@ -2556,15 +2571,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: @@ -2581,7 +2596,6 @@ 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: NativeUInt; @@ -2751,6 +2765,13 @@ TTypeServices = class(TPersistent) property Mapping : TMappingServices read FMapping write FMapping; end; +//------------------------------------------------------- +//-- -- +//--class: TPythonType derived from TGetSetContainer -- +//-- -- +//------------------------------------------------------- + + // The base class of all new Python types // The component that initializes the Python type and // that creates instances of itself. {$IF not Defined(FPC) and (CompilerVersion >= 23)} @@ -3901,6 +3922,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'); @@ -5072,6 +5096,19 @@ procedure TPythonEngine.Initialize; if not Initialized then Initialize; + + {$IFDEF MSWINDOWS} + 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 @@ -5127,10 +5164,12 @@ procedure TPythonEngine.InitWinConsole; 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 From 0258b8fbeae063a9b81607b779471bfe0c163796 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Wed, 9 Jul 2025 14:55:43 +0300 Subject: [PATCH 17/17] Minor changes clarifying comments. --- Source/PythonEngine.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 9e149a8c..11ad3803 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -2771,9 +2771,9 @@ TTypeServices = class(TPersistent) //-- -- //------------------------------------------------------- + // The component that initializes a Python type and + // creates instances of itself. // The base class of all new Python types - // The component that initializes the Python type and - // that creates instances of itself. {$IF not Defined(FPC) and (CompilerVersion >= 23)} [ComponentPlatformsAttribute(pidSupportedPlatforms)] {$IFEND} @@ -5096,8 +5096,8 @@ procedure TPythonEngine.Initialize; if not Initialized then Initialize; - {$IFDEF MSWINDOWS} + // fix #504 if not FRedirectIO and UseWindowsConsole then PyRun_SimpleString( 'import sys, io'#10 +