From 9d4a980e3f6985a6d89fcfc03ef4b4898b098901 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Mon, 1 Apr 2024 16:53:13 +0300 Subject: [PATCH 01/55] Implement PEP587 Python Initialzation Configuration. (necessary for python 3.13 support) Support python 3.13 (incomplete) Drop support for python for python 3.3-3.7 (do not contain support for PEP587) --- Source/PythonEngine.pas | 261 ++++++++++++++++++++++++++-------------- 1 file changed, 174 insertions(+), 87 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 7bd52c93..b124f59d 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -73,59 +73,47 @@ TPythonVersionProp = record end; const {$IFDEF MSWINDOWS} - PYTHON_KNOWN_VERSIONS: array[1..10] of TPythonVersionProp = + PYTHON_KNOWN_VERSIONS: array[1..6] of TPythonVersionProp = ( - (DllName: 'python33.dll'; RegVersion: '3.3'; APIVersion: 1013), - (DllName: 'python34.dll'; RegVersion: '3.4'; APIVersion: 1013), - (DllName: 'python35.dll'; RegVersion: '3.5'; APIVersion: 1013), - (DllName: 'python36.dll'; RegVersion: '3.6'; APIVersion: 1013), - (DllName: 'python37.dll'; RegVersion: '3.7'; APIVersion: 1013), (DllName: 'python38.dll'; RegVersion: '3.8'; APIVersion: 1013), (DllName: 'python39.dll'; RegVersion: '3.9'; APIVersion: 1013), (DllName: 'python310.dll'; RegVersion: '3.10'; APIVersion: 1013), (DllName: 'python311.dll'; RegVersion: '3.11'; APIVersion: 1013), - (DllName: 'python312.dll'; RegVersion: '3.12'; APIVersion: 1013) + (DllName: 'python312.dll'; RegVersion: '3.12'; APIVersion: 1013), + (DllName: 'python313.dll'; RegVersion: '3.13'; APIVersion: 1013) ); {$ENDIF} {$IFDEF _so_files} - PYTHON_KNOWN_VERSIONS: array[1..10] of TPythonVersionProp = + PYTHON_KNOWN_VERSIONS: array[1..6] of TPythonVersionProp = ( - (DllName: 'libpython3.3m.so'; RegVersion: '3.3'; APIVersion: 1013), - (DllName: 'libpython3.4m.so'; RegVersion: '3.4'; APIVersion: 1013), - (DllName: 'libpython3.5m.so'; RegVersion: '3.5'; APIVersion: 1013), - (DllName: 'libpython3.6m.so'; RegVersion: '3.6'; APIVersion: 1013), - (DllName: 'libpython3.7m.so'; RegVersion: '3.7'; APIVersion: 1013), (DllName: 'libpython3.8.so'; RegVersion: '3.8'; APIVersion: 1013), (DllName: 'libpython3.9.so'; RegVersion: '3.9'; APIVersion: 1013), (DllName: 'libpython3.10.so'; RegVersion: '3.10'; APIVersion: 1013), (DllName: 'libpython3.11.so'; RegVersion: '3.11'; APIVersion: 1013), - (DllName: 'libpython3.12.so'; RegVersion: '3.12'; APIVersion: 1013) + (DllName: 'libpython3.12.so'; RegVersion: '3.12'; APIVersion: 1013), + (DllName: 'libpython3.13.so'; RegVersion: '3.13'; APIVersion: 1013) ); {$ENDIF} {$IFDEF DARWIN} - PYTHON_KNOWN_VERSIONS: array[1..10] of TPythonVersionProp = + PYTHON_KNOWN_VERSIONS: array[1..6] of TPythonVersionProp = ( - (DllName: 'libpython3.3.dylib'; RegVersion: '3.3'; APIVersion: 1013), - (DllName: 'libpython3.4.dylib'; RegVersion: '3.4'; APIVersion: 1013), - (DllName: 'libpython3.5.dylib'; RegVersion: '3.5'; APIVersion: 1013), - (DllName: 'libpython3.6.dylib'; RegVersion: '3.6'; APIVersion: 1013), - (DllName: 'libpython3.7.dylib'; RegVersion: '3.7'; APIVersion: 1013), (DllName: 'libpython3.8.dylib'; RegVersion: '3.8'; APIVersion: 1013), (DllName: 'libpython3.9.dylib'; RegVersion: '3.9'; APIVersion: 1013), (DllName: 'libpython3.10.dylib'; RegVersion: '3.10'; APIVersion: 1013), (DllName: 'libpython3.11.dylib'; RegVersion: '3.11'; APIVersion: 1013), - (DllName: 'libpython3.12.dylib'; RegVersion: '3.12'; APIVersion: 1013) + (DllName: 'libpython3.12.dylib'; RegVersion: '3.12'; APIVersion: 1013), + (DllName: 'libpython3.13.dylib'; RegVersion: '3.13'; APIVersion: 1013) ); {$ENDIF} {$IFDEF ANDROID} - PYTHON_KNOWN_VERSIONS: array[5..10] of TPythonVersionProp = + PYTHON_KNOWN_VERSIONS: array[1..6] of TPythonVersionProp = ( - (DllName: 'libpython3.7m.so'; RegVersion: '3.7'; APIVersion: 1013), (DllName: 'libpython3.8.so'; RegVersion: '3.8'; APIVersion: 1013), (DllName: 'libpython3.9.so'; RegVersion: '3.9'; APIVersion: 1013), (DllName: 'libpython3.10.so'; RegVersion: '3.10'; APIVersion: 1013), (DllName: 'libpython3.11.so'; RegVersion: '3.11'; APIVersion: 1013), (DllName: 'libpython3.12.so'; RegVersion: '3.12'; APIVersion: 1013) + (DllName: 'libpython3.13.so'; RegVersion: '3.13'; APIVersion: 1013) ); {$ENDIF} @@ -966,6 +954,7 @@ PyBufferProcs = record end; //initconfig.h + //See https://docs.python.org/3/c-api/init_config.html const _PyStatus_TYPE_OK = 0; @@ -982,6 +971,92 @@ PyBufferProcs = record exitcode: Integer; end; + PPyWideStringList = ^PyWideStringList; + PyWideStringList = {$IFDEF CPUX86}packed{$ENDIF} record + length: Py_ssize_t; + items: PPWCharT; + end; + + PPyConfig = ^PyConfig; + PyConfig = record + _config_init: Integer; + isolated: Integer; + use_environment: Integer; + dev_mode: Integer; + install_signal_handlers: Integer; + use_hash_seed: Integer; + hash_seed: C_ULong; + faulthandler: Integer; + tracemalloc: Integer; + perf_profiling: Integer; + import_time: Integer; + code_debug_ranges: Integer; + show_ref_count: Integer; + dump_refs: Integer; + dump_refs_file: PWCharT; + malloc_stats: Integer; + filesystem_encoding: PWCharT; + filesystem_errors: PWCharT; + pycache_prefix: PWCharT; + parse_argv: Integer; + orig_argv: PyWideStringList; + argv: PyWideStringList; + xoptions: PyWideStringList; + warnoptions: PyWideStringList ; + site_import: Integer; + bytes_warning: Integer; + warn_default_encoding: Integer; + inspect: Integer; + interactive: Integer; + optimization_level: Integer; + parser_debug: Integer; + write_bytecode: Integer; + verbose: Integer; + quiet: Integer; + user_site_directory: Integer; + configure_c_stdio: Integer; + buffered_stdio: Integer; + stdio_encoding: PWCharT; + stdio_errors: PWCharT; + {$IFDEF MSWINDOWS} + legacy_windows_stdio: Integer; + {$ENDIF} + check_hash_pycs_mode: PWCharT; + use_frozen_modules: Integer; + safe_path: Integer; + int_max_str_digits: Integer; + + (* --- Path configuration inputs ------------ *) + pathconfig_warnings: Integer; + program_name: PWCharT; + pythonpath_env: PWCharT; + home: PWCharT; + platlibdir: PWCharT; + + (* --- Path configuration outputs ----------- *) + module_search_paths_set: Integer; + module_search_paths: PyWideStringList; + stdlib_dir: PWCharT; + executable: PWCharT; + base_executable: PWCharT; + prefix: PWCharT; + base_prefix: PWCharT; + exec_prefix: PWCharT; + base_exec_prefix: PWCharT; + + (* --- Parameter only used by Py_Main() ---------- *) + kip_source_first_line: Integer; + un_command: PWCharT; + un_module: PWCharT; + un_filename: PWCharT; + + (* --- Private fields ---------------------------- *) + install_importlib: Integer; + init_main: Integer; + is_python_build: Integer; +end; + + //####################################################### //## ## //## GIL related ## @@ -1355,15 +1430,6 @@ TPythonInterface=class(TDynamicDll) procedure CheckPython; public - // define Python flags. See file pyDebug.h - Py_DebugFlag: PInteger; - Py_VerboseFlag: PInteger; - Py_InteractiveFlag: PInteger; - Py_OptimizeFlag: PInteger; - Py_NoSiteFlag: PInteger; - Py_FrozenFlag: PInteger; - Py_IgnoreEnvironmentFlag: PInteger; - PyImport_FrozenModules: PP_frozen; Py_None: PPyObject; @@ -1771,6 +1837,18 @@ TPythonInterface=class(TDynamicDll) PyGILState_Ensure : function() : PyGILstate_STATE; cdecl; PyGILState_Release : procedure(gilstate : PyGILState_STATE); cdecl; + // Initialization functions + PyWideStringList_Append : function(var list: PyWideStringList; item: PWCharT): PyStatus; cdecl; + PyWideStringList_Insert : function(var list: PyWideStringList; index: Py_ssize_t; item: PWCharT): PyStatus; cdecl; + PyConfig_InitPythonConfig : procedure(var config: PyConfig); cdecl; + PyConfig_InitIsolatedConfig : procedure(var config: PyConfig); cdecl; + PyConfig_Clear : procedure(var config: PyConfig); cdecl; + PyConfig_SetString : function(var config: PyConfig; config_str: PPWCharT; str: PWCharT): PyStatus; cdecl; + PyConfig_Read : function(var config: PyConfig): PyStatus; cdecl; + PyConfig_SetArgv : function(var config: PyConfig; argc: Py_ssize_t; argv: PPWCharT): PyStatus; cdecl; + PyConfig_SetWideStringList : function(var config: PyConfig; list: PPyWideStringList; length: Py_ssize_t; items: PPWCharT): PyStatus; cdecl; + Py_InitializeFromConfig : function({$IFDEF FPC}constref{$ELSE}[Ref] const{$ENDIF} config: PyConfig): PyStatus; cdecl; + // Not exported in Python 3.8 and implemented as functions - this has been fixed // TODO - deal with the following: // the PyParser_* functions are deprecated in python 3.9 and will be removed in @@ -1887,7 +1965,7 @@ TEngineClient = class; TPathInitializationEvent = procedure ( Sender : TObject; var Path : string ) of Object; TSysPathInitEvent = procedure ( Sender : TObject; PathList : PPyObject ) of Object; TPythonFlag = (pfDebug, pfInteractive, pfNoSite, pfOptimize, pfVerbose, - pfFrozenFlag, pfIgnoreEnvironmentFlag); + pfFrozenFlag, pfIgnoreEnvironmentFlag, pfIsolated); TPythonFlags = set of TPythonFlag; @@ -1974,14 +2052,14 @@ TPythonEngine = class(TPythonInterface) procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure CheckRegistry; - procedure SetProgramArgs; + 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; + procedure AssignPyFlags(var Config: PyConfig); public // Constructors & Destructors @@ -3647,15 +3725,6 @@ procedure TPythonInterface.CheckPython; procedure TPythonInterface.MapDll; begin - Py_DebugFlag := Import('Py_DebugFlag'); - Py_VerboseFlag := Import('Py_VerboseFlag'); - Py_InteractiveFlag := Import('Py_InteractiveFlag'); - Py_OptimizeFlag := Import('Py_OptimizeFlag'); - Py_NoSiteFlag := Import('Py_NoSiteFlag'); - Py_FrozenFlag := Import('Py_FrozenFlag'); - - Py_IgnoreEnvironmentFlag := Import('Py_IgnoreEnvironmentFlag'); - Py_None := Import('_Py_NoneStruct'); Py_Ellipsis := Import('_Py_EllipsisObject'); Py_False := Import('_Py_FalseStruct'); @@ -4060,6 +4129,17 @@ procedure TPythonInterface.MapDll; PyErr_SetInterrupt := Import('PyErr_SetInterrupt'); PyGILState_Ensure := Import('PyGILState_Ensure'); PyGILState_Release := Import('PyGILState_Release'); + + PyWideStringList_Append := Import('PyWideStringList_Append'); + PyWideStringList_Insert := Import('PyWideStringList_Insert'); + PyConfig_InitPythonConfig := Import('PyConfig_InitPythonConfig'); + PyConfig_InitIsolatedConfig := Import('PyConfig_InitIsolatedConfig'); + PyConfig_Clear := Import('PyConfig_Clear'); + PyConfig_SetString := Import('PyConfig_SetString'); + PyConfig_Read := Import('PyConfig_Read'); + PyConfig_SetArgv := Import('PyConfig_SetArgv'); + PyConfig_SetWideStringList := Import('PyConfig_SetWideStringList'); + Py_InitializeFromConfig := Import('Py_InitializeFromConfig'); end; function TPythonInterface.Py_CompileString(str,filename:PAnsiChar;start:integer):PPyObject; @@ -4596,25 +4676,15 @@ procedure TPythonEngine.DoOpenDll(const aDllName : string); end; end; -procedure TPythonEngine.AssignPyFlags; - - procedure SetFlag( AFlag: PInteger; AValue : Boolean ); - begin - if AValue then - AFlag^ := 1 - else - AFlag^ := 0; - end; - +procedure TPythonEngine.AssignPyFlags(var Config: PyConfig); begin - // define each Python flag. See file pyDebug.h - SetFlag(Py_DebugFlag, pfDebug in FPyFlags); - SetFlag(Py_VerboseFlag, pfVerbose in FPyFlags); - SetFlag(Py_InteractiveFlag, pfInteractive in FPyFlags); - SetFlag(Py_OptimizeFlag, pfOptimize in FPyFlags); - SetFlag(Py_NoSiteFlag, pfNoSite in FPyFlags); - SetFlag(Py_FrozenFlag, pfFrozenFlag in FPyFlags); - SetFlag(Py_IgnoreEnvironmentFlag, pfIgnoreEnvironmentFlag in FPyFlags); + Config.parser_debug := IfThen(pfDebug in FPyFlags, 1, 0); + Config.verbose := IfThen(pfVerbose in FPyFlags, 1, 0); + Config.interactive := IfThen(pfInteractive in FPyFlags, 1, 0); + Config.optimization_level := IfThen(pfOptimize in FPyFlags, 1, 0); + Config.site_import := IfThen(pfNoSite in FPyFlags, 0, 1); + Config.pathconfig_warnings := IfThen(pfFrozenFlag in FPyFlags, 1, 0); + Config.use_environment := IfThen(pfIgnoreEnvironmentFlag in FPyFlags, 0, 1); end; procedure TPythonEngine.Initialize; @@ -4689,6 +4759,7 @@ procedure TPythonEngine.Initialize; var i : Integer; + Config: PyConfig; begin if Assigned(gPythonEngine) then raise Exception.Create('There is already one instance of TPythonEngine running' ); @@ -4700,19 +4771,41 @@ procedure TPythonEngine.Initialize; FInitialized := True else begin - CheckRegistry; - if Assigned(Py_SetProgramName) and (Length(FProgramName) > 0) then - Py_SetProgramName(PWCharT(FProgramName)); - AssignPyFlags; - if Length(FPythonHome) > 0 then - Py_SetPythonHome(PWCharT(FPythonHome)); - Py_Initialize; +// CheckRegistry; +// if Assigned(Py_SetProgramName) and (Length(FProgramName) > 0) then +// Py_SetProgramName(PWCharT(FProgramName)); +// AssignPyFlags; +// if Length(FPythonHome) > 0 then +// Py_SetPythonHome(PWCharT(FPythonHome)); +// Py_Initialize; + + // 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 Length(FProgramName) > 0 then + PyConfig_SetString(Config, @Config.program_name, PWCharT(FProgramName)); + if Length(FPythonHome) > 0 then + PyConfig_SetString(Config, @Config.program_name, PWCharT(FPythonHome)); + + // Set program arguments (sys.argv) + SetProgramArgs(Config); + + Py_InitializeFromConfig(Config); + finally + PyConfig_Clear(Config); + end; + if Assigned(Py_IsInitialized) then FInitialized := Py_IsInitialized() <> 0 else FInitialized := True; InitSysPath; - SetProgramArgs; if InitThreads and Assigned(PyEval_InitThreads) then PyEval_InitThreads; if RedirectIO and Assigned(FIO) then @@ -4842,20 +4935,16 @@ procedure TPythonEngine.CheckRegistry; {$ENDIF} end; -procedure TPythonEngine.SetProgramArgs; +procedure TPythonEngine.SetProgramArgs(var Config: PyConfig); var - I, argc : Integer; - wargv : array of PWCharT; - WL : array of WCharTString; + I: Integer; TempS: UnicodeString; + Str: WCharTString; + begin - // we build a string list of the arguments, because ParamStr returns a volatile string - // and we want to build an array of PWCharT, pointing to valid strings. - argc := ParamCount; - SetLength(wargv, argc + 1); - // build the PWCharT array - SetLength(WL, argc+1); - for I := 0 to argc do begin + Config.parse_argv := 0; // do not parse + 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 @@ -4866,14 +4955,12 @@ procedure TPythonEngine.SetProgramArgs; else TempS := ParamStr(I); {$IFDEF POSIX} - WL[I] := UnicodeStringToUCS4String(TempS); + Str := UnicodeStringToUCS4String(TempS); {$ELSE} - WL[I] := UnicodeString(TempS); + Str := TempS; {$ENDIF} - wargv[I] := PWCharT(WL[I]); - end; - // set the argv list of the sys module with the application arguments - PySys_SetArgv( argc + 1, PPWCharT(wargv) ); + PyWideStringList_Append(Config.argv, PWCharT(Str)); + end; end; procedure TPythonEngine.InitWinConsole; From d26ede5cfe71cc80992ebccea6d6d4cb47396379 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Mon, 1 Apr 2024 18:41:12 +0300 Subject: [PATCH 02/55] Set VenvPythonExe using PyConfig PythonHome and ProgramName no longer need to be stored as WCharTString --- Source/PythonEngine.pas | 74 +++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 48 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index b124f59d..3af53848 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -2011,8 +2011,8 @@ TPythonEngine = class(TPythonInterface) FClients: TList; FExecModule: AnsiString; FAutoFinalize: Boolean; - FProgramName: WCharTString; - FPythonHome: WCharTString; + FProgramName: UnicodeString; + FPythonHome: UnicodeString; FPythonPath: WCharTString; FInitThreads: Boolean; FOnPathInitialization: TPathInitializationEvent; @@ -2033,8 +2033,6 @@ TPythonEngine = class(TPythonInterface) FPyDateTime_TZInfoType: PPyObject; FPyDateTime_TimeTZType: PPyObject; FPyDateTime_DateTimeTZType: PPyObject; - function GetPythonHome: UnicodeString; - function GetProgramName: UnicodeString; function GetPythonPath: UnicodeString; procedure SetPythonPath(const Value: UnicodeString); @@ -2074,7 +2072,6 @@ TPythonEngine = class(TPythonInterface) function Run_CommandAsObjectWithDict(const command: AnsiString; mode: Integer; locals, globals: PPyObject; const FileName: string = ''): PPyObject; function EncodeString (const str: UnicodeString): AnsiString; {$IFDEF FPC}overload;{$ENDIF} {$IFDEF FPC} - overload; function EncodeString (const str: AnsiString): AnsiString; overload; {$ENDIF} function EncodeWindowsFilePath(const str: string): AnsiString; @@ -2157,8 +2154,8 @@ TPythonEngine = class(TPythonInterface) property LocalVars : PPyObject read FLocalVars Write SetLocalVars; property GlobalVars : PPyObject read FGlobalVars Write SetGlobalVars; property IOPythonModule: TObject read FIOPythonModule; {TPythonModule} - property PythonHome: UnicodeString read GetPythonHome write SetPythonHome; - property ProgramName: UnicodeString read GetProgramName write SetProgramName; + property PythonHome: UnicodeString read FPythonHome write SetPythonHome; + property ProgramName: UnicodeString read FProgramName write SetProgramName; property PythonPath: UnicodeString read GetPythonPath write SetPythonPath; published property AutoFinalize: Boolean read FAutoFinalize write FAutoFinalize default True; @@ -2992,6 +2989,7 @@ procedure PythonVersionFromDLLName(LibName: string; out MajorVersion, MinorVersi function PythonVersionFromRegVersion(const ARegVersion: string; out AMajorVersion, AMinorVersion: integer): boolean; function PyStatus_Exception(const APyStatus: PyStatus): Boolean; +function StringToWCharTString(Str: string): WcharTString; //####################################################### //## ## @@ -4692,19 +4690,7 @@ procedure TPythonEngine.Initialize; procedure InitSysPath; var _path : PPyObject; - const Script = - 'import sys' + sLineBreak + - 'sys.executable = r"%s"' + sLineBreak + - 'path = sys.path' + sLineBreak + - 'for i in range(len(path)-1, -1, -1):' + sLineBreak + - ' if path[i].find("site-packages") > 0:' + sLineBreak + - ' path.pop(i)' + sLineBreak + - 'import site' + sLineBreak + - 'site.main()' + sLineBreak + - 'del sys, path, i, site'; begin - if VenvPythonExe <> '' then - ExecString(AnsiString(Format(Script, [VenvPythonExe]))); _path := PySys_GetObject('path'); if Assigned(FOnSysPathInit) then FOnSysPathInit(Self, _path); @@ -4788,11 +4774,18 @@ procedure TPythonEngine.Initialize; AssignPyFlags(Config); // Set programname and pythonhome if available - if Length(FProgramName) > 0 then - PyConfig_SetString(Config, @Config.program_name, PWCharT(FProgramName)); - if Length(FPythonHome) > 0 then - PyConfig_SetString(Config, @Config.program_name, PWCharT(FPythonHome)); - + if FProgramName <> '' then + PyConfig_SetString(Config, @Config.program_name, + PWCharT(StringToWCharTString(FProgramName))); + if FPythonHome <> '' then + PyConfig_SetString(Config, @Config.program_name, + PWCharT(StringToWCharTString(FPythonHome))); + // Set venv executable if available + if FVenvPythonExe <> '' then + PyConfig_SetString(Config, @Config.program_name, + PWCharT(StringToWCharTString(FVenvPythonExe))); + + PyConfig_Read(Config); // Set program arguments (sys.argv) SetProgramArgs(Config); @@ -5025,18 +5018,6 @@ procedure TPythonEngine.SetPyFlags(const Value: TPythonFlags); end; // of if end; -function TPythonEngine.GetPythonHome: UnicodeString; -begin -{$IFDEF POSIX} - if Length(FPythonHome) = 0 then - Result := '' - else - Result := UCS4StringToUnicodeString(FPythonHome); -{$ELSE} - Result := FPythonHome; -{$ENDIF} -end; - function TPythonEngine.GetPythonPath: UnicodeString; begin {$IFDEF POSIX} @@ -5062,18 +5043,6 @@ function TPythonEngine.GetSequenceItem(sequence: PPyObject; end; end; -function TPythonEngine.GetProgramName: UnicodeString; -begin -{$IFDEF POSIX} - if Length(FProgramName) = 0 then - Result := '' - else - Result := UCS4StringToUnicodeString(FProgramName); -{$ELSE} - Result := FProgramName; -{$ENDIF} -end; - procedure TPythonEngine.SetPythonHome(const PythonHome: UnicodeString); begin {$IFDEF POSIX} @@ -9916,6 +9885,15 @@ function PyStatus_Exception(const APyStatus: PyStatus): Boolean; Result := APyStatus._type <> _PyStatus_TYPE_OK; end; +function StringToWCharTString(Str: string): WcharTString; +begin + {$IFDEF POSIX} + Result := UnicodeStringToUCS4String(UnicodeString(Str)); + {$ELSE} + Result := Str; + {$ENDIF} +end; + { TPyEngineAndGIL - Internal class for SafePythonEngine } type From 6cd46ca269fc6d8f3fbe9970ebce0e188b7fa0e5 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Mon, 1 Apr 2024 18:46:23 +0300 Subject: [PATCH 03/55] Removed CheckRegistry and associated OnPathInitialization event. It was a bad way to change the python path by modifying the Windows Registry. --- Source/PythonEngine.pas | 76 ----------------------------------------- 1 file changed, 76 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 3af53848..13aa5d06 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -1962,7 +1962,6 @@ TPythonInterface=class(TDynamicDll) DEFAULT_DATETIME_CONVERSION_MODE = dcmToTuple; type TEngineClient = class; - TPathInitializationEvent = procedure ( Sender : TObject; var Path : string ) of Object; TSysPathInitEvent = procedure ( Sender : TObject; PathList : PPyObject ) of Object; TPythonFlag = (pfDebug, pfInteractive, pfNoSite, pfOptimize, pfVerbose, pfFrozenFlag, pfIgnoreEnvironmentFlag, pfIsolated); @@ -2015,7 +2014,6 @@ TPythonEngine = class(TPythonInterface) FPythonHome: UnicodeString; FPythonPath: WCharTString; FInitThreads: Boolean; - FOnPathInitialization: TPathInitializationEvent; FOnSysPathInit: TSysPathInitEvent; FTraceback: TPythonTraceback; FUseWindowsConsole: Boolean; @@ -2049,7 +2047,6 @@ TPythonEngine = class(TPythonInterface) function GetClients( idx : Integer ) : TEngineClient; procedure Notification(AComponent: TComponent; Operation: TOperation); override; - procedure CheckRegistry; procedure SetProgramArgs(var Config: PyConfig); procedure InitWinConsole; procedure SetUseWindowsConsole( const Value : Boolean ); @@ -2168,7 +2165,6 @@ TPythonEngine = class(TPythonInterface) 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; - property OnPathInitialization: TPathInitializationEvent read FOnPathInitialization write FOnPathInitialization; property OnSysPathInit: TSysPathInitEvent read FOnSysPathInit write FOnSysPathInit; end; @@ -4757,14 +4753,6 @@ procedure TPythonEngine.Initialize; FInitialized := True else begin -// CheckRegistry; -// if Assigned(Py_SetProgramName) and (Length(FProgramName) > 0) then -// Py_SetProgramName(PWCharT(FProgramName)); -// AssignPyFlags; -// if Length(FPythonHome) > 0 then -// Py_SetPythonHome(PWCharT(FPythonHome)); -// Py_Initialize; - // Fills Config with zeros and then sets some default values if pfIsolated in FPyFlags then PyConfig_InitIsolatedConfig(Config) @@ -4872,62 +4860,6 @@ procedure TPythonEngine.Notification( AComponent: TComponent; IO := nil end; -procedure TPythonEngine.CheckRegistry; -{$IFDEF MSWINDOWS} -var - key : string; - Path : string; - NewPath : string; -{$IFDEF CPUX86} - LMajorVersion : integer; - LMinorVersion : integer; -{$ENDIF} - VersionSuffix: string; -{$ENDIF} -begin -{$IFDEF MSWINDOWS} - if Assigned( FOnPathInitialization ) then - try - with TRegistry.Create(KEY_ALL_ACCESS and not KEY_NOTIFY) do - try - VersionSuffix := ''; -{$IFDEF CPUX86} - PythonVersionFromRegVersion(RegVersion, LMajorVersion, LMinorVersion); - if (LMajorVersion > 3) or ((LMajorVersion = 3) and (LMinorVersion >= 5)) then - VersionSuffix := '-32'; -{$ENDIF} - key := Format('\Software\Python\PythonCore\%s%s\PythonPath', [RegVersion, VersionSuffix]); - - RootKey := HKEY_LOCAL_MACHINE; - if not KeyExists( key ) then - begin - // try a current user installation - RootKey := HKEY_CURRENT_USER; - if not KeyExists( key ) then Exit; - end; - // Key found - OpenKey( key, True ); - try - Path := ReadString(''); - NewPath := Path; - FOnPathInitialization( Self, NewPath ); - if NewPath <> Path then - begin - WriteString( '', NewPath ); - end; - finally - CloseKey; - end; - finally - Free; - end; - except - // under WinNT, with a user without admin rights, the access to the - // LocalMachine keys would raise an exception. - end; -{$ENDIF} -end; - procedure TPythonEngine.SetProgramArgs(var Config: PyConfig); var I: Integer; @@ -5045,11 +4977,7 @@ function TPythonEngine.GetSequenceItem(sequence: PPyObject; procedure TPythonEngine.SetPythonHome(const PythonHome: UnicodeString); begin -{$IFDEF POSIX} - FPythonHome := UnicodeStringToUCS4String(PythonHome); -{$ELSE} FPythonHome := PythonHome; -{$ENDIF} end; procedure TPythonEngine.SetPythonPath(const Value: UnicodeString); @@ -5063,11 +4991,7 @@ procedure TPythonEngine.SetPythonPath(const Value: UnicodeString); procedure TPythonEngine.SetProgramName(const ProgramName: UnicodeString); begin -{$IFDEF POSIX} - FProgramName := UnicodeStringToUCS4String(ProgramName); -{$ELSE} FProgramName := ProgramName; -{$ENDIF} end; function TPythonEngine.EvalPyFunction(pyfunc, pyargs:PPyObject): Variant; From 603a9f638f87eda0e71ca323d40ae611eea1676d Mon Sep 17 00:00:00 2001 From: pyscripter Date: Mon, 1 Apr 2024 19:02:48 +0300 Subject: [PATCH 04/55] Removed InitThreads property and deprecated PyEval_InitThreads which does nothing since python 3.7. --- Demos/Demo11/ThSort.dfm | 1 - Demos/Demo33/ThSort.dfm | 1 - Source/PythonEngine.pas | 18 ------------------ Tests/AutoWrapEventHandlerTest.pas | 1 - Tests/NumberServicesTest.pas | 1 - Tests/VarPythTest.pas | 1 - Tests/WrapDelphiEventHandlerTest.pas | 1 - Tests/WrapDelphiTest.pas | 1 - .../Webinar II/AnalyticsDemo/MainFormSVG.dfm | 1 - 9 files changed, 26 deletions(-) diff --git a/Demos/Demo11/ThSort.dfm b/Demos/Demo11/ThSort.dfm index 2f5f2710..f0c50c0d 100644 --- a/Demos/Demo11/ThSort.dfm +++ b/Demos/Demo11/ThSort.dfm @@ -165,7 +165,6 @@ object ThreadSortForm: TThreadSortForm OnClick = SaveBtnClick end object PythonEngine1: TPythonEngine - InitThreads = True RedirectIO = False Left = 16 Top = 32 diff --git a/Demos/Demo33/ThSort.dfm b/Demos/Demo33/ThSort.dfm index fa04fa71..3b4c41e6 100644 --- a/Demos/Demo33/ThSort.dfm +++ b/Demos/Demo33/ThSort.dfm @@ -171,7 +171,6 @@ object ThreadSortForm: TThreadSortForm OnClick = StopBtnClick end object PythonEngine1: TPythonEngine - InitThreads = True PyFlags = [pfDebug, pfInteractive, pfVerbose] RedirectIO = False Left = 16 diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 13aa5d06..34824c6c 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -1605,7 +1605,6 @@ TPythonInterface=class(TDynamicDll) PyEval_GetGlobals:function :PPyObject; cdecl; PyEval_GetLocals:function :PPyObject; cdecl; - PyEval_InitThreads:procedure; cdecl; PyEval_RestoreThread:procedure( tstate: PPyThreadState); cdecl; PyEval_SaveThread:function :PPyThreadState; cdecl; @@ -2013,7 +2012,6 @@ TPythonEngine = class(TPythonInterface) FProgramName: UnicodeString; FPythonHome: UnicodeString; FPythonPath: WCharTString; - FInitThreads: Boolean; FOnSysPathInit: TSysPathInitEvent; FTraceback: TPythonTraceback; FUseWindowsConsole: Boolean; @@ -2042,7 +2040,6 @@ TPythonEngine = class(TPythonInterface) procedure DoOpenDll(const aDllName : string); override; procedure SetInitScript(Value: TStrings); function GetThreadState: PPyThreadState; - procedure SetInitThreads(Value: Boolean); function GetClientCount : Integer; function GetClients( idx : Integer ) : TEngineClient; procedure Notification(AComponent: TComponent; @@ -2159,7 +2156,6 @@ TPythonEngine = class(TPythonInterface) property VenvPythonExe: string read FVenvPythonExe write FVenvPythonExe; property DatetimeConversionMode: TDatetimeConversionMode read FDatetimeConversionMode write FDatetimeConversionMode default DEFAULT_DATETIME_CONVERSION_MODE; property InitScript: TStrings read FInitScript write SetInitScript; - property InitThreads: Boolean read FInitThreads write SetInitThreads default False; property IO: TPythonInputOutput read FIO write SetIO; property PyFlags: TPythonFlags read FPyFlags write SetPyFlags default []; property RedirectIO: Boolean read FRedirectIO write FRedirectIO default True; @@ -3880,7 +3876,6 @@ procedure TPythonInterface.MapDll; PyEval_GetFrame := Import('PyEval_GetFrame'); PyEval_GetGlobals := Import('PyEval_GetGlobals'); PyEval_GetLocals := Import('PyEval_GetLocals'); - PyEval_InitThreads := Import('PyEval_InitThreads'); PyEval_RestoreThread := Import('PyEval_RestoreThread'); PyEval_SaveThread := Import('PyEval_SaveThread'); PyFile_GetLine := Import('PyFile_GetLine'); @@ -4555,7 +4550,6 @@ constructor TPythonEngine.Create(AOwner: TComponent); FRedirectIO := True; FExecModule := '__main__'; FAutoFinalize := True; - FInitThreads := False; FTraceback := TPythonTraceback.Create; FUseWindowsConsole := False; FPyFlags := []; @@ -4787,8 +4781,6 @@ procedure TPythonEngine.Initialize; else FInitialized := True; InitSysPath; - if InitThreads and Assigned(PyEval_InitThreads) then - PyEval_InitThreads; if RedirectIO and Assigned(FIO) then DoRedirectIO; end; @@ -4820,16 +4812,6 @@ function TPythonEngine.GetThreadState: PPyThreadState; Result := nil; end; -procedure TPythonEngine.SetInitThreads(Value: Boolean); -begin - if Value <> FInitThreads then - begin - if Value and Assigned(PyEval_InitThreads) then - PyEval_InitThreads; - FInitThreads := Value; - end; -end; - procedure TPythonEngine.SetIO(InputOutput: TPythonInputOutput); begin if InputOutput <> fIO then diff --git a/Tests/AutoWrapEventHandlerTest.pas b/Tests/AutoWrapEventHandlerTest.pas index feb9656d..173794c2 100644 --- a/Tests/AutoWrapEventHandlerTest.pas +++ b/Tests/AutoWrapEventHandlerTest.pas @@ -71,7 +71,6 @@ procedure TTestAutoWrapEventHandlers.SetupFixture; PythonEngine.FatalMsgDlg := True; PythonEngine.UseLastKnownVersion := True; PythonEngine.AutoFinalize := True; - PythonEngine.InitThreads := True; PythonEngine.PyFlags := [pfInteractive]; DelphiModule := TPythonModule.Create(nil); DelphiModule.Name := 'DelphiModule'; diff --git a/Tests/NumberServicesTest.pas b/Tests/NumberServicesTest.pas index d1e1a3cf..ca1bdb1a 100644 --- a/Tests/NumberServicesTest.pas +++ b/Tests/NumberServicesTest.pas @@ -176,7 +176,6 @@ procedure TTestNumberServices.SetupFixture; PythonEngine.UseLastKnownVersion := True; PythonEngine.AutoFinalize := True; - PythonEngine.InitThreads := True; PythonEngine.PyFlags := [pfInteractive]; PythonEngine.LoadDll; diff --git a/Tests/VarPythTest.pas b/Tests/VarPythTest.pas index 34e68f0a..f32fa7de 100644 --- a/Tests/VarPythTest.pas +++ b/Tests/VarPythTest.pas @@ -74,7 +74,6 @@ procedure TTestVarPyth.SetupFixture; PythonEngine.UseLastKnownVersion := True; PythonEngine.AutoFinalize := True; - PythonEngine.InitThreads := True; PythonEngine.PyFlags := [pfInteractive]; PythonEngine.LoadDll; end; diff --git a/Tests/WrapDelphiEventHandlerTest.pas b/Tests/WrapDelphiEventHandlerTest.pas index c6cda4ce..efaf5b44 100644 --- a/Tests/WrapDelphiEventHandlerTest.pas +++ b/Tests/WrapDelphiEventHandlerTest.pas @@ -215,7 +215,6 @@ procedure TTestWrapDelphiEventHandlers.SetupFixture; PythonEngine.FatalMsgDlg := True; PythonEngine.UseLastKnownVersion := True; PythonEngine.AutoFinalize := True; - PythonEngine.InitThreads := True; PythonEngine.PyFlags := [pfInteractive]; DelphiModule := TPythonModule.Create(nil); DelphiModule.Name := 'DelphiModule'; diff --git a/Tests/WrapDelphiTest.pas b/Tests/WrapDelphiTest.pas index ba7ff43e..384584fa 100644 --- a/Tests/WrapDelphiTest.pas +++ b/Tests/WrapDelphiTest.pas @@ -202,7 +202,6 @@ procedure TTestWrapDelphi.SetupFixture; PythonEngine.UseLastKnownVersion := True; PythonEngine.AutoFinalize := True; - PythonEngine.InitThreads := True; PythonEngine.PyFlags := [pfInteractive]; DelphiModule := TPythonModule.Create(nil); diff --git a/Tutorials/Webinar II/AnalyticsDemo/MainFormSVG.dfm b/Tutorials/Webinar II/AnalyticsDemo/MainFormSVG.dfm index 15464024..1642832f 100644 --- a/Tutorials/Webinar II/AnalyticsDemo/MainFormSVG.dfm +++ b/Tutorials/Webinar II/AnalyticsDemo/MainFormSVG.dfm @@ -254,7 +254,6 @@ object Form1: TForm1 Top = 89 end object PythonEngine1: TPythonEngine - InitThreads = True IO = PythonGUIInputOutput1 Left = 632 Top = 136 From 5b2a7bdebdfe788d86a7f4691a37e5d5dfbeeeea Mon Sep 17 00:00:00 2001 From: pyscripter Date: Mon, 1 Apr 2024 20:11:32 +0300 Subject: [PATCH 05/55] The public PythonPath property can be used to initialize sys.path. --- Source/PythonEngine.pas | 49 +++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 34824c6c..e0d886e9 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -2011,7 +2011,7 @@ TPythonEngine = class(TPythonInterface) FAutoFinalize: Boolean; FProgramName: UnicodeString; FPythonHome: UnicodeString; - FPythonPath: WCharTString; + FPythonPath: UnicodeString; FOnSysPathInit: TSysPathInitEvent; FTraceback: TPythonTraceback; FUseWindowsConsole: Boolean; @@ -2029,8 +2029,6 @@ TPythonEngine = class(TPythonInterface) FPyDateTime_TZInfoType: PPyObject; FPyDateTime_TimeTZType: PPyObject; FPyDateTime_DateTimeTZType: PPyObject; - function GetPythonPath: UnicodeString; - procedure SetPythonPath(const Value: UnicodeString); protected procedure Initialize; @@ -2150,7 +2148,10 @@ TPythonEngine = class(TPythonInterface) property IOPythonModule: TObject read FIOPythonModule; {TPythonModule} property PythonHome: UnicodeString read FPythonHome write SetPythonHome; property ProgramName: UnicodeString read FProgramName write SetProgramName; - property PythonPath: UnicodeString read GetPythonPath write SetPythonPath; + // List of paths separated with the path delimiter + // If used with pfNoSite, it completely overwrites the pyhon path on initialization! + // For adding directories to sys.path use the OnSysPathInit event instead. + property PythonPath: UnicodeString read FPythonPath write FPythonPath; published property AutoFinalize: Boolean read FAutoFinalize write FAutoFinalize default True; property VenvPythonExe: string read FVenvPythonExe write FVenvPythonExe; @@ -4686,6 +4687,21 @@ procedure TPythonEngine.Initialize; FOnSysPathInit(Self, _path); end; + procedure SetPythonPath(var Config: PyConfig); + var + Paths: TArray; + I: Integer; + begin + if FPythonPath = '' then Exit; + + Paths := FPythonPath.Split([PathSep], TStringSplitOptions.ExcludeLastEmpty); + for I := 0 to Length(Paths) - 1 do + PyWideStringList_Append(Config.module_search_paths, + PWCharT(StringToWCharTString(Paths[I]))); + if Config.module_search_paths.length > 0 then + Config.module_search_paths_set := 1; + end; + function GetVal(AModule : PPyObject; AVarName : AnsiString) : PPyObject; begin Result := PyObject_GetAttrString(AModule, PAnsiChar(AVarName)); @@ -4767,10 +4783,12 @@ procedure TPythonEngine.Initialize; PyConfig_SetString(Config, @Config.program_name, PWCharT(StringToWCharTString(FVenvPythonExe))); - PyConfig_Read(Config); // Set program arguments (sys.argv) SetProgramArgs(Config); + // PythonPath + SetPythonPath(Config); + Py_InitializeFromConfig(Config); finally PyConfig_Clear(Config); @@ -4932,18 +4950,6 @@ procedure TPythonEngine.SetPyFlags(const Value: TPythonFlags); end; // of if end; -function TPythonEngine.GetPythonPath: UnicodeString; -begin -{$IFDEF POSIX} - if (Length(FPythonPath) > 0) then - Result := UCS4StringToUnicodeString(FPythonPath) - else - Result := ''; -{$ELSE} - Result := FPythonPath; -{$ENDIF} -end; - function TPythonEngine.GetSequenceItem(sequence: PPyObject; idx: Integer): Variant; var @@ -4962,15 +4968,6 @@ procedure TPythonEngine.SetPythonHome(const PythonHome: UnicodeString); FPythonHome := PythonHome; end; -procedure TPythonEngine.SetPythonPath(const Value: UnicodeString); -begin -{$IFDEF POSIX} - FPythonPath := UnicodeStringToUCS4String(Value); -{$ELSE} - FPythonPath := Value; -{$ENDIF} -end; - procedure TPythonEngine.SetProgramName(const ProgramName: UnicodeString); begin FProgramName := ProgramName; From a7ea765319d077310f20a927548154906fb89f7c Mon Sep 17 00:00:00 2001 From: pyscripter Date: Mon, 1 Apr 2024 20:16:50 +0300 Subject: [PATCH 06/55] Added OnConfigInit event. --- Source/PythonEngine.pas | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index e0d886e9..afaa7842 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -1961,7 +1961,8 @@ TPythonInterface=class(TDynamicDll) DEFAULT_DATETIME_CONVERSION_MODE = dcmToTuple; type TEngineClient = class; - TSysPathInitEvent = procedure ( Sender : TObject; PathList : PPyObject ) of Object; + TSysPathInitEvent = procedure(Sender: TObject; PathList: PPyObject) of object; + TConfigInitEvent = procedure(Sender: TObject; var Config: PyConfig) of object; TPythonFlag = (pfDebug, pfInteractive, pfNoSite, pfOptimize, pfVerbose, pfFrozenFlag, pfIgnoreEnvironmentFlag, pfIsolated); TPythonFlags = set of TPythonFlag; @@ -2013,6 +2014,7 @@ TPythonEngine = class(TPythonInterface) FPythonHome: UnicodeString; FPythonPath: UnicodeString; FOnSysPathInit: TSysPathInitEvent; + FOnConfigInit: TConfigInitEvent; FTraceback: TPythonTraceback; FUseWindowsConsole: Boolean; FGlobalVars: PPyObject; @@ -2163,6 +2165,8 @@ TPythonEngine = class(TPythonInterface) property UseWindowsConsole: Boolean read FUseWindowsConsole write FUseWindowsConsole default False; property OnAfterInit: TNotifyEvent read FOnAfterInit write FOnAfterInit; property OnSysPathInit: TSysPathInitEvent read FOnSysPathInit write FOnSysPathInit; + property OnConfigInit: TConfigInitEvent read FOnConfigInit write FOnConfigInit; + end; @@ -4789,6 +4793,10 @@ procedure TPythonEngine.Initialize; // PythonPath SetPythonPath(Config); + // Fine tune Config + if Assigned(FOnConfigInit) then + FOnConfigInit(Self, Config); + Py_InitializeFromConfig(Config); finally PyConfig_Clear(Config); From 862db52ff979664b631e96a83045c4f725ba854d Mon Sep 17 00:00:00 2001 From: pyscripter Date: Wed, 3 Apr 2024 01:35:13 +0300 Subject: [PATCH 07/55] Fix #466 Python 3.13 support implemented and tested (preliminary since 3.13 is still in alpha) Since the PyConfig structure is python version dependent it was made opaque. --- Demos/Demo29/Unit1.dfm | 2 - Demos/Demo29/Unit1.pas | 2 +- Source/PythonEngine.pas | 259 +++++++++++++++++----------------------- Source/VarPyth.pas | 2 +- 4 files changed, 109 insertions(+), 156 deletions(-) diff --git a/Demos/Demo29/Unit1.dfm b/Demos/Demo29/Unit1.dfm index c149398f..c151b511 100644 --- a/Demos/Demo29/Unit1.dfm +++ b/Demos/Demo29/Unit1.dfm @@ -10,11 +10,9 @@ object Form1: TForm1 Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] - OldCreateOrder = False DesignSize = ( 668 701) - PixelsPerInch = 96 TextHeight = 13 object Image1: TImage Left = 8 diff --git a/Demos/Demo29/Unit1.pas b/Demos/Demo29/Unit1.pas index 025c5cd1..b969d646 100644 --- a/Demos/Demo29/Unit1.pas +++ b/Demos/Demo29/Unit1.pas @@ -86,7 +86,7 @@ procedure TForm1.Button2Click(Sender: TObject); with GetPythonEngine do begin pargs := MakePyTuple([ExtractPythonObjectFrom(_im)]); try - presult := PyEval_CallObjectWithKeywords( + presult := PyObject_Call( ExtractPythonObjectFrom(MainModule.ImageToBytes), pargs, nil); try if PyBytes_AsStringAndSize(presult, P, Len) < 0 then begin diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index afaa7842..968452a6 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -979,83 +979,68 @@ PyBufferProcs = record PPyConfig = ^PyConfig; PyConfig = record - _config_init: Integer; - isolated: Integer; - use_environment: Integer; - dev_mode: Integer; - install_signal_handlers: Integer; - use_hash_seed: Integer; - hash_seed: C_ULong; - faulthandler: Integer; - tracemalloc: Integer; - perf_profiling: Integer; - import_time: Integer; - code_debug_ranges: Integer; - show_ref_count: Integer; - dump_refs: Integer; - dump_refs_file: PWCharT; - malloc_stats: Integer; - filesystem_encoding: PWCharT; - filesystem_errors: PWCharT; - pycache_prefix: PWCharT; - parse_argv: Integer; - orig_argv: PyWideStringList; - argv: PyWideStringList; - xoptions: PyWideStringList; - warnoptions: PyWideStringList ; - site_import: Integer; - bytes_warning: Integer; - warn_default_encoding: Integer; - inspect: Integer; - interactive: Integer; - optimization_level: Integer; - parser_debug: Integer; - write_bytecode: Integer; - verbose: Integer; - quiet: Integer; - user_site_directory: Integer; - configure_c_stdio: Integer; - buffered_stdio: Integer; - stdio_encoding: PWCharT; - stdio_errors: PWCharT; + // The definition of PyConfig has been changing in every python version + // So we make this structure opaque and we access its fields through + // the ConfigOffsets below + Filler: array [0..1000] of Byte; + end; + +{$SCOPEDENUMS ON} + TConfigFields = ( + use_environment, + parse_argv, + argv, + site_import, + interactive, + optimization_level, + parser_debug, + verbose, + pathconfig_warnings, + program_name, + home, + module_search_paths_set, + module_search_paths, + executable); +{$SCOPEDENUMS OFF} + + TConfigOffsets = array [8..13] of array [TConfigFields] of Integer; + + // The followng needs updating when new versions are added + const + ConfigOffests: TConfigOffsets = {$IFDEF MSWINDOWS} - legacy_windows_stdio: Integer; + {$IFDEF CPU64BITS} + ((8, 80, 88, 144, 156, 160, 164, 172, 216, 104, 232, 240, 248, 264), + (8, 80, 88, 144, 156, 160, 164, 172, 216, 104, 232, 240, 248, 264), + (8, 80, 104, 152, 168, 172, 176, 184, 232, 240, 256, 272, 280, 296), + (8, 96, 120, 168, 184, 188, 192, 200, 264, 272, 288, 304, 312, 336), + (8, 96, 120, 168, 184, 188, 192, 200, 268, 272, 288, 304, 312, 336), + (8, 96, 120, 168, 184, 188, 192, 200, 272, 280, 296, 312, 320, 344)); + {$ELSE} + ((8, 68, 72, 100, 112, 116, 120, 128, 164, 80, 172, 176, 180, 188), + (8, 68, 72, 100, 112, 116, 120, 128, 164, 80, 172, 176, 180, 188), + (8, 64, 76, 100, 116, 120, 124, 132, 168, 172, 180, 188, 192, 200), + (8, 72, 84, 108, 124, 128, 132, 140, 184, 188, 196, 204, 208, 220), + (8, 76, 88, 112, 128, 132, 136, 144, 192, 196, 204, 212, 216, 228), + (8, 76, 88, 112, 128, 132, 136, 144, 196, 200, 208, 216, 220, 232)); + {$ENDIF} + {$ELSE} + {$IFDEF CPU64BITS} + ((8, 88, 96, 152, 164, 168, 172, 180, 224, 112, 240, 248, 256, 272), + (8, 88, 96, 152, 164, 168, 172, 180, 224, 112, 240, 248, 256, 272), + (8, 80, 104, 152, 168, 172, 176, 184, 232, 240, 256, 272, 280, 296), + (8, 96, 120, 168, 184, 188, 192, 200, 256, 264, 280, 296, 304, 328), + (8, 104, 128, 176, 192, 196, 200, 208, 268, 272, 288, 304, 312, 336), + (8, 104, 128, 176, 192, 196, 200, 208, 272, 280, 296, 312, 320, 344)); + {$ELSE} + ((8, 68, 72, 100, 112, 116, 120, 128, 160, 80, 168, 172, 176, 184), + (8, 68, 72, 100, 112, 116, 120, 128, 160, 80, 168, 172, 176, 184), + (8, 64, 76, 100, 116, 120, 124, 132, 164, 168, 176, 184, 188, 196), + (8, 72, 84, 108, 124, 128, 132, 140, 180, 184, 192, 200, 204, 216), + (8, 76, 88, 112, 128, 132, 136, 144, 188, 192, 200, 208, 212, 224), + (8, 76, 88, 112, 128, 132, 136, 144, 192, 196, 204, 212, 216, 228)); + {$ENDIF} {$ENDIF} - check_hash_pycs_mode: PWCharT; - use_frozen_modules: Integer; - safe_path: Integer; - int_max_str_digits: Integer; - - (* --- Path configuration inputs ------------ *) - pathconfig_warnings: Integer; - program_name: PWCharT; - pythonpath_env: PWCharT; - home: PWCharT; - platlibdir: PWCharT; - - (* --- Path configuration outputs ----------- *) - module_search_paths_set: Integer; - module_search_paths: PyWideStringList; - stdlib_dir: PWCharT; - executable: PWCharT; - base_executable: PWCharT; - prefix: PWCharT; - base_prefix: PWCharT; - exec_prefix: PWCharT; - base_exec_prefix: PWCharT; - - (* --- Parameter only used by Py_Main() ---------- *) - kip_source_first_line: Integer; - un_command: PWCharT; - un_module: PWCharT; - un_filename: PWCharT; - - (* --- Private fields ---------------------------- *) - install_importlib: Integer; - init_main: Integer; - is_python_build: Integer; -end; - //####################################################### //## ## @@ -1583,7 +1568,6 @@ TPythonInterface=class(TDynamicDll) PyBytes_AsString: function( ob: PPyObject): PAnsiChar; cdecl; PyBytes_AsStringAndSize: function( ob: PPyObject; var buffer: PAnsiChar; var size: NativeInt): integer; cdecl; PyByteArray_AsString: function(ob: PPyObject): PAnsiChar; cdecl; - PySys_SetArgv: procedure( argc: Integer; argv: PPWCharT); cdecl; PyCFunction_NewEx: function(md:PPyMethodDef;self, ob:PPyObject):PPyObject; cdecl; @@ -1598,9 +1582,6 @@ TPythonInterface=class(TDynamicDll) len: Py_ssize_t; readonly: Integer; flags: Integer): Integer; cdecl; PyBuffer_Release: procedure(view: PPy_buffer); cdecl; - // Removed. Use PyEval_CallObjectWithKeywords with third argument nil - // PyEval_CallObject: function(callable_obj, args:PPyObject):PPyObject; cdecl; - PyEval_CallObjectWithKeywords:function (callable_obj, args, kw:PPyObject):PPyObject; cdecl; PyEval_GetFrame:function :PPyObject; cdecl; PyEval_GetGlobals:function :PPyObject; cdecl; PyEval_GetLocals:function :PPyObject; cdecl; @@ -1760,7 +1741,6 @@ TPythonInterface=class(TDynamicDll) PySet_Size: function(anyset: PPyObject): Py_ssize_t; cdecl; PySys_GetObject:function (s:PAnsiChar):PPyObject; cdecl; PySys_SetObject:function (s:PAnsiChar;ob:PPyObject):integer; cdecl; - PySys_SetPath:procedure(path:PAnsiChar); cdecl; PyTraceBack_Here:function (p:pointer):integer; cdecl; PyTraceBack_Print:function (ob1,ob2:PPyObject):integer; cdecl; PyTuple_GetItem:function (ob:PPyObject;i:NativeInt):PPyObject; cdecl; @@ -1803,25 +1783,18 @@ TPythonInterface=class(TDynamicDll) Py_GetCopyright : function : PAnsiChar; cdecl; Py_GetExecPrefix : function : PWCharT; cdecl; Py_GetPath : function : PWCharT; cdecl; - Py_SetPath : procedure (path: PWCharT); cdecl; - Py_SetPythonHome : procedure (home : PWCharT); cdecl; Py_GetPythonHome : function : PWCharT; cdecl; Py_GetPrefix : function : PWCharT; cdecl; Py_GetProgramName : function : PWCharT; cdecl; - PyParser_SimpleParseStringFlags : function ( str : PAnsiChar; start, flags : Integer) : PNode; cdecl; - PyNode_Free : procedure( n : PNode ); cdecl; PyErr_NewException : function ( name : PAnsiChar; base, dict : PPyObject ) : PPyObject; cdecl; PyMem_Malloc : function ( size : NativeUInt ) : Pointer; - Py_SetProgramName : procedure( name: PWCharT); cdecl; Py_IsInitialized : function : integer; cdecl; Py_GetProgramFullPath : function : PAnsiChar; cdecl; Py_NewInterpreter : function : PPyThreadState; cdecl; Py_NewInterpreterFromConfig : function( tstate: PPyThreadState; config: PPyInterpreterConfig): PyStatus; cdecl; Py_EndInterpreter : procedure( tstate: PPyThreadState); cdecl; - PyEval_AcquireLock : procedure; cdecl; - PyEval_ReleaseLock : procedure; cdecl; PyEval_AcquireThread : procedure( tstate: PPyThreadState); cdecl; PyEval_ReleaseThread : procedure( tstate: PPyThreadState); cdecl; PyInterpreterState_New : function : PPyInterpreterState; cdecl; @@ -1837,8 +1810,8 @@ TPythonInterface=class(TDynamicDll) PyGILState_Release : procedure(gilstate : PyGILState_STATE); cdecl; // Initialization functions - PyWideStringList_Append : function(var list: PyWideStringList; item: PWCharT): PyStatus; cdecl; - PyWideStringList_Insert : function(var list: PyWideStringList; index: Py_ssize_t; item: PWCharT): PyStatus; cdecl; + PyWideStringList_Append : function(list: PPyWideStringList; item: PWCharT): PyStatus; cdecl; + PyWideStringList_Insert : function(list: PPyWideStringList; index: Py_ssize_t; item: PWCharT): PyStatus; cdecl; PyConfig_InitPythonConfig : procedure(var config: PyConfig); cdecl; PyConfig_InitIsolatedConfig : procedure(var config: PyConfig); cdecl; PyConfig_Clear : procedure(var config: PyConfig); cdecl; @@ -1848,11 +1821,6 @@ 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; - // Not exported in Python 3.8 and implemented as functions - this has been fixed - // TODO - deal with the following: - // the PyParser_* functions are deprecated in python 3.9 and will be removed in - // Python 3.10 - function PyParser_SimpleParseString(str : PAnsiChar; start : Integer) : PNode; cdecl; function Py_CompileString(str,filename:PAnsiChar;start:integer) : PPyObject; cdecl; // functions redefined in Delphi @@ -3862,7 +3830,6 @@ procedure TPythonInterface.MapDll; PyRun_String := Import('PyRun_String'); PyRun_SimpleString := Import('PyRun_SimpleString'); PyDict_GetItemString := Import('PyDict_GetItemString'); - PySys_SetArgv := Import('PySys_SetArgv'); Py_Exit := Import('Py_Exit'); PyCFunction_NewEx := Import('PyCFunction_NewEx'); @@ -3877,7 +3844,6 @@ procedure TPythonInterface.MapDll; if (FMajorVersion > 3) or (FMinorVersion > 9) then PyBuffer_SizeFromFormat := Import('PyBuffer_SizeFromFormat'); - PyEval_CallObjectWithKeywords:= Import('PyEval_CallObjectWithKeywords'); PyEval_GetFrame := Import('PyEval_GetFrame'); PyEval_GetGlobals := Import('PyEval_GetGlobals'); PyEval_GetLocals := Import('PyEval_GetLocals'); @@ -4040,7 +4006,6 @@ procedure TPythonInterface.MapDll; PySet_Size := Import('PySet_Size'); PySys_GetObject := Import('PySys_GetObject'); PySys_SetObject := Import('PySys_SetObject'); - PySys_SetPath := Import('PySys_SetPath'); PyTraceBack_Here := Import('PyTraceBack_Here'); PyTraceBack_Print := Import('PyTraceBack_Print'); PyTuple_GetItem := Import('PyTuple_GetItem'); @@ -4083,24 +4048,15 @@ procedure TPythonInterface.MapDll; Py_GetCopyright := Import('Py_GetCopyright'); Py_GetExecPrefix := Import('Py_GetExecPrefix'); Py_GetPath := Import('Py_GetPath'); - Py_SetPath := Import('Py_SetPath'); - Py_SetPythonHome := Import('Py_SetPythonHome'); Py_GetPythonHome := Import('Py_GetPythonHome'); Py_GetPrefix := Import('Py_GetPrefix'); Py_GetProgramName := Import('Py_GetProgramName'); - if (FMajorVersion = 3) and (FMinorVersion < 10) then - begin - PyParser_SimpleParseStringFlags := Import('PyParser_SimpleParseStringFlags'); - PyNode_Free := Import('PyNode_Free'); - end; - PyErr_NewException := Import('PyErr_NewException'); try PyMem_Malloc := Import ('PyMem_Malloc'); except end; - Py_SetProgramName := Import('Py_SetProgramName'); Py_IsInitialized := Import('Py_IsInitialized'); Py_GetProgramFullPath := Import('Py_GetProgramFullPath'); Py_GetBuildInfo := Import('Py_GetBuildInfo'); @@ -4108,8 +4064,6 @@ procedure TPythonInterface.MapDll; if (FMajorVersion > 3) or (FMinorVersion >= 12) then Py_NewInterpreterFromConfig := Import('Py_NewInterpreterFromConfig'); Py_EndInterpreter := Import('Py_EndInterpreter'); - PyEval_AcquireLock := Import('PyEval_AcquireLock'); - PyEval_ReleaseLock := Import('PyEval_ReleaseLock'); PyEval_AcquireThread := Import('PyEval_AcquireThread'); PyEval_ReleaseThread := Import('PyEval_ReleaseThread'); PyInterpreterState_New := Import('PyInterpreterState_New'); @@ -4141,11 +4095,6 @@ function TPythonInterface.Py_CompileString(str,filename:PAnsiChar;start:integer) Result := Py_CompileStringExFlags(str, filename, start, nil, -1); end; -function TPythonInterface.PyParser_SimpleParseString( str : PAnsiChar; start : integer) : PNode; cdecl; -begin - Result := PyParser_SimpleParseStringFlags(str, start, 0); -end; - class procedure TPythonInterface.Py_INCREF(op: PPyObject); begin Inc(op^.ob_refcnt); @@ -4671,13 +4620,20 @@ procedure TPythonEngine.DoOpenDll(const aDllName : string); procedure TPythonEngine.AssignPyFlags(var Config: PyConfig); begin - Config.parser_debug := IfThen(pfDebug in FPyFlags, 1, 0); - Config.verbose := IfThen(pfVerbose in FPyFlags, 1, 0); - Config.interactive := IfThen(pfInteractive in FPyFlags, 1, 0); - Config.optimization_level := IfThen(pfOptimize in FPyFlags, 1, 0); - Config.site_import := IfThen(pfNoSite in FPyFlags, 0, 1); - Config.pathconfig_warnings := IfThen(pfFrozenFlag in FPyFlags, 1, 0); - Config.use_environment := IfThen(pfIgnoreEnvironmentFlag in FPyFlags, 0, 1); + 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; @@ -4695,15 +4651,23 @@ procedure TPythonEngine.Initialize; var Paths: TArray; I: Integer; + PWSL: PPyWideStringList; begin if FPythonPath = '' then Exit; - Paths := FPythonPath.Split([PathSep], TStringSplitOptions.ExcludeLastEmpty); + PWSL := PPyWideStringList(PByte(@Config) + ConfigOffests[MinorVersion, + TConfigFields.module_search_paths]); + Paths := FPythonPath.Split([PathSep]); for I := 0 to Length(Paths) - 1 do - PyWideStringList_Append(Config.module_search_paths, - PWCharT(StringToWCharTString(Paths[I]))); - if Config.module_search_paths.length > 0 then - Config.module_search_paths_set := 1; + 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; function GetVal(AModule : PPyObject; AVarName : AnsiString) : PPyObject; @@ -4777,14 +4741,17 @@ procedure TPythonEngine.Initialize; // Set programname and pythonhome if available if FProgramName <> '' then - PyConfig_SetString(Config, @Config.program_name, + PyConfig_SetString(Config, + PPWcharT(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.program_name]), PWCharT(StringToWCharTString(FProgramName))); if FPythonHome <> '' then - PyConfig_SetString(Config, @Config.program_name, + PyConfig_SetString(Config, + PPWcharT(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.home]), PWCharT(StringToWCharTString(FPythonHome))); // Set venv executable if available if FVenvPythonExe <> '' then - PyConfig_SetString(Config, @Config.program_name, + PyConfig_SetString(Config, + PPWcharT(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.executable]), PWCharT(StringToWCharTString(FVenvPythonExe))); // Set program arguments (sys.argv) @@ -4875,7 +4842,8 @@ procedure TPythonEngine.SetProgramArgs(var Config: PyConfig); Str: WCharTString; begin - Config.parse_argv := 0; // do not parse + // do not parse further + PInteger(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.parse_argv])^ := 0; for I := 0 to ParamCount do begin { @@ -4892,7 +4860,9 @@ procedure TPythonEngine.SetProgramArgs(var Config: PyConfig); {$ELSE} Str := TempS; {$ENDIF} - PyWideStringList_Append(Config.argv, PWCharT(Str)); + PyWideStringList_Append( + PPyWideStringList(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.argv]), + PWCharT(Str)); end; end; @@ -4988,7 +4958,7 @@ function TPythonEngine.EvalPyFunction(pyfunc, pyargs:PPyObject): Variant; Result := -1; if pyfunc = nil then exit; try - presult := PyEval_CallObjectWithKeywords(pyfunc,pyargs, nil); + presult := PyObject_Call(pyfunc,pyargs, nil); CheckError(False); if presult = nil then // should not happen since an exception would have been raised @@ -5200,22 +5170,11 @@ function TPythonEngine.CheckExecSyntax( const str : AnsiString ) : Boolean; function TPythonEngine.CheckSyntax( const str : AnsiString; mode : Integer ) : Boolean; var - n : PNode; PyCode: PPyObject; begin - if (FMajorVersion = 3) and (MinorVersion < 10) then - begin - n := PyParser_SimpleParseString( PAnsiChar(str), mode ); - result := Assigned(n); - if Assigned( n ) then - PyNode_Free(n); - end - else - begin - PyCode := Py_CompileString(PAnsiChar(str), '', mode); - Result := Assigned(PyCode); - Py_XDECREF(PyCode); - end; + PyCode := Py_CompileString(PAnsiChar(str), '', mode); + Result := Assigned(PyCode); + Py_XDECREF(PyCode); end; procedure TPythonEngine.RaiseError; @@ -5741,7 +5700,7 @@ function TPythonEngine.VariantAsPyObject( const V : Variant ) : PPyObject; raise EPythonError.Create('dcmToDatetime DatetimeConversionMode cannot be used with this version of python. Missing module datetime'); args := ArrayToPyTuple([y, m, d, h, mi, sec, ms*1000]); try - Result := PyEval_CallObjectWithKeywords(FPyDateTime_DateTimeType, args, nil); + Result := PyObject_Call(FPyDateTime_DateTimeType, args, nil); CheckError(False); finally Py_DecRef(args); @@ -7225,11 +7184,7 @@ procedure TError.RaiseErrorObj( const msg : AnsiString; obj : PPyObject ); // instance. if PyDict_Check( obj ) then begin - args := PyTuple_New(0); - if not Assigned(args) then - raise Exception.Create('TError.RaiseErrorObj: Could not create an empty tuple'); - res := PyEval_CallObjectWithKeywords(Error, args, nil); - Py_DECREF(args); + res := PyObject_CallObject(Error, nil); if not Assigned(res) then raise Exception.CreateFmt('TError.RaiseErrorObj: Could not create an instance of "%s"', [Self.Name]); if PyObject_TypeCheck(res, PPyTypeObject(PyExc_Exception^)) then @@ -7239,7 +7194,7 @@ procedure TError.RaiseErrorObj( const msg : AnsiString; obj : PPyObject ); raise Exception.Create('TError.RaiseErrorObj: Could not create an empty tuple'); str := PyUnicodeFromString(msg); PyTuple_SetItem(args, 0, str); - res := PyEval_CallObjectWithKeywords(Error, args, nil); + res := PyObject_Call(Error, args, nil); Py_DECREF(args); if not Assigned(res) then raise Exception.CreateFmt('TError.RaiseErrorObj: Could not create an instance of "%s"', [Self.Name]); diff --git a/Source/VarPyth.pas b/Source/VarPyth.pas index fd69085f..b16f91b8 100644 --- a/Source/VarPyth.pas +++ b/Source/VarPyth.pas @@ -1604,7 +1604,7 @@ function TPythonVariantType.EvalPython(const V: TVarData; PyDict_SetItemString(_KW, LNamedParams[i].Name, ArgAsPythonObject(LNamedParams[i].Index)); // call the func or method, with or without named parameters (KW) - Result := PyEval_CallObjectWithKeywords(_obj, _Args, _KW); + Result := PyObject_Call(_obj, _Args, _KW); CheckError(True); finally Py_XDecRef(_Args); From 7b485c1d612c1b516b283a19e584cf61ae65aa2d Mon Sep 17 00:00:00 2001 From: pyscripter Date: Mon, 8 Apr 2024 08:27:17 +0300 Subject: [PATCH 08/55] Fix #469 --- Source/WrapDelphi.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index 6ec11c1f..79e626f6 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -1021,8 +1021,8 @@ implementation rs_ErrCheckBound = 'Delphi wrapper %s is not bound'; rs_ErrSequence = 'Wrapper %s does not support sequences'; rs_ErrInvalidArgs = '"%s" called with invalid arguments.'#$A'Error: %s'; - rs_ErrInvalidRet = 'Call "%s" returned a value that could not be coverted to Python'#$A'Error: %s'; - rs_IncompatibleArguments = 'Expected and actual arguements are incompatible'; + rs_ErrInvalidRet = 'Call "%s" returned a value that could not be converted to Python'#$A'Error: %s'; + rs_IncompatibleArguments = 'Expected and actual arguments are incompatible'; rs_ErrAttrGet = 'Error in getting property "%s".'#$A'Error: %s'; rs_UnknownAttribute = 'Unknown attribute'; rs_ErrIterSupport = 'Wrapper %s does not support iterators'; From b3e051cb254ef77eecde76e13dd82c62f1586323 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Mon, 8 Apr 2024 14:47:44 +0300 Subject: [PATCH 09/55] Wrap methods with parameters and/or return values PPyObjects. --- Source/WrapDelphi.pas | 40 +++++++++++++++++++++++++++++++++++----- Tests/WrapDelphiTest.pas | 22 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index 79e626f6..04ecc415 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -1038,6 +1038,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'; 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 '+ @@ -2176,6 +2177,25 @@ function ValidateDynArray(PyValue: PPyObject; const RttiType: TRttiType; end; end; +function ValidatePPyObject(PyValue: PPyObject; const RttiType: TRttiType; + out ParamValue: TValue; out ErrMsg: string): Boolean; +var + RefType: TRttiType; +begin + Result := False; + if (RTTIType is TRttiPointerType) then + begin + RefType := TRttiPointerType(RTTIType).ReferredType; + if Assigned(RefType) and (RefType.Name = 'PyObject') then + begin + Result := True; + ParamValue := TValue.From(PyValue); + end; + end; + if not Result then + ErrMsg := rsExpectedPPyObject; +end; + function PyObjectToTValue(PyArg: PPyObject; ArgType: TRttiType; out Arg: TValue; out ErrMsg: string): Boolean; var @@ -2205,7 +2225,9 @@ function PyObjectToTValue(PyArg: PPyObject; ArgType: TRttiType; tkRecord{$IFDEF MANAGED_RECORD}, tkMRecord{$ENDIF}: Result := ValidateRecordProperty(PyArg, ArgType.Handle, Arg, ErrMsg); tkDynArray: - Result := ValidateDynArray(PyArg, ArgType, Arg, ErrMsg) + Result := ValidateDynArray(PyArg, ArgType, Arg, ErrMsg); + tkPointer: + Result := ValidatePPyObject(PyArg, ArgType, Arg, ErrMsg); else Result := SimplePythonToValue(PyArg, ArgType.Handle, Arg, ErrMsg); end; @@ -2254,6 +2276,14 @@ function TValueToPyObject(const Value: TValue; Result := DelphiWrapper.WrapRecord(Value); tkArray, tkDynArray: Result := DynArrayToPython(Value, DelphiWrapper, ErrMsg); + tkPointer: + if Value.IsType then + Result := Value.AsType + else + begin + Result := nil; + ErrMsg := rs_ErrValueToPython; + end; else Result := SimpleValueToPython(Value, ErrMsg); end; @@ -4127,7 +4157,7 @@ class procedure TPyDelphiObject.ExposeMethods(AClass: TClass; // Ignore methods with unhandled return type if Assigned(LRttiMethod.ReturnType) and (LRttiMethod.ReturnType.TypeKind - in [tkUnknown, tkMethod, tkPointer, tkProcedure]) + in [tkUnknown, tkMethod, tkProcedure]) then Continue; @@ -4229,7 +4259,7 @@ class procedure TPyDelphiObject.ExposeFields(AClass: TClass; Continue; // Skip if the type cannot be handled - if LRttiField.FieldType.TypeKind in [tkUnknown, tkMethod, tkPointer, tkProcedure] then + if LRttiField.FieldType.TypeKind in [tkUnknown, tkMethod, tkProcedure] then Continue; AddedFields := AddedFields + [LRttiField.Name]; @@ -4315,7 +4345,7 @@ class procedure TPyDelphiObject.ExposeProperties(AClass: TClass; else begin // Skip if the type cannot be handled - if LRttiProperty.PropertyType.TypeKind in [tkUnknown, tkPointer, tkMethod, tkProcedure] then + if LRttiProperty.PropertyType.TypeKind in [tkUnknown, tkMethod, tkProcedure] then Continue; // Create the exposed property @@ -4399,7 +4429,7 @@ class procedure TPyDelphiObject.ExposeIndexedProperties(AClass: TClass; Continue; // Skip if the type cannot be handled - if LRttiProperty.PropertyType.TypeKind in [tkUnknown, tkPointer, tkMethod, tkProcedure] then + if LRttiProperty.PropertyType.TypeKind in [tkUnknown, tkMethod, tkProcedure] then Continue; AddedProperties := AddedProperties + [LRttiProperty.Name]; diff --git a/Tests/WrapDelphiTest.pas b/Tests/WrapDelphiTest.pas index 384584fa..350b0bb2 100644 --- a/Tests/WrapDelphiTest.pas +++ b/Tests/WrapDelphiTest.pas @@ -71,6 +71,7 @@ TTestRttiAccess = class procedure VarArgsProc1(var I: Integer); function VarArgsFunc1(var I: Integer): Integer; procedure VarArgsProc2(var I: Integer; var S: string); + function PlaceInNewList(PyObj: PPyObject): PPyObject; property Indexed[I: Integer]: Integer read GetIndexed write SetIndexed; property Indexed2[S1, S2: string]: string read GetIndexed2 write SetIndexed2; default; class var ClassField: string; @@ -157,6 +158,8 @@ TTestWrapDelphi = class(TObject) procedure TestIndexedProperties; [Test] procedure TestVarArgs; + [Test] + procedure TestPPyObjects; end; implementation @@ -427,6 +430,15 @@ procedure TTestWrapDelphi.TestPassVariantArray; Assert.Pass; end; +procedure TTestWrapDelphi.TestPPyObjects; +var + List: Variant; +begin + List := rtti_var.PlaceInNewList('abc'); + Assert.IsTrue(VarIsPythonList(List)); + Assert.AreEqual(List.GetItem(0), 'abc'); +end; + procedure TTestWrapDelphi.TestRecord; begin Rtti_rec.StringField := 'abcd'; @@ -615,6 +627,16 @@ procedure TTestRttiAccess.PassVariantArray(const Value: Variant); Assert.IsTrue(VarIsArray(Value) and (VarArrayHighBound(Value, 1) = 9)); end; +function TTestRttiAccess.PlaceInNewList(PyObj: PPyObject): PPyObject; +begin + with GetPythonEngine do + begin + Result := PyList_New(1); + Py_XIncRef(PyObj); + PyList_SetItem(Result, 0, PyObj); + end; +end; + procedure TTestRttiAccess.SellFruits(const AFruits: TFruitDynArray); var Fruit: TFruit; From b2512c6334e9495c0b178e1c07866220dac71c3e Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sat, 13 Apr 2024 05:57:41 +0100 Subject: [PATCH 10/55] Improve the handling of python bytes and AnsiStrings --- Source/PythonEngine.pas | 19 ++++++++----------- Source/WrapDelphi.pas | 12 ++++++++++-- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 968452a6..c3e7745e 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -5414,25 +5414,22 @@ procedure TPythonEngine.RaiseError; function TPythonEngine.PyObjectAsString( obj : PPyObject ) : string; var S : PPyObject; - W : UnicodeString; begin Result := ''; if not Assigned( obj ) then Exit; if PyUnicode_Check(obj) then + Result := string(PyUnicodeAsString(obj)) + else if PyBytes_Check(obj) then + Result := string(UTF8ToString(PyBytesAsAnsiString(obj))) + else begin - W := PyUnicodeAsString(obj); - Result := string(W); - Exit; - end; - S := PyObject_Str( obj ); - if Assigned(S) and PyUnicode_Check(S) then - begin - W := PyUnicodeAsString(S); - Result := string(W); + S := PyObject_Str( obj ); + if Assigned(S) and PyUnicode_Check(S) then + Result := string(PyUnicodeAsString(S)); + Py_XDECREF(S); end; - Py_XDECREF(S); end; procedure TPythonEngine.DoRedirectIO; diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index 04ecc415..b2cea15e 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -2033,8 +2033,16 @@ function SimplePythonToValue(PyValue: PPyObject; TypeInfo: PTypeInfo; end else ErrMsg := rs_ErrPythonToValue; - tkString, tkWString, tkUString, - tkLString, tkChar, tkWChar: + tkString, tkLString, tkChar: + begin + if GetPythonEngine.PyBytes_Check(PyValue) then + V := TValue.From(GetPythonEngine.PyBytesAsAnsiString(PyValue)) + else + V := GetPythonEngine.PyObjectAsString(PyValue); + Value := V.Cast(TypeInfo); + Result := True; + end; + tkWString, tkUString, tkWChar: begin V := GetPythonEngine.PyObjectAsString(PyValue); Value := V.Cast(TypeInfo); From bddf7c8460ee4ee084a3fffdc3bad82f37dc94e9 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Fri, 17 May 2024 21:55:15 +0300 Subject: [PATCH 11/55] Fix Initialization for python versions 3.8 and 3.9. Added error handling for initialization errors. --- Source/PythonEngine.pas | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index c3e7745e..fa92d7be 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -1010,8 +1010,8 @@ PyConfig = record ConfigOffests: TConfigOffsets = {$IFDEF MSWINDOWS} {$IFDEF CPU64BITS} - ((8, 80, 88, 144, 156, 160, 164, 172, 216, 104, 232, 240, 248, 264), - (8, 80, 88, 144, 156, 160, 164, 172, 216, 104, 232, 240, 248, 264), + ((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, 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), @@ -3036,6 +3036,8 @@ implementation SPyConvertionError = 'Conversion Error: %s expects a %s Python object'; SPyExcStopIteration = 'Stop Iteration'; SPyExcSystemError = 'Unhandled SystemExit exception. Code: %s'; +SPyInitFailed = 'Python initialization failed: %s'; +SPyInitFailedUnknown = 'Unknown initialization error'; (*******************************************************) (** **) @@ -4720,6 +4722,8 @@ procedure TPythonEngine.Initialize; var i : Integer; Config: PyConfig; + Status: PyStatus; + ErrMsg: string; begin if Assigned(gPythonEngine) then raise Exception.Create('There is already one instance of TPythonEngine running' ); @@ -4764,15 +4768,30 @@ procedure TPythonEngine.Initialize; if Assigned(FOnConfigInit) then FOnConfigInit(Self, Config); - Py_InitializeFromConfig(Config); + Status := Py_InitializeFromConfig(Config); + FInitialized := Py_IsInitialized() <> 0 finally PyConfig_Clear(Config); end; - if Assigned(Py_IsInitialized) then - FInitialized := Py_IsInitialized() <> 0 - else - FInitialized := True; + 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 ); + {$ELSE} + WriteLn(ErrOutput, ErrMsg); + {$ENDIF} + if FatalAbort then + Quit + else + raise Exception.Create(ErrMsg); + end; + InitSysPath; if RedirectIO and Assigned(FIO) then DoRedirectIO; From 0599a8851ee2176c0fb01e17f7b889ce7b3cfdda Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sun, 19 May 2024 01:16:41 +0300 Subject: [PATCH 12/55] Corrected the definition of PyModuleDef. --- Source/PythonEngine.pas | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index fa92d7be..0e0969a7 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -611,6 +611,15 @@ TPythonVersionProp = record m_copy : PPyObject; end; + // Slots are used for two phase module initialization + // which is not yet implemented + + PPyModuleDef_Slot = ^PyModuleDef_Slot; + PyModuleDef_Slot = {$IFDEF CPUX86}packed{$ENDIF} record + slot: integer; + value: Pointer; + end; + PPyModuleDef = ^PyModuleDef; PyModuleDef = {$IFDEF CPUX86}packed{$ENDIF} record m_base : PyModuleDef_Base; @@ -618,7 +627,7 @@ TPythonVersionProp = record m_doc : PAnsiChar; m_size : NativeInt; m_methods : PPyMethodDef; - m_reload : inquiry; + m_slots : PPyModuleDef_Slot; m_traverse : traverseproc; m_clear : inquiry; m_free : inquiry; From c113a4ffaef3738019c1726575908dff9a4b87b4 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sat, 25 May 2024 07:45:46 +0100 Subject: [PATCH 13/55] Check for DelphiObject = nil immediately in TPyDelphiObject.SetAttrO and TPyDelphiObject.GetAttrO --- Source/WrapDelphi.pas | 62 ++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index b2cea15e..970bcb48 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -1026,7 +1026,8 @@ implementation rs_ErrAttrGet = 'Error in getting property "%s".'#$A'Error: %s'; rs_UnknownAttribute = 'Unknown attribute'; rs_ErrIterSupport = 'Wrapper %s does not support iterators'; - rs_ErrAttrSetr = 'Error in setting property %s'#$A'Error: %s'; + rs_ErrAttrSet = 'Error in setting property %s'#$A'Error: %s'; + rs_ErrObjectDestroyed = 'Trying to access a destroyed pascal object'; rs_IncompatibleClasses = 'Incompatible classes'; rs_IncompatibleRecords = 'Incompatible record types'; rs_IncompatibleInterfaces = 'Incompatible interfaces'; @@ -1550,7 +1551,7 @@ function TExposedGetSet.SetterWrapper(AObj, AValue: PPyObject; AContext: Pointer if Result <> 0 then with GetPythonEngine do PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrAttrSetr, [FRttiMember.Name, ErrMsg]))); + PyUnicodeFromString(Format(rs_ErrAttrSet, [FRttiMember.Name, ErrMsg]))); end; { TExposedField } @@ -1646,7 +1647,7 @@ function TExposedEvent.SetterWrapper(AObj, AValue: PPyObject; AContext: Pointer) if Result <> 0 then with GetPythonEngine do PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrAttrSetr, [FRttiMember.Name, ErrMsg]))); + PyUnicodeFromString(Format(rs_ErrAttrSet, [FRttiMember.Name, ErrMsg]))); end; { TExposedIndexedProperty } @@ -3434,7 +3435,7 @@ function TPyRttiObject.SetAttrO(key, value: PPyObject): Integer; if Result <> 0 then with GetPythonEngine do PyErr_SetObject(PyExc_AttributeError^, PyUnicodeFromString( - Format(rs_ErrAttrSetr, [KeyName, ErrMsg]))); + Format(rs_ErrAttrSet, [KeyName, ErrMsg]))); end; function TPyRttiObject.SetProps(args, keywords: PPyObject): PPyObject; @@ -3543,6 +3544,7 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject; var KeyName: string; ErrMsg : string; + PyEngine: TPythonEngine; {$IFNDEF EXTENDED_RTTI} {$IFNDEF FPC} Info: PMethodInfoHeader; @@ -3554,16 +3556,24 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject; RttiType: TRttiStructuredType; {$ENDIF} begin - Result := inherited GetAttrO(key); - if GetPythonEngine.PyErr_Occurred = nil then Exit; // We found what we wanted + Result := nil; + PyEngine := GetPythonEngine; - // should not happen - if not (Assigned(DelphiObject) and - CheckStrAttribute(Key, 'GetAttrO key parameter', KeyName)) - then + // If DelphiObject is nil Exit immediately with an error + if not Assigned(DelphiObject) then + begin + PyEngine.PyErr_SetObject(PyEngine.PyExc_AttributeError^, + PyEngine.PyUnicodeFromString(rs_ErrObjectDestroyed)); Exit; + end; + + if not CheckStrAttribute(Key, 'GetAttrO key parameter', KeyName) then + Exit; // should not happen + + Result := inherited GetAttrO(key); + if PyEngine.PyErr_Occurred = nil then Exit; // We found what we wanted - GetPythonEngine.PyErr_Clear; + PyEngine.PyErr_Clear; {$IFDEF EXTENDED_RTTI} // Use RTTI if Assigned(DelphiObject) then begin @@ -3620,17 +3630,17 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject; {$ELSE FPC} if GetTypeData(PropInfo^.PropType^)^.BaseType^ = TypeInfo(Boolean) then {$ENDIF FPC} - Result := GetPythonEngine.VariantAsPyObject(Boolean(GetOrdProp(Self.DelphiObject, PropInfo))) + Result := PyEngine.VariantAsPyObject(Boolean(GetOrdProp(Self.DelphiObject, PropInfo))) else {$IFDEF FPC} - Result := GetPythonEngine.PyUnicodeFromString(GetEnumName(PropInfo^.PropType, + Result := PyEngine.PyUnicodeFromString(GetEnumName(PropInfo^.PropType, {$ELSE FPC} - Result := GetPythonEngine.PyUnicodeFromString(GetEnumName(PropInfo^.PropType^, + Result := PyEngine.PyUnicodeFromString(GetEnumName(PropInfo^.PropType^, {$ENDIF FPC} GetOrdProp(Self.DelphiObject, PropInfo))); end end else - Result := GetPythonEngine.VariantAsPyObject(GetPropValue(DelphiObject, PropInfo)); + Result := PyEngine.VariantAsPyObject(GetPropValue(DelphiObject, PropInfo)); end; except on E: Exception do begin @@ -3640,9 +3650,8 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject; end; {$ENDIF} if not Assigned(Result) then - with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrAttrGet,[KeyName, ErrMsg]))); + PyEngine.PyErr_SetObject (PyEngine.PyExc_AttributeError^, + PyEngine.PyUnicodeFromString(Format(rs_ErrAttrGet,[KeyName, ErrMsg]))); end; function TPyDelphiObject.GetContainerAccess: TContainerAccess; @@ -3944,11 +3953,16 @@ function TPyDelphiObject.SetAttrO(key, value: PPyObject): Integer; Result := -1; PyEngine := GetPythonEngine; - // should not happen - if not (Assigned(DelphiObject) and - CheckStrAttribute(Key, 'SetAttrO key parameter', KeyName)) - then + // If DelphiObject is nil Exit immediately with an error + if not Assigned(DelphiObject) then + begin + PyEngine.PyErr_SetObject(PyEngine.PyExc_AttributeError^, + PyEngine.PyUnicodeFromString(rs_ErrObjectDestroyed)); Exit; + end; + + if not CheckStrAttribute(Key, 'SetAttrO key parameter', KeyName) then + Exit; // should not happen // Only call the inherited method at this stage if the attribute exists PyObj := PyEngine.PyObject_GenericGetAttr(GetSelf, key); @@ -3989,8 +4003,8 @@ function TPyDelphiObject.SetAttrO(key, value: PPyObject): Integer; Result := inherited SetAttrO(key, value); if Result <> 0 then with PyEngine do - PyErr_SetObject(PyEngine.PyExc_AttributeError^, PyUnicodeFromString( - Format(rs_ErrAttrSetr, [KeyName, ErrMsg]))); + PyErr_SetObject(PyExc_AttributeError^, PyUnicodeFromString( + Format(rs_ErrAttrSet, [KeyName, ErrMsg]))); end; procedure TPyDelphiObject.SetDelphiObject(const Value: TObject); From 7eb051e1f708f492fef50cda796bcb5000f2cad1 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sat, 25 May 2024 07:56:14 +0100 Subject: [PATCH 14/55] GenericSetAttrO raises the AttributeError on failure. No need to raise it again. --- Source/WrapDelphi.pas | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index 970bcb48..96bc881b 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -3559,7 +3559,7 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject; Result := nil; PyEngine := GetPythonEngine; - // If DelphiObject is nil Exit immediately with an error + // If DelphiObject is nil exit immediately with an error if not Assigned(DelphiObject) then begin PyEngine.PyErr_SetObject(PyEngine.PyExc_AttributeError^, @@ -3953,7 +3953,7 @@ function TPyDelphiObject.SetAttrO(key, value: PPyObject): Integer; Result := -1; PyEngine := GetPythonEngine; - // If DelphiObject is nil Exit immediately with an error + // If DelphiObject is nil exit immediately with an error if not Assigned(DelphiObject) then begin PyEngine.PyErr_SetObject(PyEngine.PyExc_AttributeError^, @@ -4001,10 +4001,6 @@ function TPyDelphiObject.SetAttrO(key, value: PPyObject): Integer; // Subclasses have a __dict__ and can set extra fields if Result <> 0 then Result := inherited SetAttrO(key, value); - if Result <> 0 then - with PyEngine do - PyErr_SetObject(PyExc_AttributeError^, PyUnicodeFromString( - Format(rs_ErrAttrSet, [KeyName, ErrMsg]))); end; procedure TPyDelphiObject.SetDelphiObject(const Value: TObject); From 4426ae3fdfb302cd048110d92a2dc6d1aeda99bf Mon Sep 17 00:00:00 2001 From: pyscripter Date: Tue, 28 May 2024 13:35:10 +0300 Subject: [PATCH 15/55] Changed then __owned__ docstring to reflect that it is now a read/write property. --- Source/WrapDelphi.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index 96bc881b..2ea65440 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -3835,7 +3835,7 @@ class procedure TPyDelphiObject.RegisterGetSets(PythonType: TPythonType); PythonType.AddGetSet('__bound__', @TPyDelphiObject.Get_Bound, nil, 'Returns True if the wrapper is still bound to the Delphi instance.', nil); PythonType.AddGetSet('__owned__', @TPyDelphiObject.Get_Owned, @TPyDelphiObject.Set_Owned, - 'Returns True if the wrapper owns the Delphi instance.', nil); + 'Boolean read/write property that determines weather the wrapper owns the Delphi instance.', nil); end; class procedure TPyDelphiObject.RegisterMethods(PythonType: TPythonType); From 38b228f7fd5c91510642f9d1ab9800965b468369 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Fri, 31 May 2024 22:05:03 +0300 Subject: [PATCH 16/55] Use LoadDLLinExtensionModule instead of LoadDLL in RttiModule/uMain.pas --- Modules/DemoModule/uMain.pas | 1 - Modules/RttiModule/uMain.pas | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Modules/DemoModule/uMain.pas b/Modules/DemoModule/uMain.pas index 89ef3d22..8df2b082 100644 --- a/Modules/DemoModule/uMain.pas +++ b/Modules/DemoModule/uMain.pas @@ -49,7 +49,6 @@ function PyInit_DemoModule: PPyObject; try gEngine := TPythonEngine.Create(nil); gEngine.AutoFinalize := False; - gEngine.UseLastKnownVersion := False; gEngine.UseLastKnownVersion := True; gModule := TPythonModule.Create(nil); diff --git a/Modules/RttiModule/uMain.pas b/Modules/RttiModule/uMain.pas index 5afc2b19..386b522f 100644 --- a/Modules/RttiModule/uMain.pas +++ b/Modules/RttiModule/uMain.pas @@ -34,10 +34,7 @@ function PyInit_DemoModule: PPyObject; try gEngine := TPythonEngine.Create(nil); gEngine.AutoFinalize := False; - gEngine.UseLastKnownVersion := False; - // Adapt to the desired python version - gEngine.RegVersion := '3.8'; - gEngine.DllName := 'python38.dll'; + gEngine.UseLastKnownVersion := True; gModule := TPythonModule.Create(nil); gModule.Engine := gEngine; @@ -47,7 +44,7 @@ function PyInit_DemoModule: PPyObject; gDelphiWrapper.Engine := gEngine; gDelphiWrapper.Module := gModule; - gEngine.LoadDll; + gEngine.LoadDllInExtensionModule; Py := gDelphiWrapper.Wrap(DelphiFunctions, TObjectOwnership.soReference); gModule.SetVar('delphi_funcs', Py); gEngine.Py_DecRef(Py); From b402379ff9cda88dbc612af8a28352e44cd32418 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Thu, 20 Jun 2024 11:52:34 +0300 Subject: [PATCH 17/55] Fix backward compatibility --- Source/WrapDelphi.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index 2ea65440..638e524a 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -553,16 +553,16 @@ TPyDelphiObject = class (TPyInterfacedObject, IFreeNotificationSubscriber) class function ExcludedExposedMembers(APythonType: TPythonType): TArray; virtual; class procedure ExposeMethods(AClass: TClass; NearestAncestorClass: TClass; APythonType: TPythonType; APyDelphiWrapper: TPyDelphiWrapper; - AExcludedMethodNames: TArray = []); + AExcludedMethodNames: TArray = nil); class procedure ExposeFields(AClass: TClass; NearestAncestorClass: TClass; APythonType: TPythonType; APyDelphiWrapper: TPyDelphiWrapper; - AExcludedFieldNames: TArray = []); + AExcludedFieldNames: TArray = nil); class procedure ExposeProperties(AClass: TClass; NearestAncestorClass: TClass; APythonType: TPythonType; APyDelphiWrapper: TPyDelphiWrapper; - AExcludedPropertyNames: TArray = []); + AExcludedPropertyNames: TArray = nil); class procedure ExposeIndexedProperties(AClass: TClass; NearestAncestorClass: TClass; APythonType: TPythonType; APyDelphiWrapper: TPyDelphiWrapper; - AExcludedPropertyNames: TArray = []); + AExcludedPropertyNames: TArray = nil); {$ENDIF EXTENDED_RTTI} public PyDelphiWrapper : TPyDelphiWrapper; From ec485c100453c8d9d2029cef9574e935c822edfe Mon Sep 17 00:00:00 2001 From: pyscripter Date: Thu, 20 Jun 2024 23:43:52 +0300 Subject: [PATCH 18/55] TPythonTread.Execute should be protected. --- Source/PythonEngine.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 0e0969a7..d16b814c 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -2906,9 +2906,9 @@ TPythonThread = class(TThread) private class threadvar f_savethreadstate: PPyThreadState; + protected // Do not overwrite Execute! Use ExecuteWithPython instead! procedure Execute; override; - protected procedure ExecuteWithPython; virtual; abstract; function InterpreterConfig: PyInterpreterConfig; virtual; public From ad3d8c7140812ea36924cb862e1598a4828aab20 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sun, 23 Jun 2024 11:59:48 +0300 Subject: [PATCH 19/55] Utf8 encoding of docstrings. See https://github.com/Embarcadero/DelphiVCL4Python/issues/84 --- Source/WrapDelphi.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index 638e524a..0a863e3f 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -4290,7 +4290,7 @@ class procedure TPyDelphiObject.ExposeFields(AClass: TClass; if Assigned(PyDocServer) and PyDocServer.Initialized and PyDocServer.ReadMemberDocStr(LRttiField, LDocStr) then - LExposedField.DocString := AnsiString(LDocStr); + LExposedField.DocString := Utf8Encode(LDocStr); // Keep it alive until the Wrapper is Finalized APyDelphiWrapper.fExposedMembers.Add(LExposedField); @@ -4377,7 +4377,7 @@ class procedure TPyDelphiObject.ExposeProperties(AClass: TClass; if Assigned(PyDocServer) and PyDocServer.Initialized and PyDocServer.ReadMemberDocStr(LRttiProperty, LDocStr) then - LExposedProperty.DocString := AnsiString(LDocStr); + LExposedProperty.DocString := Utf8Encode(LDocStr); // Keep it alive until the Wrapper is Finalized APyDelphiWrapper.fExposedMembers.Add(LExposedProperty); @@ -4460,7 +4460,7 @@ class procedure TPyDelphiObject.ExposeIndexedProperties(AClass: TClass; if Assigned(PyDocServer) and PyDocServer.Initialized and PyDocServer.ReadMemberDocStr(LRttiProperty, LDocStr) then - LExposedProperty.DocString := AnsiString(LDocStr); + LExposedProperty.DocString := Utf8Encode(LDocStr); // Keep it alive until the Wrapper is Finalized APyDelphiWrapper.fExposedMembers.Add(LExposedProperty); From e7b3a0a541e04fa7ea638fd21dedc1a6255dc8cd Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sun, 23 Jun 2024 18:14:08 +0300 Subject: [PATCH 20/55] Fix Screen.Realign docstring See https://github.com/Embarcadero/DelphiVCL4Python/issues/84 --- Source/vcl/WrapVclForms.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/vcl/WrapVclForms.pas b/Source/vcl/WrapVclForms.pas index 0a373dfa..fd0799c3 100644 --- a/Source/vcl/WrapVclForms.pas +++ b/Source/vcl/WrapVclForms.pas @@ -1072,7 +1072,7 @@ class procedure TPyDelphiScreen.RegisterMethods(PythonType: TPythonType); 'Allows forms to be aligned in the screen.'); PythonType.AddMethod('Realign', @TPyDelphiScreen.Realign_Wrapper, 'TScreen.Realign()'#10 + - 'Realigns the screen’s forms according to their Align properties.'); + 'Realigns the screen''s forms according to their Align properties.'); PythonType.AddMethod('ResetFonts', @TPyDelphiScreen.ResetFonts_Wrapper, 'TScreen.ResetFonts()'#10 + 'Reinitializes the fonts listed in the Fonts property.'); From 6b2cc0eb1eb48aa6d823da5c8b3353ac672fe56e Mon Sep 17 00:00:00 2001 From: pyscripter Date: Fri, 28 Jun 2024 19:52:49 +0300 Subject: [PATCH 21/55] Fix #477 --- Source/PythonEngine.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index d16b814c..d2ec67df 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -4668,7 +4668,7 @@ procedure TPythonEngine.Initialize; PWSL := PPyWideStringList(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.module_search_paths]); - Paths := FPythonPath.Split([PathSep]); + Paths := string(FPythonPath).Split([PathSep]); for I := 0 to Length(Paths) - 1 do begin if (Paths[I] = '') and (I > 0) then @@ -9781,7 +9781,7 @@ function StringToWCharTString(Str: string): WcharTString; {$IFDEF POSIX} Result := UnicodeStringToUCS4String(UnicodeString(Str)); {$ELSE} - Result := Str; + Result := WcharTString(Str); {$ENDIF} end; From 847039615dab9146239414367430b09c43987e3c Mon Sep 17 00:00:00 2001 From: pyscripter Date: Mon, 8 Jul 2024 22:41:59 +0300 Subject: [PATCH 22/55] Fix #478 --- Source/vcl/WrapVclComCtrls.pas | 50 ++++++++++++---------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/Source/vcl/WrapVclComCtrls.pas b/Source/vcl/WrapVclComCtrls.pas index 18c161e8..c7b90fac 100644 --- a/Source/vcl/WrapVclComCtrls.pas +++ b/Source/vcl/WrapVclComCtrls.pas @@ -731,7 +731,8 @@ TPyDelphiListView = class(TPyDelphiCustomListView) function CustomDrawTargetToPython(const ACustomDrawTarget: TCustomDrawTarget): PPyObject; function CustomDrawStageToPython(const ACustomDrawStage: TCustomDrawStage): PPyObject; - function CustomDrawStateToPython(const ACustomDrawState: TCustomDrawState): PPyObject; + function CustomDrawStateToPython(const ACustomDrawState: TCustomDrawState; + DelphiWrapper: TPyDelphiWrapper): PPyObject; function ItemChangeToPython(const AItemChange: TItemChange): PPyObject; function ItemStateToPython(const AItemState: TItemState): PPyObject; @@ -742,8 +743,10 @@ TPyDelphiListView = class(TPyDelphiCustomListView) implementation uses - WrapDelphiTypes, WrapDelphiWindows, - Vcl.ExtCtrls; + System.Rtti, + Vcl.ExtCtrls, + WrapDelphiTypes, + WrapDelphiWindows; { Register the wrappers, the globals and the constants } type @@ -780,31 +783,14 @@ function CustomDrawStageToPython(const ACustomDrawStage: TCustomDrawStage): PPyO Ord(ACustomDrawStage))); end; -function CustomDrawStateToPython(const ACustomDrawState: TCustomDrawState): PPyObject; - - procedure Append(const AList: PPyObject; const AString: string); - var - LItem: PPyObject; - begin - with GetPythonEngine do begin - LItem := PyUnicodeFromString(AString); - PyList_Append(AList, LItem); - Py_XDecRef(LItem); - end; - end; - +function CustomDrawStateToPython(const ACustomDrawState: TCustomDrawState; + DelphiWrapper: TPyDelphiWrapper): PPyObject; var - LCompType: PTypeInfo; - LMin: integer; - LMax: integer; - LState: integer; + ErrMsg: string; + Value: TValue; begin - Result := GetPythonEngine().PyList_New(0); - LCompType := GetTypeData(TypeInfo(TCustomDrawState)).CompType^; - LMin := LCompType^.TypeData^.MinValue; - LMax := LCompType^.TypeData^.MaxValue; - for LState := LMin to LMax do - Append(Result, GetEnumName(LCompType, LState)); + Value := TValue.From(ACustomDrawState); + Result := TValueToPyObject(Value, DelphiWrapper, ErrMsg); end; function ItemChangeToPython(const AItemChange: TItemChange): PPyObject; @@ -2203,7 +2189,7 @@ procedure TTVCustomDrawItemEventHandler.DoEvent(Sender: TCustomTreeView; LPyTuple := PyTuple_New(4); PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyNode); - PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State)); + PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State, PyDelphiWrapper)); PyTuple_SetItem(LPyTuple, 3, LPyDefaultDraw); try LPyResult := PyObject_CallObject(Callable, LPyTuple); @@ -2306,7 +2292,7 @@ procedure TTVAdvancedCustomDrawItemEventHandler.DoEvent(Sender: TCustomTreeView; LPyTuple := PyTuple_New(6); PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyNode); - PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State)); + PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State, PyDelphiWrapper)); PyTuple_SetItem(LPyTuple, 3, CustomDrawStageToPython(Stage)); PyTuple_SetItem(LPyTuple, 4, LPyPaintImages); PyTuple_SetItem(LPyTuple, 5, LPyDefaultDraw); @@ -3098,7 +3084,7 @@ procedure TLVCustomDrawItemEventHandler.DoEvent(Sender: TCustomListView; LPyTuple := PyTuple_New(4); PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyItem); - PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State)); + PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State, PyDelphiWrapper)); PyTuple_SetItem(LPyTuple, 3, LPyDefaultDraw); try LPyResult := PyObject_CallObject(Callable, LPyTuple); @@ -3150,7 +3136,7 @@ procedure TLVCustomDrawSubItemEventHandler.DoEvent(Sender: TCustomListView; PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyItem); PyTuple_SetItem(LPyTuple, 2, PyLong_FromLong(SubItem)); - PyTuple_SetItem(LPyTuple, 3, CustomDrawStateToPython(State)); + PyTuple_SetItem(LPyTuple, 3, CustomDrawStateToPython(State, PyDelphiWrapper)); PyTuple_SetItem(LPyTuple, 4, LPyDefaultDraw); try LPyResult := PyObject_CallObject(Callable, LPyTuple); @@ -3251,7 +3237,7 @@ procedure TLVAdvancedCustomDrawItemEventHandler.DoEvent(Sender: TCustomListView; LPyTuple := PyTuple_New(5); PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyItem); - PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State)); + PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State, PyDelphiWrapper)); PyTuple_SetItem(LPyTuple, 3, CustomDrawStageToPython(Stage)); PyTuple_SetItem(LPyTuple, 4, LPyDefaultDraw); try @@ -3304,7 +3290,7 @@ procedure TLVAdvancedCustomDrawSubItemEventHandler.DoEvent( PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyItem); PyTuple_SetItem(LPyTuple, 2, PyLong_FromLong(SubItem)); - PyTuple_SetItem(LPyTuple, 3, CustomDrawStateToPython(State)); + PyTuple_SetItem(LPyTuple, 3, CustomDrawStateToPython(State, PyDelphiWrapper)); PyTuple_SetItem(LPyTuple, 4, CustomDrawStageToPython(Stage)); PyTuple_SetItem(LPyTuple, 5, LPyDefaultDraw); try From fc96036b96f6504f07c9be917f28ad14c6cc5fb4 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Mon, 8 Jul 2024 22:56:26 +0300 Subject: [PATCH 23/55] Improve previous commit. --- Source/WrapDelphi.pas | 2 ++ Source/vcl/WrapVclComCtrls.pas | 20 +++++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index 0a863e3f..70b5b837 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -991,6 +991,8 @@ TPyDelphiWrapper = class(TEngineClient, IFreeNotificationSubscriber) {$IFDEF EXTENDED_RTTI} function CreateVarParam(PyDelphiWrapper : TPyDelphiWrapper; const AValue: TValue) : PPyObject; overload; + function SimpleValueToPython(const Value: TValue; + out ErrMsg: string): PPyObject; function TValueToPyObject(const Value: TValue; DelphiWrapper: TPyDelphiWrapper; out ErrMsg: string): PPyObject; function PyObjectToTValue(PyArg : PPyObject; ArgType: TRttiType; diff --git a/Source/vcl/WrapVclComCtrls.pas b/Source/vcl/WrapVclComCtrls.pas index c7b90fac..aff247eb 100644 --- a/Source/vcl/WrapVclComCtrls.pas +++ b/Source/vcl/WrapVclComCtrls.pas @@ -731,8 +731,7 @@ TPyDelphiListView = class(TPyDelphiCustomListView) function CustomDrawTargetToPython(const ACustomDrawTarget: TCustomDrawTarget): PPyObject; function CustomDrawStageToPython(const ACustomDrawStage: TCustomDrawStage): PPyObject; - function CustomDrawStateToPython(const ACustomDrawState: TCustomDrawState; - DelphiWrapper: TPyDelphiWrapper): PPyObject; + function CustomDrawStateToPython(const ACustomDrawState: TCustomDrawState): PPyObject; function ItemChangeToPython(const AItemChange: TItemChange): PPyObject; function ItemStateToPython(const AItemState: TItemState): PPyObject; @@ -783,14 +782,13 @@ function CustomDrawStageToPython(const ACustomDrawStage: TCustomDrawStage): PPyO Ord(ACustomDrawStage))); end; -function CustomDrawStateToPython(const ACustomDrawState: TCustomDrawState; - DelphiWrapper: TPyDelphiWrapper): PPyObject; +function CustomDrawStateToPython(const ACustomDrawState: TCustomDrawState): PPyObject; var ErrMsg: string; Value: TValue; begin Value := TValue.From(ACustomDrawState); - Result := TValueToPyObject(Value, DelphiWrapper, ErrMsg); + Result := SimpleValueToPython(Value, ErrMsg); end; function ItemChangeToPython(const AItemChange: TItemChange): PPyObject; @@ -2189,7 +2187,7 @@ procedure TTVCustomDrawItemEventHandler.DoEvent(Sender: TCustomTreeView; LPyTuple := PyTuple_New(4); PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyNode); - PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State, PyDelphiWrapper)); + PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State)); PyTuple_SetItem(LPyTuple, 3, LPyDefaultDraw); try LPyResult := PyObject_CallObject(Callable, LPyTuple); @@ -2292,7 +2290,7 @@ procedure TTVAdvancedCustomDrawItemEventHandler.DoEvent(Sender: TCustomTreeView; LPyTuple := PyTuple_New(6); PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyNode); - PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State, PyDelphiWrapper)); + PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State)); PyTuple_SetItem(LPyTuple, 3, CustomDrawStageToPython(Stage)); PyTuple_SetItem(LPyTuple, 4, LPyPaintImages); PyTuple_SetItem(LPyTuple, 5, LPyDefaultDraw); @@ -3084,7 +3082,7 @@ procedure TLVCustomDrawItemEventHandler.DoEvent(Sender: TCustomListView; LPyTuple := PyTuple_New(4); PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyItem); - PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State, PyDelphiWrapper)); + PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State)); PyTuple_SetItem(LPyTuple, 3, LPyDefaultDraw); try LPyResult := PyObject_CallObject(Callable, LPyTuple); @@ -3136,7 +3134,7 @@ procedure TLVCustomDrawSubItemEventHandler.DoEvent(Sender: TCustomListView; PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyItem); PyTuple_SetItem(LPyTuple, 2, PyLong_FromLong(SubItem)); - PyTuple_SetItem(LPyTuple, 3, CustomDrawStateToPython(State, PyDelphiWrapper)); + PyTuple_SetItem(LPyTuple, 3, CustomDrawStateToPython(State)); PyTuple_SetItem(LPyTuple, 4, LPyDefaultDraw); try LPyResult := PyObject_CallObject(Callable, LPyTuple); @@ -3237,7 +3235,7 @@ procedure TLVAdvancedCustomDrawItemEventHandler.DoEvent(Sender: TCustomListView; LPyTuple := PyTuple_New(5); PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyItem); - PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State, PyDelphiWrapper)); + PyTuple_SetItem(LPyTuple, 2, CustomDrawStateToPython(State)); PyTuple_SetItem(LPyTuple, 3, CustomDrawStageToPython(Stage)); PyTuple_SetItem(LPyTuple, 4, LPyDefaultDraw); try @@ -3290,7 +3288,7 @@ procedure TLVAdvancedCustomDrawSubItemEventHandler.DoEvent( PyTuple_SetItem(LPyTuple, 0, LPyObject); PyTuple_SetItem(LPyTuple, 1, LPyItem); PyTuple_SetItem(LPyTuple, 2, PyLong_FromLong(SubItem)); - PyTuple_SetItem(LPyTuple, 3, CustomDrawStateToPython(State, PyDelphiWrapper)); + PyTuple_SetItem(LPyTuple, 3, CustomDrawStateToPython(State)); PyTuple_SetItem(LPyTuple, 4, CustomDrawStageToPython(Stage)); PyTuple_SetItem(LPyTuple, 5, LPyDefaultDraw); try From b2f9224922f6fbbc3360410827466556c13a3788 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Fri, 12 Jul 2024 14:13:12 +0300 Subject: [PATCH 24/55] Added FPC Demo35 --- Demos/FPC/Demo35/project1.lpi | 71 ++++++++++++ Demos/FPC/Demo35/project1.lpr | 144 +++++++++++++++++++++++++ Demos/FPC/Demo35/stopwatch.pas | 191 +++++++++++++++++++++++++++++++++ 3 files changed, 406 insertions(+) create mode 100644 Demos/FPC/Demo35/project1.lpi create mode 100644 Demos/FPC/Demo35/project1.lpr create mode 100644 Demos/FPC/Demo35/stopwatch.pas diff --git a/Demos/FPC/Demo35/project1.lpi b/Demos/FPC/Demo35/project1.lpi new file mode 100644 index 00000000..ff71647f --- /dev/null +++ b/Demos/FPC/Demo35/project1.lpi @@ -0,0 +1,71 @@ + + + + + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes> + <Item Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <RequiredPackages> + <Item> + <PackageName Value="P4DLaz"/> + </Item> + </RequiredPackages> + <Units> + <Unit> + <Filename Value="project1.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="stopwatch.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="project1"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf3"/> + </Debugging> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="EAbort"/> + </Item> + <Item> + <Name Value="ECodetoolError"/> + </Item> + <Item> + <Name Value="EFOpenError"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/Demos/FPC/Demo35/project1.lpr b/Demos/FPC/Demo35/project1.lpr new file mode 100644 index 00000000..0856f9f4 --- /dev/null +++ b/Demos/FPC/Demo35/project1.lpr @@ -0,0 +1,144 @@ +program project1; + +{$mode delphi}{$H+} + +uses + {$IFDEF UNIX} + cthreads, + {$ENDIF} + Classes, SysUtils, CustApp, + { you can add units after this } + Variants, + PythonEngine, + VarPyth, + stopwatch; + +var + PyEngine: TPythonEngine; + +procedure CreatePyEngine; +begin + MaskFPUExceptions(True, True); + PyEngine := TPythonEngine.Create(nil); + PyEngine.Name := 'PythonEngine'; + PyEngine.UseLastKnownVersion := False; + PyEngine.RegVersion:= '3.12'; + PyEngine.DllName:= 'python312.dll'; + PyEngine.LoadDll; +end; + +procedure DestroyEngine; +begin + PyEngine.Free; +end; + +const + N = 100000; + +type + PIntArray = ^TIntArray; + TIntArray = array[0..N - 1] of Integer; + + { TBufferProtocol } + + TBufferProtocol = class(TCustomApplication) + protected + procedure DoRun; override; + public + constructor Create(TheOwner: TComponent); override; + destructor Destroy; override; + end; + +{ TBufferProtocol } + +procedure TBufferProtocol.DoRun; +var + SW: TStopwatch; + Sum: Int64; + np: Variant; + arr: Variant; + np_arr: PPyObject; + PyBuffer: Py_buffer; + V: Variant; + I: Integer; + Count: Integer; + ArrItem: Variant; +begin + try + CreatePyEngine; + try + // Import numpy and create an array + np := Import('numpy'); + arr := np.&array(BuiltinModule.range(N)); + + // This is the slow way to iterate the array + WriteLn('Lazy but slow:'); + SW := TStopwatch.StartNew; + Sum := 0; + Count := VarPythonToVariant(arr.Length); + for I := 0 to Count - 1 do + begin + ArrItem := BuiltinModule.int(arr.GetItem(I)); + Sum := Sum + Int64(VarPythonToVariant(ArrItem)); + end; + + //for V in VarPyIterate(arr) do + // Sum := Sum + Int64(VarPythonToVariant(BuiltinModule.int(V))); + SW.Stop; + WriteLn(Format('Sum from 0 to %d = %d', [N, Sum])); + WriteLn('Elapsed ms: ' + SW.ElapsedMilliseconds.ToString); + WriteLn; + + WriteLn('Using Py_Buffer:'); + SW := TStopwatch.StartNew; + np_arr := ExtractPythonObjectFrom(arr); + PyEngine.PyObject_GetBuffer(np_arr, @PyBuffer, PyBUF_CONTIG); + PyEngine.CheckError; + try + Sum := 0; + for I := 0 to N - 1 do + Sum := Sum + PIntArray(PyBuffer.buf)^[I]; + SW.Stop; + WriteLn(Format('Sum from 0 to %d = %d', [N, Sum])); + finally + PyEngine.PyBuffer_Release(@PyBuffer); + end; + WriteLn('Elapsed ms: ' + SW.ElapsedMilliseconds.ToString); + WriteLn; + + // test write access + PIntArray(PyBuffer.buf)^[0] := 999; + if VarPythonToVariant(BuiltinModule.int(arr.GetItem(0))) = 999 then + WriteLn('Successfully modified the numpy array using Py_buffer'); + finally + DestroyEngine; + end; + except + on E: Exception do + Writeln(E.ClassName, ': ', E.Message); + end; + Readln; + // stop program loop + Terminate; +end; + +constructor TBufferProtocol.Create(TheOwner: TComponent); +begin + inherited Create(TheOwner); + StopOnException:=True; +end; + +destructor TBufferProtocol.Destroy; +begin + inherited Destroy; +end; + +var + Application: TBufferProtocol; +begin + Application:=TBufferProtocol.Create(nil); + Application.Title:='BufferProtocol'; + Application.Run; + Application.Free; +end. + diff --git a/Demos/FPC/Demo35/stopwatch.pas b/Demos/FPC/Demo35/stopwatch.pas new file mode 100644 index 00000000..d2ef8baf --- /dev/null +++ b/Demos/FPC/Demo35/stopwatch.pas @@ -0,0 +1,191 @@ +{ High frequency stop watch implemntation. + Copyright (c) 2012 by Inoussa OUEDRAOGO + + This source code is distributed under the Library GNU General Public License + with the following modification: + + - object files and libraries linked into an application may be + distributed without source code. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +{$IFDEF FPC} + {$mode objfpc}{$H+} + {$modeswitch advancedrecords} +{$ENDIF} + +{$IFDEF MSWINDOWS} + {$IFNDEF WINDOWS} + {$DEFINE WINDOWS} + {$ENDIF WINDOWS} +{$ENDIF MSWINDOWS} + +unit stopwatch; + +interface +uses + SysUtils + {$IFDEF LINUX} + ,unixtype, linux + {$ENDIF LINUX} + ; + +type + + { TStopWatch } + + TStopWatch = record + private + const + C_THOUSAND = 1000; + C_MILLION = C_THOUSAND * C_THOUSAND; + C_BILLION = C_THOUSAND * C_THOUSAND * C_THOUSAND; + TicksPerNanoSecond = 100; + TicksPerMilliSecond = 10000; + TicksPerSecond = C_BILLION div 100; + Type + TBaseMesure = + {$IFDEF WINDOWS} + Int64; + {$ENDIF WINDOWS} + {$IFDEF LINUX} + TTimeSpec; + {$ENDIF LINUX} + strict private + class var FFrequency : Int64; + class var FIsHighResolution : Boolean; + strict private + FElapsed : Int64; + FRunning : Boolean; + FStartPosition : TBaseMesure; + strict private + procedure CheckInitialization();inline; + function GetElapsedMilliseconds: Int64; + function GetElapsedTicks: Int64; + public + class function Create() : TStopWatch;static; + class function StartNew() : TStopWatch;static; + class property Frequency : Int64 read FFrequency; + class property IsHighResolution : Boolean read FIsHighResolution; + procedure Reset(); + procedure Start(); + procedure Stop(); + property ElapsedMilliseconds : Int64 read GetElapsedMilliseconds; + property ElapsedTicks : Int64 read GetElapsedTicks; + property IsRunning : Boolean read FRunning; + end; + +resourcestring + sStopWatchNotInitialized = 'The StopWatch is not initialized.'; + +implementation +{$IFDEF WINDOWS} +uses + Windows; +{$ENDIF WINDOWS} + +{ TStopWatch } + +class function TStopWatch.Create(): TStopWatch; +{$IFDEF LINUX} +var + r : TBaseMesure; +{$ENDIF LINUX} +begin + if (FFrequency = 0) then begin +{$IFDEF WINDOWS} + FIsHighResolution := QueryPerformanceFrequency(FFrequency); +{$ENDIF WINDOWS} +{$IFDEF LINUX} + FIsHighResolution := (clock_getres(CLOCK_MONOTONIC,@r) = 0); + FIsHighResolution := FIsHighResolution and (r.tv_nsec <> 0); + if (r.tv_nsec <> 0) then + FFrequency := C_BILLION div r.tv_nsec; +{$ENDIF LINUX} + end; + FillChar(Result,SizeOf(Result),0); +end; + +class function TStopWatch.StartNew() : TStopWatch; +begin + Result := TStopWatch.Create(); + Result.Start(); +end; + +procedure TStopWatch.CheckInitialization(); +begin + if (FFrequency = 0) then + raise Exception.Create(sStopWatchNotInitialized); +end; + +function TStopWatch.GetElapsedMilliseconds: Int64; +begin + {$IFDEF WINDOWS} + Result := ElapsedTicks * TicksPerMilliSecond; + {$ENDIF WINDOWS} + {$IFDEF LINUX} + Result := FElapsed div C_MILLION; + {$ENDIF LINUX} +end; + +function TStopWatch.GetElapsedTicks: Int64; +begin + CheckInitialization(); +{$IFDEF WINDOWS} + Result := (FElapsed * TicksPerSecond) div FFrequency; +{$ENDIF WINDOWS} +{$IFDEF LINUX} + Result := FElapsed div TicksPerNanoSecond; +{$ENDIF LINUX} +end; + +procedure TStopWatch.Reset(); +begin + Stop(); + FElapsed := 0; + FillChar(FStartPosition,SizeOf(FStartPosition),0); +end; + +procedure TStopWatch.Start(); +begin + if FRunning then + exit; + FRunning := True; +{$IFDEF WINDOWS} + QueryPerformanceCounter(FStartPosition); +{$ENDIF WINDOWS} +{$IFDEF LINUX} + clock_gettime(CLOCK_MONOTONIC,@FStartPosition); +{$ENDIF LINUX} +end; + +procedure TStopWatch.Stop(); +var + locEnd : TBaseMesure; + s, n : Int64; +begin + if not FRunning then + exit; + FRunning := False; +{$IFDEF WINDOWS} + QueryPerformanceCounter(locEnd); + FElapsed := FElapsed + (UInt64(locEnd) - UInt64(FStartPosition)); +{$ENDIF WINDOWS} +{$IFDEF LINUX} + clock_gettime(CLOCK_MONOTONIC,@locEnd); + if (locEnd.tv_nsec < FStartPosition.tv_nsec) then begin + s := locEnd.tv_sec - FStartPosition.tv_sec - 1; + n := C_BILLION + locEnd.tv_nsec - FStartPosition.tv_nsec; + end else begin + s := locEnd.tv_sec - FStartPosition.tv_sec; + n := locEnd.tv_nsec - FStartPosition.tv_nsec; + end; + FElapsed := FElapsed + (s * C_BILLION) + n; +{$ENDIF LINUX} +end; + +end. From a90a14f1b29aee7c7540abb6fccf49418ad40107 Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Fri, 12 Jul 2024 14:44:05 +0300 Subject: [PATCH 25/55] Fix for Linux and other non-Windows platforms. --- Demos/FPC/Demo35/project1.lpr | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Demos/FPC/Demo35/project1.lpr b/Demos/FPC/Demo35/project1.lpr index 0856f9f4..bb83f928 100644 --- a/Demos/FPC/Demo35/project1.lpr +++ b/Demos/FPC/Demo35/project1.lpr @@ -36,9 +36,13 @@ procedure DestroyEngine; N = 100000; type - PIntArray = ^TIntArray; - TIntArray = array[0..N - 1] of Integer; - + PIntArray = ^TIntArray; + {$IFDEF MSWINDOWS} + TIntArray = array[0..N - 1] of Integer; + {$ELSE} + TIntArray = array[0..N - 1] of NativeInt; + {$ENDIF} + { TBufferProtocol } TBufferProtocol = class(TCustomApplication) From b8d57195402040a7825fa81b0673537569896408 Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Sat, 13 Jul 2024 04:33:26 +0300 Subject: [PATCH 26/55] _PyInterpreterConfig_INIT is now a variable. --- Source/PythonEngine.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index d2ec67df..83c924f8 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -1068,7 +1068,7 @@ PyConfig = record PyInterpreterConfig_SHARED_GIL = 1; PyInterpreterConfig_OWN_GIL = 2; - type +type PPyInterpreterConfig = ^PyInterpreterConfig; PyInterpreterConfig = {$IFDEF CPUX86}packed{$ENDIF} record use_main_obmalloc: Integer; @@ -1080,7 +1080,7 @@ PyConfig = record gil: Integer; end; -const +var _PyInterpreterConfig_INIT: PyInterpreterConfig = ( use_main_obmalloc: 0; allow_fork: 0; @@ -9305,7 +9305,7 @@ procedure TPythonThread.Execute; finally PyGILState_Release(gilstate); end; - end else {fThreadExecMode} + end else begin gilstate := PyGILState_Ensure(); global_state := PyThreadState_Get; @@ -9328,8 +9328,8 @@ procedure TPythonThread.Execute; PyThreadState_Swap(global_state); PyGILState_Release(gilstate); end else - raise EPythonError.Create( 'Could not create a new thread state'); - end; {withinterp} + raise EPythonError.Create('Could not create a new thread state'); + end; end; end; From e57e2feffb926d624834b67955517c6b5e36a52c Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Thu, 18 Jul 2024 20:52:29 +0300 Subject: [PATCH 27/55] Fix #481 --- Source/PythonEngine.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 83c924f8..90cfca3b 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -8373,7 +8373,6 @@ function TPythonType.NewSubtypeInst( aType: PPyTypeObject; args, kwds : PPyObje begin Engine.Py_DECREF(Result); Result := nil; - obj.Free; end; end; end; From a650ee79b838d9d0574af9a677350d4fb8d0649c Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Wed, 18 Sep 2024 01:40:44 +0300 Subject: [PATCH 28/55] #483 --- Source/PythonEngine.pas | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 90cfca3b..50c5f8a6 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -3021,9 +3021,8 @@ function CleanString(const s : UnicodeString; AppendLF : Boolean = True) : Unico implementation uses -{$IFDEF FPC} StrUtils, -{$ELSE} +{$IFNDEF FPC} AnsiStrings, {$ENDIF} {$IFDEF MSWINDOWS} @@ -4660,7 +4659,7 @@ procedure TPythonEngine.Initialize; procedure SetPythonPath(var Config: PyConfig); var - Paths: TArray<string>; + Paths: TStringDynArray; I: Integer; PWSL: PPyWideStringList; begin @@ -4668,7 +4667,7 @@ procedure TPythonEngine.Initialize; PWSL := PPyWideStringList(PByte(@Config) + ConfigOffests[MinorVersion, TConfigFields.module_search_paths]); - Paths := string(FPythonPath).Split([PathSep]); + Paths := SplitString(string(FPythonPath), PathSep); for I := 0 to Length(Paths) - 1 do begin if (Paths[I] = '') and (I > 0) then From c32596f9b8bc9cc0fb80f4c4a44657fc2c2049b3 Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Mon, 23 Sep 2024 17:46:42 +0300 Subject: [PATCH 29/55] Expose EncodeString (const str: AnsiString) to Delphi and correct its implementation. --- Source/PythonEngine.pas | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 50c5f8a6..13604e26 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -2041,10 +2041,8 @@ TPythonEngine = class(TPythonInterface) function Run_CommandAsString(const command: AnsiString; mode: Integer; const FileName: string = '<string>'): string; function Run_CommandAsObject(const command: AnsiString; mode: Integer; const FileName: string = '<string>'): PPyObject; function Run_CommandAsObjectWithDict(const command: AnsiString; mode: Integer; locals, globals: PPyObject; const FileName: string = '<string>'): PPyObject; - function EncodeString (const str: UnicodeString): AnsiString; {$IFDEF FPC}overload;{$ENDIF} - {$IFDEF FPC} - function EncodeString (const str: AnsiString): AnsiString; overload; - {$ENDIF} + function EncodeString(const str: UnicodeString): AnsiString; overload; + function EncodeString(const str: AnsiString): AnsiString; overload; function EncodeWindowsFilePath(const str: string): AnsiString; procedure ExecString(const command: AnsiString; const FileName: string = '<string>'); overload; procedure ExecStrings(strings: TStrings; const FileName: string = '<string>'); overload; @@ -5538,17 +5536,15 @@ function TPythonEngine.FindClient( const aName : string ) : TEngineClient; end; end; -function TPythonEngine.EncodeString(const str: UnicodeString): AnsiString; {$IFDEF FPC}overload;{$ENDIF} +function TPythonEngine.EncodeString(const str: UnicodeString): AnsiString; begin - Result := UTF8Encode(str) + Result := UTF8Encode(str); end; -{$IFDEF FPC} -function TPythonEngine.EncodeString (const str: AnsiString): AnsiString; overload; +function TPythonEngine.EncodeString(const str: AnsiString): AnsiString; begin - Result := str; + Result := UTF8Encode(str); end; -{$ENDIF} function TPythonEngine.EncodeWindowsFilePath(const str: string): AnsiString; {PEP 529} From 311860e766683435bee7147ad7f3d5972716c0ab Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Mon, 23 Sep 2024 18:43:17 +0300 Subject: [PATCH 30/55] Fix #485 --- Source/PythonEngine.pas | 7 +- Source/WrapDelphi.pas | 137 ++++++++++++++++++++-------------------- 2 files changed, 71 insertions(+), 73 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 13604e26..a0a72e0d 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -7234,10 +7234,11 @@ procedure TError.RaiseErrorObj( const msg : AnsiString; obj : PPyObject ); end else raise Exception.Create('TError.RaiseErrorObj: I didn''t get an instance' ); - PyErr_SetObject( Error, res ); + PyErr_SetObject(Error, res); + Py_XDECREF(res); end else - PyErr_SetObject( Error, obj ); + PyErr_SetObject(Error, obj); end; function TError.Owner : TErrors; @@ -7735,7 +7736,7 @@ function TPyObject.GetBuffer(view: PPy_buffer; flags: Integer): Integer; begin view^.obj := nil; with GetPythonEngine do - PyErr_SetObject(PyExc_BufferError^, PyUnicodeFromString('')); + PyErr_SetString(PyExc_BufferError^, ''); Result := -1; end; diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index 70b5b837..67d0535c 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -1527,8 +1527,8 @@ function TExposedGetSet.GetterWrapper(AObj: PPyObject; AContext : Pointer): PPyO if not Assigned(Result) then with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrAttrGet, [FRttiMember.Name, LOutMsg]))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrAttrGet, [FRttiMember.Name, LOutMsg])))); end; function TExposedGetSet.SetterWrapper(AObj, AValue: PPyObject; AContext: Pointer): Integer; cdecl; @@ -1552,8 +1552,8 @@ function TExposedGetSet.SetterWrapper(AObj, AValue: PPyObject; AContext: Pointer if Result <> 0 then with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrAttrSet, [FRttiMember.Name, ErrMsg]))); + PyErr_SetString (PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrAttrSet, [FRttiMember.Name, ErrMsg])))); end; { TExposedField } @@ -1648,8 +1648,8 @@ function TExposedEvent.SetterWrapper(AObj, AValue: PPyObject; AContext: Pointer) if Result <> 0 then with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrAttrSet, [FRttiMember.Name, ErrMsg]))); + PyErr_SetString (PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrAttrSet, [FRttiMember.Name, ErrMsg])))); end; { TExposedIndexedProperty } @@ -1745,7 +1745,7 @@ function TPyIndexedProperty.MpAssSubscript(obj1, obj2: PPyObject) : Integer; if not FProperty.IsWritable then begin with Engine do - PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString(rs_NotWritable)); + PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString(rs_NotWritable))); Exit; end; @@ -1869,8 +1869,8 @@ class procedure TRttiEventHandler.ImplCallback(UserData: Pointer; if Assigned(PyResult) and (EventHandler.MethodType.ReturnType <> nil) and not PyObjectToTValue(PyResult, EventHandler.MethodType.ReturnType, Result, ErrMsg) then - Engine.PyErr_SetObject(Engine.PyExc_TypeError^, Engine.PyUnicodeFromString( - Format(rs_ErrInvalidRet, [string(EventHandler.PropertyInfo.Name), ErrMsg]))); + Engine.PyErr_SetString(Engine.PyExc_TypeError^, PAnsiChar(Engine.EncodeString( + Format(rs_ErrInvalidRet, [string(EventHandler.PropertyInfo.Name), ErrMsg])))); Engine.Py_XDECREF(PyResult); finally Engine.Py_XDECREF(PyArgs); @@ -1904,9 +1904,8 @@ function GlobalDelphiWrapper: TPyDelphiWrapper; procedure InvalidArguments(const MethName, ErrMsg : string); begin with GetPythonEngine do - PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString( - Format(rs_ErrInvalidArgs, - [MethName, ErrMsg]))); + PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString( + Format(rs_ErrInvalidArgs, [MethName, ErrMsg])))); end; function ValidateClassRef(PyValue: PPyObject; RefClass: TClass; @@ -2354,8 +2353,8 @@ function CheckIndex(AIndex, ACount : Integer; const AIndexName : string = 'Index with GetPythonEngine do begin Result := False; - PyErr_SetObject (PyExc_IndexError^, PyUnicodeFromString( - Format(rs_ErrCheckIndex,[AIndexName, AIndex]))); + PyErr_SetString(PyExc_IndexError^, PAnsiChar(EncodeString( + Format(rs_ErrCheckIndex,[AIndexName, AIndex])))); end else Result := True; @@ -2372,8 +2371,8 @@ function CheckIntAttribute(AAttribute : PPyObject; const AAttributeName : string begin Result := False; with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrCheckInt, [AAttributeName]))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrCheckInt, [AAttributeName])))); end; end; @@ -2388,8 +2387,8 @@ function CheckFloatAttribute(AAttribute : PPyObject; const AAttributeName : stri begin Result := False; with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrCheckFloat, [AAttributeName]))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrCheckFloat, [AAttributeName])))); end; end; @@ -2410,8 +2409,8 @@ function CheckStrAttribute(AAttribute : PPyObject; const AAttributeName : string begin Result := False; with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrCheckStr, [AAttributeName]))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrCheckStr, [AAttributeName])))); end; end; @@ -2423,8 +2422,8 @@ function CheckCallableAttribute(AAttribute : PPyObject; const AAttributeName : s begin Result := False; with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrCheckCallable, [AAttributeName]))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrCheckCallable, [AAttributeName])))); end; end; @@ -2436,9 +2435,9 @@ function CheckEnum(const AEnumName : string; AValue, AMinValue, AMaxValue : Int begin Result := False; with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrCheckEnum, - [AEnumName, AMinValue, AMaxValue, AValue]))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrCheckEnum, + [AEnumName, AMinValue, AMaxValue, AValue])))); end; end; @@ -2461,8 +2460,8 @@ function CheckObjAttribute(AAttribute : PPyObject; const AAttributeName : string begin Result := False; with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrCheckObjOfType, [AAttributeName, AExpectedClass.ClassName]))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrCheckObjOfType, [AAttributeName, AExpectedClass.ClassName])))); end else begin @@ -2474,8 +2473,8 @@ function CheckObjAttribute(AAttribute : PPyObject; const AAttributeName : string begin Result := False; with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrCheckObj, [AAttributeName]))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrCheckObj, [AAttributeName])))); end; end; @@ -2815,8 +2814,8 @@ function TPyDelphiContainer.SqAssItem(idx: NativeInt; begin Result := -1; with GetPythonEngine do - PyErr_SetObject( PyExc_SystemError^, - PyUnicodeFromString(Format(rs_ErrSqAss, [fContainerAccess.Name])) ); + PyErr_SetString( PyExc_SystemError^, + PAnsiChar(EncodeString(Format(rs_ErrSqAss, [fContainerAccess.Name])))); end; end; @@ -2833,8 +2832,8 @@ function TPyDelphiContainer.SqContains(obj: PPyObject): integer; begin Result := -1; with GetPythonEngine do - PyErr_SetObject( PyExc_SystemError^, - PyUnicodeFromString(Format(rs_ErrSqContains, [fContainerAccess.Name])) ); + PyErr_SetString(PyExc_SystemError^, + PAnsiChar(EncodeString(Format(rs_ErrSqContains, [fContainerAccess.Name])))); end; end; @@ -2928,8 +2927,8 @@ function TPyDelphiObject.CheckBound: Boolean; Result := Assigned(DelphiObject); if not Result then with GetPythonEngine do - PyErr_SetObject(PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrCheckBound, [ClassName]))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrCheckBound, [ClassName])))); end; function TPyDelphiObject.Compare(obj: PPyObject): Integer; @@ -2959,8 +2958,8 @@ constructor TPyDelphiObject.Create(APythonType: TPythonType); constructor TPyDelphiObject.CreateWith(APythonType: TPythonType; args, kwds: PPyObject); begin with APythonType.Engine do - PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString( - Format(rs_CannotCreate, [APythonType.TypeName]))); + PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString( + Format(rs_CannotCreate, [APythonType.TypeName])))); end; function TPyDelphiObject.CreateContainerAccess: TContainerAccess; @@ -3189,8 +3188,8 @@ function RttiCall(ParentAddress: pointer; DelphiWrapper: TPyDelphiWrapper; if Result = nil then with DelphiWrapper.Engine do - PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString( - Format(rs_ErrInvalidRet, [Method.Name, ErrMsg]))); + PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString( + Format(rs_ErrInvalidRet, [Method.Name, ErrMsg])))); except on E: Exception do begin Result := nil; @@ -3405,8 +3404,8 @@ function TPyRttiObject.GetAttrO(key: PPyObject): PPyObject; Result := GetRttiAttr(fAddr, RttiType, KeyName, PyDelphiWrapper, ErrMsg); if not Assigned(Result) then with GetPythonEngine do - PyErr_SetObject (PyExc_AttributeError^, - PyUnicodeFromString(Format(rs_ErrAttrGet,[KeyName, ErrMsg]))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format(rs_ErrAttrGet,[KeyName, ErrMsg])))); end; class procedure TPyRttiObject.RegisterMethods(PythonType: TPythonType); @@ -3436,8 +3435,8 @@ function TPyRttiObject.SetAttrO(key, value: PPyObject): Integer; if Result <> 0 then with GetPythonEngine do - PyErr_SetObject(PyExc_AttributeError^, PyUnicodeFromString( - Format(rs_ErrAttrSet, [KeyName, ErrMsg]))); + PyErr_SetString(PyExc_AttributeError^, PAnsiChar(EncodeString( + Format(rs_ErrAttrSet, [KeyName, ErrMsg])))); end; function TPyRttiObject.SetProps(args, keywords: PPyObject): PPyObject; @@ -3564,8 +3563,8 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject; // If DelphiObject is nil exit immediately with an error if not Assigned(DelphiObject) then begin - PyEngine.PyErr_SetObject(PyEngine.PyExc_AttributeError^, - PyEngine.PyUnicodeFromString(rs_ErrObjectDestroyed)); + PyEngine.PyErr_SetString(PyEngine.PyExc_AttributeError^, + PAnsiChar(PyEngine.EncodeString(rs_ErrObjectDestroyed))); Exit; end; @@ -3652,8 +3651,8 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject; end; {$ENDIF} if not Assigned(Result) then - PyEngine.PyErr_SetObject (PyEngine.PyExc_AttributeError^, - PyEngine.PyUnicodeFromString(Format(rs_ErrAttrGet,[KeyName, ErrMsg]))); + PyEngine.PyErr_SetString(PyEngine.PyExc_AttributeError^, + PAnsiChar(PyEngine.EncodeString(Format(rs_ErrAttrGet,[KeyName, ErrMsg])))); end; function TPyDelphiObject.GetContainerAccess: TContainerAccess; @@ -3816,9 +3815,9 @@ function TPyDelphiObject.Iter: PPyObject; begin Result := nil; with GetPythonEngine do - PyErr_SetObject( PyExc_SystemError^, - PyUnicodeFromString(Format(rs_ErrIterSupport, - [Self.ClassName])) ); + PyErr_SetString(PyExc_SystemError^, + PAnsiChar(EncodeString(Format(rs_ErrIterSupport, + [Self.ClassName])))); end; end; @@ -3958,8 +3957,8 @@ function TPyDelphiObject.SetAttrO(key, value: PPyObject): Integer; // If DelphiObject is nil exit immediately with an error if not Assigned(DelphiObject) then begin - PyEngine.PyErr_SetObject(PyEngine.PyExc_AttributeError^, - PyEngine.PyUnicodeFromString(rs_ErrObjectDestroyed)); + PyEngine.PyErr_SetString(PyEngine.PyExc_AttributeError^, + PAnsiChar(PyEngine.EncodeString(rs_ErrObjectDestroyed))); Exit; end; @@ -4528,7 +4527,7 @@ function TPyDelphiObject.MpAssSubscript(obj1, obj2: PPyObject) : Integer; if not Prop.IsWritable then begin with Engine do - PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString(rs_NotWritable)); + PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString(rs_NotWritable))); Exit; end; @@ -4595,8 +4594,8 @@ function TPyDelphiObject.SqAssItem(idx: NativeInt; obj: PPyObject): integer; begin Result := -1; with GetPythonEngine do - PyErr_SetObject( PyExc_SystemError^, - PyUnicodeFromString(Format(rs_ErrSqAss, [Self.ClassName])) ); + PyErr_SetString( PyExc_SystemError^, + PAnsiChar(EncodeString(Format(rs_ErrSqAss, [Self.ClassName])))); end; end; @@ -4626,8 +4625,8 @@ function TPyDelphiObject.SqItem(idx: NativeInt): PPyObject; begin Result := nil; with GetPythonEngine do - PyErr_SetObject( PyExc_SystemError^, - PyUnicodeFromString(Format(rs_ErrSequence, [Self.ClassName])) ); + PyErr_SetString(PyExc_SystemError^, + PAnsiChar(EncodeString(Format(rs_ErrSequence, [Self.ClassName])))); end; end; @@ -4658,8 +4657,8 @@ function TPyDelphiObject.ToList_Wrapper(args: PPyObject): PPyObject; begin Result := nil; with GetPythonEngine do - PyErr_SetObject( PyExc_SystemError^, - PyUnicodeFromString(Format(rs_ErrSequence, [Self.ClassName])) ); + PyErr_SetString(PyExc_SystemError^, + PAnsiChar(EncodeString(Format(rs_ErrSequence, [Self.ClassName])))); end else if GetPythonEngine.PyArg_ParseTuple( args, ':ToList' ) <> 0 then with GetPythonEngine do @@ -4682,8 +4681,8 @@ function TPyDelphiObject.ToTuple_Wrapper(args: PPyObject): PPyObject; begin Result := nil; with GetPythonEngine do - PyErr_SetObject( PyExc_SystemError^, - PyUnicodeFromString(Format(rs_ErrSequence, [Self.ClassName])) ); + PyErr_SetString( PyExc_SystemError^, + PAnsiChar(EncodeString(Format(rs_ErrSequence, [Self.ClassName])))); end else if GetPythonEngine.PyArg_ParseTuple( args, ':ToTuple' ) <> 0 then with GetPythonEngine do @@ -4749,9 +4748,9 @@ function TPyDelphiMethodObject.Call(ob1, ob2: PPyObject): PPyObject; on E: Exception do begin Result := nil; - PyErr_SetObject (PyExc_TypeError^, - PyUnicodeFromString(Format(rs_ErrInvalidArgs, - [MethodInfo.Name, E.Message]))); + PyErr_SetString(PyExc_TypeError^, + PAnsiChar(EncodeString(Format(rs_ErrInvalidArgs, + [MethodInfo.Name, E.Message])))); end; end; end; @@ -5227,9 +5226,8 @@ function TPyDelphiWrapper.CreateComponent(pself, args: PPyObject): PPyObject; Klass := nil; end; if (Klass = nil) or not Klass.InheritsFrom(TComponent) then begin - PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString( - Format(rs_ErrInvalidArgs, - ['CreateComponent', rs_InvalidClass]))); + PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString( + Format(rs_ErrInvalidArgs, ['CreateComponent', rs_InvalidClass])))); Exit; end; @@ -5244,9 +5242,8 @@ function TPyDelphiWrapper.CreateComponent(pself, args: PPyObject): PPyObject; Ownership := soOwned; Result := Self.Wrap(Component, Ownership); end else - PyErr_SetObject(PyExc_TypeError^, PyUnicodeFromString( - Format(rs_ErrInvalidArgs, - ['CreateComponent', '']))); + PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString( + Format(rs_ErrInvalidArgs, ['CreateComponent', ''])))); end; end; From 01b73d4b5a99430574de41151b627b41ef6f2302 Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Mon, 23 Sep 2024 20:04:43 +0300 Subject: [PATCH 31/55] PyErr_SetString should be called with utf8 encoded strings --- Demos/Demo07/Unit1.dfm | 3 --- Demos/Demo07/Unit1.pas | 8 ++++---- Source/PythonAction.pas | 14 +++++++------- Source/PythonEngine.pas | 14 +++++++------- Source/WrapDelphiClasses.pas | 14 +++++++------- Source/WrapDelphiTypes.pas | 12 ++++++------ Source/WrapFireDAC.pas | 20 ++++++++++---------- Source/fmx/WrapFmxForms.pas | 2 +- Source/fmx/WrapFmxTypes.pas | 8 ++++---- Source/vcl/WrapVclForms.pas | 2 +- Source/vcl/WrapVclGraphics.pas | 14 +++++++------- Tests/FMX/Android/NumberServicesTest.pas | 2 +- Tests/NumberServicesTest.pas | 2 +- 13 files changed, 56 insertions(+), 59 deletions(-) diff --git a/Demos/Demo07/Unit1.dfm b/Demos/Demo07/Unit1.dfm index 51b77e56..500ec0e6 100644 --- a/Demos/Demo07/Unit1.dfm +++ b/Demos/Demo07/Unit1.dfm @@ -13,8 +13,6 @@ object Form1: TForm1 Font.Name = 'MS Sans Serif' Font.Pitch = fpVariable Font.Style = [] - OldCreateOrder = True - PixelsPerInch = 96 TextHeight = 13 object Splitter1: TSplitter Left = 0 @@ -23,7 +21,6 @@ object Form1: TForm1 Height = 3 Cursor = crVSplit Align = alTop - ExplicitWidth = 536 end object Memo1: TMemo Left = 0 diff --git a/Demos/Demo07/Unit1.pas b/Demos/Demo07/Unit1.pas index 012507af..67e672b0 100644 --- a/Demos/Demo07/Unit1.pas +++ b/Demos/Demo07/Unit1.pas @@ -205,7 +205,7 @@ function PyPoint_getattr(obj : PPyObject; key : PAnsiChar) : PPyObject; cdecl; // Else check for a method Result := PyObject_GenericGetAttr(obj, PyUnicodeFromString(key)); if not Assigned(Result) then - PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown attribute "%s"',[key])))); + PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Unknown attribute "%s"',[key])))); end; end; end; @@ -226,7 +226,7 @@ function PyPoint_setattrfunc(obj : PPyObject; key : PAnsiChar; value : PPyObjec Result := 0; end else - PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Attribute "%s" needs an integer',[key])))); + PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Attribute "%s" needs an integer',[key])))); // Check for attribute y end else if key = 'y' then begin if PyLong_Check(value) then @@ -235,9 +235,9 @@ function PyPoint_setattrfunc(obj : PPyObject; key : PAnsiChar; value : PPyObjec Result := 0; end else - PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Attribute "%s" needs an integer',[key])))); + PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Attribute "%s" needs an integer',[key])))); end else - PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown attribute "%s"',[key])))); + PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Unknown attribute "%s"',[key])))); end; end; diff --git a/Source/PythonAction.pas b/Source/PythonAction.pas index 60af65e5..d94d610e 100644 --- a/Source/PythonAction.pas +++ b/Source/PythonAction.pas @@ -17,7 +17,7 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - ActnList, PythonEngine; + Actions, ActnList, PythonEngine; type TPythonAction = class(TAction) @@ -114,21 +114,21 @@ function TPythonAction.HandlesTarget(Target: TObject): Boolean; procedure TPythonAction.InitializeAction; var - docString: string; + docString: string; begin if not (csDesigning in ComponentState) and Assigned(PythonModule) then begin fClearname := 'Clear' + Name; docString := 'Claer all events of "' + Owner.Name + '.' + Name + '" action'; - PythonModule.AddDelphiMethod(PChar(fClearname), PythonClear, PChar(docString)); + PythonModule.AddDelphiMethod(PAnsiChar(fClearname), PythonClear, PAnsiChar(docString)); fRegistername := 'Register' + Name; docString := 'Register an event againt the "' + Owner.Name + '.' + Name + '" action'; - PythonModule.AddDelphiMethod(PChar(fRegistername), PythonRegister, PChar(docString)); + PythonModule.AddDelphiMethod(PAnsiChar(fRegistername), PythonRegister, PAnsiChar(docString)); fUnregistername := 'Unregister' + Name; docString := 'Unregister an event againt the "' + Owner.Name + '.' + Name + '" action'; - PythonModule.AddDelphiMethod(PChar(fUnregistername), PythonUnregister, PChar(docString)); + PythonModule.AddDelphiMethod(PAnsiChar(fUnregistername), PythonUnregister, PAnsiChar(docString)); end; end; @@ -152,7 +152,7 @@ function TPythonAction.PythonRegister(pself, args: PPyObject): PPyObject; ( not PyFunction_Check(func)) then begin s := fRegistername + '(function)'; - PyErr_SetString(PyExc_TypeError^,PChar(s)); + PyErr_SetString(PyExc_TypeError^, PAnsiChar(Utf8Encode(s))); end else with RegisteredMethods do @@ -174,7 +174,7 @@ function TPythonAction.PythonUnregister(pself, args: PPyObject): PPyObject; (RegisteredMethods.IndexOf(func) = -1) then begin s := fUnregistername + '(function)'; - PyErr_SetString(PyExc_TypeError^,PChar(s)); + PyErr_SetString(PyExc_TypeError^, PAnsiChar(Utf8Encode(s))); end else with RegisteredMethods do diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index a0a72e0d..c08ea1dc 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -2419,8 +2419,8 @@ TError = class(TCollectionItem) destructor Destroy; override; procedure Assign(Source: TPersistent); override; procedure BuildError( const ModuleName : AnsiString ); - procedure RaiseError( const msg : AnsiString ); - procedure RaiseErrorObj( const msg : AnsiString; obj : PPyObject ); + procedure RaiseError(const msg : AnsiString); + procedure RaiseErrorObj(const msg : AnsiString; obj : PPyObject); function Owner : TErrors; property Error : PPyObject read FError write FError; published @@ -7183,14 +7183,14 @@ procedure TError.BuildError( const ModuleName : AnsiString ); raise Exception.CreateFmt( 'Could not create error "%s"', [Name] ); end; -procedure TError.RaiseError( const msg : AnsiString ); +procedure TError.RaiseError(const msg : AnsiString); begin Owner.Owner.CheckEngine; with Owner.Owner.Engine do - PyErr_SetString( Error, PAnsiChar(msg) ); + PyErr_SetString(Error, PAnsiChar(EncodeString(msg))); end; -procedure TError.RaiseErrorObj( const msg : AnsiString; obj : PPyObject ); +procedure TError.RaiseErrorObj(const msg : AnsiString; obj : PPyObject); var args, res, str : PPyObject; i : Integer; @@ -7698,8 +7698,8 @@ function TPyObject.SetAttr(key : PAnsiChar; value : PPyObject) : Integer; with GetPythonEngine do begin Result := -1; - PyErr_SetString (PyExc_AttributeError^, - PAnsiChar(AnsiString(Format('Unknown attribute "%s"',[key])))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format('Unknown attribute "%s"',[key])))); end; end; diff --git a/Source/WrapDelphiClasses.pas b/Source/WrapDelphiClasses.pas index bfee8aa3..f7f57a86 100644 --- a/Source/WrapDelphiClasses.pas +++ b/Source/WrapDelphiClasses.pas @@ -1221,13 +1221,13 @@ function TPyDelphiComponent.MpSubscript(obj: PPyObject): PPyObject; else begin Result := nil; - PyErr_SetString (PyExc_KeyError^, PAnsiChar(AnsiString(_name))); + PyErr_SetString(PyExc_KeyError^, PAnsiChar(EncodeString(_name))); end; end else begin Result := nil; - PyErr_SetString (PyExc_KeyError^, 'Key must be a string'); + PyErr_SetString(PyExc_KeyError^, 'Key must be a string'); end; end; end; @@ -1329,7 +1329,7 @@ function TStringsAccess.SetItem(AIndex: Integer; AValue: PPyObject): Boolean; else begin Result := False; - PyErr_SetString (PyExc_AttributeError^, 'You can only assign strings to TStrings items'); + PyErr_SetString(PyExc_AttributeError^, 'You can only assign strings to TStrings items'); end; end end; @@ -1393,7 +1393,7 @@ function TStringsObjectsAccess.SetItem(AIndex: Integer; AValue: PPyObject): Bool else begin Result := False; - PyErr_SetString (PyExc_AttributeError^, 'You can only assign Delphi wrappers to Objects items'); + PyErr_SetString(PyExc_AttributeError^, 'You can only assign Delphi wrappers to Objects items'); end; end end; @@ -1617,11 +1617,11 @@ function TPyDelphiStrings.MpSubscript(obj: PPyObject): PPyObject; else Result := GetPythonEngine.ReturnNone; end else with GetPythonEngine do begin - PyErr_SetString (PyExc_KeyError^, PAnsiChar(AnsiString(S))); + PyErr_SetString(PyExc_KeyError^, PAnsiChar(EncodeString(S))); Result := nil; end; end else with GetPythonEngine do begin - PyErr_SetString (PyExc_KeyError^, '<Empty String>'); + PyErr_SetString(PyExc_KeyError^, '<Empty String>'); Result := nil; end; end; @@ -2445,7 +2445,7 @@ TResourceStreamClass = class of TResourceStream; except on E: Exception do with GetPythonEngine do - PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(AnsiString(E.Message))); + PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(EncodeString(E.Message))); end; //Maybe it was created on the next attempt... diff --git a/Source/WrapDelphiTypes.pas b/Source/WrapDelphiTypes.pas index e572b851..86f00e22 100644 --- a/Source/WrapDelphiTypes.pas +++ b/Source/WrapDelphiTypes.pas @@ -229,8 +229,8 @@ function CheckPointAttribute(AAttribute : PPyObject; const AAttributeName : stri begin Result := False; with GetPythonEngine do - PyErr_SetString (PyExc_AttributeError^, - PAnsiChar(AnsiString(Format('%s receives only Point objects', [AAttributeName])))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format('%s receives only Point objects', [AAttributeName])))); end; end; end; @@ -248,8 +248,8 @@ function CheckRectAttribute(AAttribute : PPyObject; const AAttributeName : strin begin Result := False; with GetPythonEngine do - PyErr_SetString (PyExc_AttributeError^, - PAnsiChar(AnsiString(Format('%s receives only Rect objects', [AAttributeName])))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format('%s receives only Rect objects', [AAttributeName])))); end; end; end; @@ -267,8 +267,8 @@ function CheckSizeAttribute(AAttribute : PPyObject; const AAttributeName : strin begin Result := False; with GetPythonEngine do - PyErr_SetString (PyExc_AttributeError^, - PAnsiChar(AnsiString(Format('%s receives only Size objects', [AAttributeName])))); + PyErr_SetString(PyExc_AttributeError^, + PAnsiChar(EncodeString(Format('%s receives only Size objects', [AAttributeName])))); end; end; end; diff --git a/Source/WrapFireDAC.pas b/Source/WrapFireDAC.pas index eefa7af9..76e64aec 100644 --- a/Source/WrapFireDAC.pas +++ b/Source/WrapFireDAC.pas @@ -597,7 +597,7 @@ function TPyDBField.CheckField : Boolean; if not Assigned(DelphiObject) then begin Result := False; with GetPythonEngine do - PyErr_SetString (PyExc_RuntimeError^, PAnsiChar('No field defined !') ); + PyErr_SetString(PyExc_RuntimeError^, PAnsiChar('No field defined !') ); end else Result := True; @@ -978,7 +978,7 @@ function TPyDBDataset.Do_Fields( args : PPyObject ): PPyObject; Result := PyDelphiWrapper.Wrap(l_oDataset.Fields[idx]) else begin Result := nil; - PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Value out of range : %d', [idx])))); + PyErr_SetString(PyExc_AttributeError^, PAnsiChar(EncodeString(Format('Value out of range : %d', [idx])))); end; end else @@ -1011,7 +1011,7 @@ function TPyDBDataset.Do_FieldByName( args : PPyObject ) : PPyObject; Result := PyDelphiWrapper.Wrap(fld) else begin Result := nil; - PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown field "%s"', [String(s)]))) ); + PyErr_SetString(PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown field "%s"', [String(s)]))) ); end; end else @@ -1191,7 +1191,7 @@ function TPyDBDataset.Do_Locate( args : PPyObject ) : PPyObject; try if PyArg_ParseTuple( args, 'sOO:DBDataset.Locate',@keyFields, @keyValues, @options ) <> 0 then begin if PySequence_Check(options) = 0 then - PyErr_SetString (PyExc_AttributeError^, 'Third argument of Locate must be a sequence.') + PyErr_SetString(PyExc_AttributeError^, 'Third argument of Locate must be a sequence.') else begin // Prepare the locate options ListToSet( options, @opt, sizeof(opt) ); @@ -1391,14 +1391,14 @@ function TPyDBTable.CheckActiveDBTable(aMustOpen: Boolean): Boolean; if not aMustOpen then begin Result := False; with GetPythonEngine do - PyErr_SetString (PyExc_RuntimeError^, PAnsiChar('DBTable is open!') ); + PyErr_SetString(PyExc_RuntimeError^, PAnsiChar('DBTable is open!') ); end; end else begin if aMustOpen then begin Result := False; with GetPythonEngine do - PyErr_SetString (PyExc_RuntimeError^, PAnsiChar('DBTable is not open!') ); + PyErr_SetString(PyExc_RuntimeError^, PAnsiChar('DBTable is not open!') ); end; end; end; @@ -1838,10 +1838,10 @@ function TPyDBTable.Do_SetRange( args : PPyObject ) : PPyObject; if l_oTable.Active and (PyArg_ParseTuple( args, 'OO:FDTable.SetRange',@l_oPyStartValues, @l_oPyEndValues ) <> 0) then begin if PySequence_Check(l_oPyStartValues) = 0 then begin - PyErr_SetString (PyExc_AttributeError^, 'First argument of SetRange must be a sequence.'); + PyErr_SetString(PyExc_AttributeError^, 'First argument of SetRange must be a sequence.'); end else if PySequence_Check(l_oPyEndValues) = 0 then begin - PyErr_SetString (PyExc_AttributeError^, 'Second argument of SetRange must be a sequence.'); + PyErr_SetString(PyExc_AttributeError^, 'Second argument of SetRange must be a sequence.'); end else begin l_oTable.SetRangeStart; @@ -1952,14 +1952,14 @@ function TPyDBQuery.CheckActiveDBQuery(aMustOpen: Boolean): Boolean; if not aMustOpen then begin Result := False; with GetPythonEngine do - PyErr_SetString (PyExc_RuntimeError^, PAnsiChar('DBQuery is open!') ); + PyErr_SetString(PyExc_RuntimeError^, PAnsiChar('DBQuery is open!') ); end; end else begin if aMustOpen then begin Result := False; with GetPythonEngine do - PyErr_SetString (PyExc_RuntimeError^, PAnsiChar('DBQuery is not open!') ); + PyErr_SetString(PyExc_RuntimeError^, PAnsiChar('DBQuery is not open!') ); end; end; end; diff --git a/Source/fmx/WrapFmxForms.pas b/Source/fmx/WrapFmxForms.pas index f3a2b68e..906f14b5 100644 --- a/Source/fmx/WrapFmxForms.pas +++ b/Source/fmx/WrapFmxForms.pas @@ -466,7 +466,7 @@ function TPyDelphiCommonCustomForm.LoadProps_Wrapper( except on E: Exception do with GetPythonEngine do - PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(AnsiString(E.Message))); + PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(Utf8Encode(E.Message))); end; Result := nil; end; diff --git a/Source/fmx/WrapFmxTypes.pas b/Source/fmx/WrapFmxTypes.pas index 53e36d9f..b7bbb8d5 100644 --- a/Source/fmx/WrapFmxTypes.pas +++ b/Source/fmx/WrapFmxTypes.pas @@ -505,7 +505,7 @@ function CheckPointFAttribute(AAttribute : PPyObject; const AAttributeName : str Result := False; with GetPythonEngine do PyErr_SetString (PyExc_AttributeError^, - PAnsiChar(AnsiString(Format('%s receives only PointF objects', [AAttributeName])))); + PAnsiChar(Utf8Encode(Format('%s receives only PointF objects', [AAttributeName])))); end; end; end; @@ -524,7 +524,7 @@ function CheckSizeFAttribute(AAttribute : PPyObject; const AAttributeName : stri Result := False; with GetPythonEngine do PyErr_SetString (PyExc_AttributeError^, - PAnsiChar(AnsiString(Format('%s receives only SizeF objects', [AAttributeName])))); + PAnsiChar(Utf8Encode(Format('%s receives only SizeF objects', [AAttributeName])))); end; end; end; @@ -543,7 +543,7 @@ function CheckRectFAttribute(AAttribute: PPyObject; const AAttributeName: string Result := False; with GetPythonEngine do PyErr_SetString (PyExc_AttributeError^, - PAnsiChar(AnsiString(Format('%s receives only RectF objects', [AAttributeName])))); + PAnsiChar(Utf8Encode(Format('%s receives only RectF objects', [AAttributeName])))); end; end; end; @@ -562,7 +562,7 @@ function CheckTouchAttribute(AAttribute: PPyObject; const AAttributeName: string Result := False; with GetPythonEngine do PyErr_SetString (PyExc_AttributeError^, - PAnsiChar(AnsiString(Format('%s receives only Touch objects', [AAttributeName])))); + PAnsiChar(Utf8Encode(Format('%s receives only Touch objects', [AAttributeName])))); end; end; end; diff --git a/Source/vcl/WrapVclForms.pas b/Source/vcl/WrapVclForms.pas index fd0799c3..b3d77bec 100644 --- a/Source/vcl/WrapVclForms.pas +++ b/Source/vcl/WrapVclForms.pas @@ -572,7 +572,7 @@ function TPyDelphiCustomForm.LoadProps_Wrapper(args: PPyObject): PPyObject; except on E: Exception do with GetPythonEngine() do - PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(AnsiString(E.Message))); + PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(EncodeString(E.Message))); end; Result := nil; end; diff --git a/Source/vcl/WrapVclGraphics.pas b/Source/vcl/WrapVclGraphics.pas index 1479d5f6..21a54013 100644 --- a/Source/vcl/WrapVclGraphics.pas +++ b/Source/vcl/WrapVclGraphics.pas @@ -1057,7 +1057,7 @@ function TPyDelphiBitmap.Set_HandleType(AValue: PPyObject; else begin with GetPythonEngine do - PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown THandleType value "%s"', [_value])))); + PyErr_SetString(PyExc_AttributeError^, PAnsiChar(EncodeString(Format('Unknown THandleType value "%s"', [_value])))); Result := -1; Exit; end; @@ -1143,7 +1143,7 @@ function TPyDelphiBitmap.Set_PixelFormat(AValue: PPyObject; DelphiObject.PixelFormat := pfCustom else begin - PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown TPixelFormat value "%s"', [_value])))); + PyErr_SetString(PyExc_AttributeError^, PAnsiChar(EncodeString(Format('Unknown TPixelFormat value "%s"', [_value])))); Result := -1; Exit; end; @@ -1184,7 +1184,7 @@ function TPyDelphiBitmap.Set_TransparentMode(AValue: PPyObject; else begin with GetPythonEngine do - PyErr_SetString (PyExc_AttributeError^, PAnsiChar(AnsiString(Format('Unknown TTransparentMode value "%s"', [_value])))); + PyErr_SetString(PyExc_AttributeError^, PAnsiChar(EncodeString(Format('Unknown TTransparentMode value "%s"', [_value])))); Result := -1; Exit; end; @@ -1615,7 +1615,7 @@ function TPyDelphiCanvas.PolyBezier_Wrapper(args: PPyObject): PPyObject; else begin Result := nil; - PyErr_SetString (PyExc_AttributeError^, 'PolyBezier accepts only a sequence of points as single parameter'); + PyErr_SetString(PyExc_AttributeError^, 'PolyBezier accepts only a sequence of points as single parameter'); end; end else @@ -1662,7 +1662,7 @@ function TPyDelphiCanvas.PolyBezierTo_Wrapper(args: PPyObject): PPyObject; else begin Result := nil; - PyErr_SetString (PyExc_AttributeError^, 'PolyBezierTo accepts only a sequence of points as single parameter'); + PyErr_SetString(PyExc_AttributeError^, 'PolyBezierTo accepts only a sequence of points as single parameter'); end; end else @@ -1709,7 +1709,7 @@ function TPyDelphiCanvas.Polygon_Wrapper(args: PPyObject): PPyObject; else begin Result := nil; - PyErr_SetString (PyExc_AttributeError^, 'Polygon accepts only a sequence of points as single parameter'); + PyErr_SetString(PyExc_AttributeError^, 'Polygon accepts only a sequence of points as single parameter'); end; end else @@ -1755,7 +1755,7 @@ function TPyDelphiCanvas.Polyline_Wrapper(args: PPyObject): PPyObject; else begin Result := nil; - PyErr_SetString (PyExc_AttributeError^, 'Polyline accepts only a sequence of points as single parameter'); + PyErr_SetString(PyExc_AttributeError^, 'Polyline accepts only a sequence of points as single parameter'); end; end else diff --git a/Tests/FMX/Android/NumberServicesTest.pas b/Tests/FMX/Android/NumberServicesTest.pas index 115ba066..3aee6737 100644 --- a/Tests/FMX/Android/NumberServicesTest.pas +++ b/Tests/FMX/Android/NumberServicesTest.pas @@ -288,7 +288,7 @@ constructor PyTRandomInteger.CreateWith(PythonType: TPythonType; args, FRandomInteger.Value := PythonToTRandomInteger(val1).Value; except on e: Exception do - PyErr_SetString(PyExc_Exception^, PAnsiChar(AnsiString(e.Message))); + PyErr_SetString(PyExc_Exception^, PAnsiChar(EncodeString(e.Message))); end; end; end; diff --git a/Tests/NumberServicesTest.pas b/Tests/NumberServicesTest.pas index ca1bdb1a..0b100950 100644 --- a/Tests/NumberServicesTest.pas +++ b/Tests/NumberServicesTest.pas @@ -291,7 +291,7 @@ constructor PyTRandomInteger.CreateWith(PythonType: TPythonType; args, FRandomInteger.Value := PythonToTRandomInteger(val1).Value; except on e: Exception do - PyErr_SetString(PyExc_Exception^, PAnsiChar(AnsiString(e.Message))); + PyErr_SetString(PyExc_Exception^, PAnsiChar(EncodeString(e.Message))); end; end; end; From 70bc12a9801be2101c6ea080220de5193e32cdbf Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Mon, 23 Sep 2024 20:39:50 +0300 Subject: [PATCH 32/55] Fix reference counting error in demos 6 and 7. --- Demos/Demo06/Unit1.dfm | 3 --- Demos/Demo06/Unit1.pas | 13 ++++++++++--- Demos/Demo07/Unit1.pas | 13 ++++++++++--- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Demos/Demo06/Unit1.dfm b/Demos/Demo06/Unit1.dfm index 19538b07..c3a31c64 100644 --- a/Demos/Demo06/Unit1.dfm +++ b/Demos/Demo06/Unit1.dfm @@ -10,8 +10,6 @@ object Form1: TForm1 Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] - OldCreateOrder = True - PixelsPerInch = 96 TextHeight = 13 object Splitter1: TSplitter Left = 0 @@ -20,7 +18,6 @@ object Form1: TForm1 Height = 3 Cursor = crVSplit Align = alTop - ExplicitWidth = 536 end object Memo1: TMemo Left = 0 diff --git a/Demos/Demo06/Unit1.pas b/Demos/Demo06/Unit1.pas index df25433d..e038b4fa 100644 --- a/Demos/Demo06/Unit1.pas +++ b/Demos/Demo06/Unit1.pas @@ -151,6 +151,8 @@ procedure PyPoint_dealloc(obj : PPyObject); cdecl; // object.value // object.method(args) function PyPoint_getattr(obj : PPyObject; key : PAnsiChar) : PPyObject; cdecl; +var + Py_Key: PPyObject; begin with GetPythonEngine, PPyPoint(obj)^ do begin @@ -163,9 +165,14 @@ function PyPoint_getattr(obj : PPyObject; key : PAnsiChar) : PPyObject; cdecl; else begin // Else check for a method - Result := PyObject_GenericGetAttr(obj, PyUnicodeFromString(key)); - if not Assigned(Result) then - PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Unknown attribute "%s"',[key])))); + Py_Key := PyUnicodeFromString(key); + try + Result := PyObject_GenericGetAttr(obj, Py_key); + if not Assigned(Result) then + PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Unknown attribute "%s"',[key])))); + finally + Py_DECREF(Py_Key); + end; end; end; end; diff --git a/Demos/Demo07/Unit1.pas b/Demos/Demo07/Unit1.pas index 67e672b0..f33b8817 100644 --- a/Demos/Demo07/Unit1.pas +++ b/Demos/Demo07/Unit1.pas @@ -191,6 +191,8 @@ procedure PyPoint_dealloc(obj : PPyObject); cdecl; // object.value // object.method(args) function PyPoint_getattr(obj : PPyObject; key : PAnsiChar) : PPyObject; cdecl; +var + Py_Key: PPyObject; begin with GetPythonEngine, PPyPoint(obj)^ do begin @@ -203,9 +205,14 @@ function PyPoint_getattr(obj : PPyObject; key : PAnsiChar) : PPyObject; cdecl; else begin // Else check for a method - Result := PyObject_GenericGetAttr(obj, PyUnicodeFromString(key)); - if not Assigned(Result) then - PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Unknown attribute "%s"',[key])))); + Py_Key := PyUnicodeFromString(key); + try + Result := PyObject_GenericGetAttr(obj, Py_Key); + if not Assigned(Result) then + PyErr_SetString (PyExc_AttributeError^, PAnsiChar(Utf8Encode(Format('Unknown attribute "%s"',[key])))); + finally + Py_DECREF(Py_Key); + end; end; end; end; From 53c24628f24f460e1805d7fd33f37cca5a1d45d6 Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Sun, 29 Sep 2024 00:54:56 -0400 Subject: [PATCH 33/55] Fix issue reported in https://en.delphipraxis.net/topic/12281-python4delphi-crash-immediately-after-launch --- Demos/Demo36/ParallelPython.dpr | 1 + 1 file changed, 1 insertion(+) diff --git a/Demos/Demo36/ParallelPython.dpr b/Demos/Demo36/ParallelPython.dpr index 00883f7a..abcfb0fa 100644 --- a/Demos/Demo36/ParallelPython.dpr +++ b/Demos/Demo36/ParallelPython.dpr @@ -109,6 +109,7 @@ begin WriteLn('Elapsed ms: ' + SW.ElapsedMilliseconds.ToString); WriteLn; finally + Sleep(1000); // allow some time for the threads to terminate DestroyEngine; end; except From d1951c18d614cc8931cc7b9edda019bcb7cb13ad Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Tue, 1 Oct 2024 00:24:22 -0400 Subject: [PATCH 34/55] TPyClassWrapper methods declared private. Documentation improved. --- Source/WrapDelphi.pas | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index 67d0535c..bed385ea 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -616,25 +616,26 @@ TPyDelphiObjectClass = class of TPyDelphiObject; Generic wrapper for pascal classes Can be used from unit wrappers as follows: - APyDelphiWrapper.RegisterDelphiWrapper(TPyClassWrapper<TMyClass>); + PyDelphiWrapper1.RegisterDelphiWrapper(TPyClassWrapper<TMyClass>); or at runtime (e.g. inside the FormCreate handler: PyDelphiWrapper1.RegisterDelphiWrapper(TPyClassWrapper<TMyClass>).Initialize; if you want your class to capable of being instantiated from python then do: - TTestWrapper = class(TPyClassWrapper<TTest>) + TMyClassWrapper = class(TPyClassWrapper<TMyClass>) constructor CreateWith(APythonType: TPythonType; args, kwds: PPyObject); overload; override; end; - constuctor TTestWrapper.CreateWith(APythonType: TPythonType; args, kwds: PPyObject); + constuctor TMyClassWrapper.CreateWith(APythonType: TPythonType; args, kwds: PPyObject); begin Create(APythonType); - DelphiObject := TTest.Create; + DelphiObject := TMyClass.Create; end; - PyDelphiWrapper1.RegisterDelphiWrapper(TTestWrapper).Initialize; + PyDelphiWrapper1.RegisterDelphiWrapper(TMyClassWrapper).Initialize; } TPyClassWrapper<T: class> = class(TPyDelphiObject) + private function GetDelphiObject: T; procedure SetDelphiObject(const Value: T); public From 6afe08111fe099609a445e8b6346e0c03bdf9c18 Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Sun, 8 Dec 2024 23:38:28 +0200 Subject: [PATCH 35/55] 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<AnsiString>; + PParams: TArray<PAnsiChar>; + 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<AnsiString>; + PUtf8Paths: TArray<PAnsiChar>; + 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 <pyscripter@gmail.com> Date: Tue, 10 Dec 2024 02:00:45 +0200 Subject: [PATCH 36/55] 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 @@ <MainSource>Python.dpk</MainSource> <Platform Condition="'$(Platform)'==''">Win32</Platform> <ProjectGuid>{018AAA56-F5BD-4A04-BCCA-A0043EAAA5CE}</ProjectGuid> - <ProjectVersion>19.5</ProjectVersion> - <TargetedPlatforms>168083</TargetedPlatforms> + <ProjectVersion>20.1</ProjectVersion> + <TargetedPlatforms>693395</TargetedPlatforms> + <ProjectName Condition="'$(ProjectName)'==''">Python</ProjectName> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> <Base>true</Base> @@ -54,6 +55,12 @@ <Cfg_1>true</Cfg_1> <Base>true</Base> </PropertyGroup> + <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Cfg_1)'=='true') or '$(Cfg_1_iOSDevice64)'!=''"> + <Cfg_1_iOSDevice64>true</Cfg_1_iOSDevice64> + <CfgParent>Cfg_1</CfgParent> + <Cfg_1>true</Cfg_1> + <Base>true</Base> + </PropertyGroup> <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''"> <Cfg_1_Win64>true</Cfg_1_Win64> <CfgParent>Cfg_1</CfgParent> @@ -88,7 +95,7 @@ <DCC_DcuOutput>..\..\..\lib\$(Platform)\$(Config)</DCC_DcuOutput> <DCC_Description>Python4Delphi - Run-time Engine Package</DCC_Description> <DCC_ImageBase>00400000</DCC_ImageBase> - <DCC_Namespace>Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;DUnitX.Loggers.GUI;Winapi;System.Win;$(DCC_Namespace)</DCC_Namespace> + <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;DUnitX.Loggers.GUI;Winapi;System.Win;$(DCC_Namespace)</DCC_Namespace> <DllSuffix>$(Auto)</DllSuffix> <GenDll>true</GenDll> <GenPackage>true</GenPackage> @@ -109,11 +116,11 @@ </PropertyGroup> <PropertyGroup Condition="'$(Base_OSX64)'!=''"> <BT_BuildType>Debug</BT_BuildType> - <VerInfo_Keys>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</VerInfo_Keys> + <VerInfo_Keys>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</VerInfo_Keys> </PropertyGroup> <PropertyGroup Condition="'$(Base_OSXARM64)'!=''"> <BT_BuildType>Debug</BT_BuildType> - <VerInfo_Keys>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</VerInfo_Keys> + <VerInfo_Keys>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</VerInfo_Keys> </PropertyGroup> <PropertyGroup Condition="'$(Base_Win32)'!=''"> <BT_BuildType>Debug</BT_BuildType> @@ -136,6 +143,9 @@ <VerInfo_Build>1</VerInfo_Build> <VerInfo_Keys>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=</VerInfo_Keys> </PropertyGroup> + <PropertyGroup Condition="'$(Cfg_1_iOSDevice64)'!=''"> + <BT_BuildType>Debug</BT_BuildType> + </PropertyGroup> <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''"> <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys> @@ -204,13 +214,14 @@ <Platforms> <Platform value="Android">True</Platform> <Platform value="Android64">True</Platform> + <Platform value="iOSDevice64">True</Platform> + <Platform value="iOSSimARM64">True</Platform> <Platform value="Linux64">True</Platform> <Platform value="OSX64">True</Platform> <Platform value="OSXARM64">True</Platform> <Platform value="Win32">True</Platform> <Platform value="Win64">True</Platform> - <Platform value="iOSDevice64">False</Platform> - <Platform value="iOSSimARM64">False</Platform> + <Platform value="Win64x">False</Platform> </Platforms> </BorlandProject> <ProjectFileVersion>12</ProjectFileVersion> 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 @@ <MainSource>PythonFmx.dpk</MainSource> <Platform Condition="'$(Platform)'==''">Win32</Platform> <ProjectGuid>{513BF750-373D-4C95-A672-78CA8DDF3F63}</ProjectGuid> - <ProjectVersion>19.5</ProjectVersion> - <TargetedPlatforms>167955</TargetedPlatforms> + <ProjectVersion>20.1</ProjectVersion> + <TargetedPlatforms>693395</TargetedPlatforms> + <ProjectName Condition="'$(ProjectName)'==''">PythonFmx</ProjectName> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> <Base>true</Base> @@ -59,9 +60,14 @@ <CfgParent>Base</CfgParent> <Base>true</Base> </PropertyGroup> + <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Cfg_2)'=='true') or '$(Cfg_2_iOSDevice64)'!=''"> + <Cfg_2_iOSDevice64>true</Cfg_2_iOSDevice64> + <CfgParent>Cfg_2</CfgParent> + <Cfg_2>true</Cfg_2> + <Base>true</Base> + </PropertyGroup> <PropertyGroup Condition="'$(Base)'!=''"> <SanitizedProjectName>PythonFmx</SanitizedProjectName> - <DCC_CBuilderOutput>All</DCC_CBuilderOutput> <DCC_DcuOutput>..\..\..\lib\$(Platform)\$(Config)</DCC_DcuOutput> <DCC_Description>Python4Delphi - Run-time Engine Package for FMX</DCC_Description> <DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput> @@ -87,11 +93,11 @@ </PropertyGroup> <PropertyGroup Condition="'$(Base_OSX64)'!=''"> <BT_BuildType>Debug</BT_BuildType> - <VerInfo_Keys>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</VerInfo_Keys> + <VerInfo_Keys>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</VerInfo_Keys> </PropertyGroup> <PropertyGroup Condition="'$(Base_OSXARM64)'!=''"> <BT_BuildType>Debug</BT_BuildType> - <VerInfo_Keys>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</VerInfo_Keys> + <VerInfo_Keys>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</VerInfo_Keys> </PropertyGroup> <PropertyGroup Condition="'$(Base_Win32)'!=''"> <BT_BuildType>Debug</BT_BuildType> @@ -127,6 +133,9 @@ <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> </PropertyGroup> + <PropertyGroup Condition="'$(Cfg_2_iOSDevice64)'!=''"> + <BT_BuildType>Debug</BT_BuildType> + </PropertyGroup> <ItemGroup> <DelphiCompile Include="$(MainSource)"> <MainSource>MainSource</MainSource> @@ -185,13 +194,14 @@ <Platforms> <Platform value="Android">True</Platform> <Platform value="Android64">True</Platform> - <Platform value="Linux64">False</Platform> + <Platform value="iOSDevice64">True</Platform> + <Platform value="iOSSimARM64">True</Platform> + <Platform value="Linux64">True</Platform> <Platform value="OSX64">True</Platform> <Platform value="OSXARM64">True</Platform> <Platform value="Win32">True</Platform> <Platform value="Win64">True</Platform> - <Platform value="iOSDevice64">False</Platform> - <Platform value="iOSSimARM64">False</Platform> + <Platform value="Win64x">False</Platform> </Platforms> </BorlandProject> <ProjectFileVersion>12</ProjectFileVersion> 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 @@ -<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <ProjectGuid>{B0F48139-24FB-42F3-93E8-05DA2E142904}</ProjectGuid> - <MainSource>PythonFmxLinux.dpk</MainSource> - <Base>True</Base> - <Config Condition="'$(Config)'==''">Release</Config> - <TargetedPlatforms>128</TargetedPlatforms> - <AppType>Package</AppType> - <FrameworkType>FMX</FrameworkType> - <ProjectVersion>19.5</ProjectVersion> - <Platform Condition="'$(Platform)'==''">Linux64</Platform> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''"> - <Base_Android>true</Base_Android> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''"> - <Base_Android64>true</Base_Android64> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''"> - <Base_iOSDevice64>true</Base_iOSDevice64> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''"> - <Base_Win32>true</Base_Win32> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''"> - <Cfg_1>true</Cfg_1> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Linux64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Linux64)'!=''"> - <Cfg_1_Linux64>true</Cfg_1_Linux64> - <CfgParent>Cfg_1</CfgParent> - <Cfg_1>true</Cfg_1> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''"> - <Cfg_2>true</Cfg_2> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Android64)'!=''"> - <Cfg_2_Android64>true</Cfg_2_Android64> - <CfgParent>Cfg_2</CfgParent> - <Cfg_2>true</Cfg_2> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Cfg_2)'=='true') or '$(Cfg_2_iOSDevice64)'!=''"> - <Cfg_2_iOSDevice64>true</Cfg_2_iOSDevice64> - <CfgParent>Cfg_2</CfgParent> - <Cfg_2>true</Cfg_2> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='OSX64' and '$(Cfg_2)'=='true') or '$(Cfg_2_OSX64)'!=''"> - <Cfg_2_OSX64>true</Cfg_2_OSX64> - <CfgParent>Cfg_2</CfgParent> - <Cfg_2>true</Cfg_2> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='OSXARM64' and '$(Cfg_2)'=='true') or '$(Cfg_2_OSXARM64)'!=''"> - <Cfg_2_OSXARM64>true</Cfg_2_OSXARM64> - <CfgParent>Cfg_2</CfgParent> - <Cfg_2>true</Cfg_2> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Base)'!=''"> - <DCC_E>false</DCC_E> - <DCC_F>false</DCC_F> - <DCC_K>false</DCC_K> - <DCC_N>false</DCC_N> - <DCC_S>false</DCC_S> - <DCC_ImageBase>00400000</DCC_ImageBase> - <GenDll>true</GenDll> - <GenPackage>true</GenPackage> - <SanitizedProjectName>PythonFmxLinux</SanitizedProjectName> - <DCC_Description>Python4Delphi - Run-time Engine Package for FMXLinux</DCC_Description> - <DllSuffix>$(Auto)</DllSuffix> - <RuntimeOnlyPackage>true</RuntimeOnlyPackage> - <VerInfo_Locale>1046</VerInfo_Locale> - <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=</VerInfo_Keys> - <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;REST.Authenticator.OAuth.WebForm;$(DCC_Namespace)</DCC_Namespace> - <DCC_UnitSearchPath>$(BDSCatalogRepositoryAllUsers)\FmxLinux-1.71\redist;$(DCC_UnitSearchPath)</DCC_UnitSearchPath> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Android)'!=''"> - <VerInfo_Keys>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=</VerInfo_Keys> - <BT_BuildType>Debug</BT_BuildType> - <Android_LauncherIcon192>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png</Android_LauncherIcon192> - <EnabledSysJars>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</EnabledSysJars> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Android64)'!=''"> - <Android_LauncherIcon192>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png</Android_LauncherIcon192> - <EnabledSysJars>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</EnabledSysJars> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''"> - <iOS_AppStore1024>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png</iOS_AppStore1024> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win32)'!=''"> - <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace> - <BT_BuildType>Debug</BT_BuildType> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys> - <VerInfo_Locale>1033</VerInfo_Locale> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1)'!=''"> - <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> - <DCC_DebugInformation>0</DCC_DebugInformation> - <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> - <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1_Linux64)'!=''"> - <Debugger_Launcher>/usr/bin/gnome-terminal -- "%debuggee%"</Debugger_Launcher> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2)'!=''"> - <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define> - <DCC_Optimize>false</DCC_Optimize> - <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames> - <DCC_RangeChecking>true</DCC_RangeChecking> - <DCC_IntegerOverflowCheck>true</DCC_IntegerOverflowCheck> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2_Android64)'!=''"> - <BT_BuildType>Debug</BT_BuildType> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2_iOSDevice64)'!=''"> - <BT_BuildType>Debug</BT_BuildType> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2_OSX64)'!=''"> - <BT_BuildType>Debug</BT_BuildType> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2_OSXARM64)'!=''"> - <BT_BuildType>Debug</BT_BuildType> - </PropertyGroup> - <ItemGroup> - <DelphiCompile Include="$(MainSource)"> - <MainSource>MainSource</MainSource> - </DelphiCompile> - <DCCReference Include="rtl.dcp"/> - <DCCReference Include="python.dcp"/> - <DCCReference Include="fmx.dcp"/> - <DCCReference Include="..\..\..\Source\fmx\FMX.PythonGUIInputOutput.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapDelphiFmx.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxActnList.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxColors.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxComCtrls.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxControls.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxDialogs.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxEdit.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxForms.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxGrids.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxLayouts.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxListBox.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxListView.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxMedia.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxMemo.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxMenus.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxScrollBox.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxShapes.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxStdActns.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxStdCtrls.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxStyles.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxTypes.pas"/> - <DCCReference Include="..\..\..\Source\fmx\WrapFmxDateTime.pas"/> - <BuildConfiguration Include="Base"> - <Key>Base</Key> - </BuildConfiguration> - <BuildConfiguration Include="Release"> - <Key>Cfg_1</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - <BuildConfiguration Include="Debug"> - <Key>Cfg_2</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - </ItemGroup> - <ProjectExtensions> - <Borland.Personality>Delphi.Personality.12</Borland.Personality> - <Borland.ProjectType>Package</Borland.ProjectType> - <BorlandProject> - <Delphi.Personality> - <Source> - <Source Name="MainSource">PythonFmxLinux.dpk</Source> - </Source> - <Excluded_Packages> - <Excluded_Packages Name="$(BDSBIN)\bcboffice2k280.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages> - <Excluded_Packages Name="$(BDSBIN)\bcbofficexp280.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages> - <Excluded_Packages Name="$(BDSBIN)\dcloffice2k280.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages> - <Excluded_Packages Name="$(BDSBIN)\dclofficexp280.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages> - </Excluded_Packages> - </Delphi.Personality> - <Platforms> - <Platform value="Android">False</Platform> - <Platform value="Android64">False</Platform> - <Platform value="iOSDevice64">False</Platform> - <Platform value="iOSSimARM64">False</Platform> - <Platform value="Linux64">True</Platform> - <Platform value="OSX64">False</Platform> - <Platform value="OSXARM64">False</Platform> - <Platform value="Win32">False</Platform> - <Platform value="Win64">False</Platform> - </Platforms> - <Deployment Version="4"> - <DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule"> - <Platform Name="iOSSimulator"> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule"> - <Platform Name="iOSSimulator"> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule"> - <Platform Name="OSX32"> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployFile LocalName="C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\Linux64\bplPythonFmxLinux280.so" Configuration="Release" Class="ProjectOutput"> - <Platform Name="Linux64"> - <RemoteName>bplPythonFmxLinux.so</RemoteName> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployFile LocalName="C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\PythonFmxLinux280.bpl" Configuration="Debug" Class="ProjectOutput"> - <Platform Name="Win32"> - <RemoteName>PythonFmxLinux.bpl</RemoteName> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployClass Name="AdditionalDebugSymbols"> - <Platform Name="OSX32"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidClasses"> - <Platform Name="Android"> - <RemoteDir>classes</RemoteDir> - <Operation>64</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>classes</RemoteDir> - <Operation>64</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidFileProvider"> - <Platform Name="Android"> - <RemoteDir>res\xml</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\xml</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidGDBServer"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeArmeabiFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeArmeabiv7aFile"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeMipsFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\mips</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\mips</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidServiceOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\arm64-v8a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidServiceOutput_Android32"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashImageDef"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStyles"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStylesV21"> - <Platform Name="Android"> - <RemoteDir>res\values-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Colors"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_DefaultAppIcon"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon144"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon192"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-ldpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-ldpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon24"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage426"> - <Platform Name="Android"> - <RemoteDir>res\drawable-small</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-small</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage470"> - <Platform Name="Android"> - <RemoteDir>res\drawable-normal</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-normal</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage640"> - <Platform Name="Android"> - <RemoteDir>res\drawable-large</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-large</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage960"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xlarge</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xlarge</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Strings"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DebugSymbols"> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyFramework"> - <Platform Name="OSX32"> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="OSX64"> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyModule"> - <Platform Name="OSX32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.dll;.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="DependencyPackage"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Name="File"> - <Platform Name="Android"> - <Operation>0</Operation> - </Platform> - <Platform Name="Android64"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX32"> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX64"> - <Operation>0</Operation> - </Platform> - <Platform Name="OSXARM64"> - <Operation>0</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iOS_AppStore1024"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_AppIcon152"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_AppIcon167"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_LaunchDark2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Notification40"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Setting58"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_SpotLight80"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_AppIcon120"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_AppIcon180"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch3x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_LaunchDark2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_LaunchDark3x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Notification40"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Notification60"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Setting58"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Setting87"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Spotlight120"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Spotlight80"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectAndroidManifest"> - <Platform Name="Android"> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSDeviceDebug"> - <Platform Name="iOSDevice32"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSEntitlements"/> - <DeployClass Name="ProjectiOSInfoPList"/> - <DeployClass Name="ProjectiOSLaunchScreen"/> - <DeployClass Name="ProjectiOSResource"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXDebug"/> - <DeployClass Name="ProjectOSXEntitlements"/> - <DeployClass Name="ProjectOSXInfoPList"/> - <DeployClass Name="ProjectOSXResource"> - <Platform Name="OSX32"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="ProjectOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\arm64-v8a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - </Platform> - <Platform Name="Linux64"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOutput_Android32"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectUWPManifest"> - <Platform Name="Win32"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo150"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo44"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="iOSSimARM64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="OSXARM64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/> - </Deployment> - </BorlandProject> - <ProjectFileVersion>12</ProjectFileVersion> - </ProjectExtensions> - <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/> - <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/> - <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/> -</Project> 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 @@ <MainSource>PythonVcl.dpk</MainSource> <Platform Condition="'$(Platform)'==''">Win32</Platform> <ProjectGuid>{D8908301-393C-4CFA-8842-4948A9935E21}</ProjectGuid> - <ProjectVersion>19.5</ProjectVersion> + <ProjectName Condition="'$(ProjectName)'==''">PythonVcl</ProjectName> + <ProjectVersion>20.1</ProjectVersion> <TargetedPlatforms>3</TargetedPlatforms> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> @@ -144,13 +145,14 @@ <Platforms> <Platform value="Android">False</Platform> <Platform value="Android64">False</Platform> + <Platform value="iOSDevice64">False</Platform> + <Platform value="iOSSimARM64">False</Platform> <Platform value="Linux64">False</Platform> <Platform value="OSX64">False</Platform> <Platform value="OSXARM64">False</Platform> <Platform value="Win32">True</Platform> <Platform value="Win64">True</Platform> - <Platform value="iOSDevice64">False</Platform> - <Platform value="iOSSimARM64">False</Platform> + <Platform value="Win64x">False</Platform> </Platforms> </BorlandProject> <ProjectFileVersion>12</ProjectFileVersion> 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 @@ <MainSource>dclPython.dpk</MainSource> <Platform Condition="'$(Platform)'==''">Win32</Platform> <ProjectGuid>{D9AB994C-54A3-4E76-81C8-6D0BB035A091}</ProjectGuid> - <ProjectVersion>19.5</ProjectVersion> + <ProjectName Condition="'$(ProjectName)'==''">dclPython</ProjectName> + <ProjectVersion>20.1</ProjectVersion> <TargetedPlatforms>1</TargetedPlatforms> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> @@ -149,6 +150,7 @@ <Platform value="OSXARM64">False</Platform> <Platform value="Win32">True</Platform> <Platform value="Win64">False</Platform> + <Platform value="Win64x">False</Platform> <Platform value="iOSDevice64">False</Platform> <Platform value="iOSSimARM64">False</Platform> </Platforms> 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 @@ <MainSource>dclPythonFmx.dpk</MainSource> <Platform Condition="'$(Platform)'==''">Win32</Platform> <ProjectGuid>{E057921E-25DB-426E-8090-FE3F428894FF}</ProjectGuid> - <ProjectVersion>19.5</ProjectVersion> + <ProjectName Condition="'$(ProjectName)'==''">dclPythonFmx</ProjectName> + <ProjectVersion>20.1</ProjectVersion> <TargetedPlatforms>1</TargetedPlatforms> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> @@ -125,6 +126,7 @@ <Platform value="OSXARM64">False</Platform> <Platform value="Win32">True</Platform> <Platform value="Win64">False</Platform> + <Platform value="Win64x">False</Platform> <Platform value="iOSDevice64">False</Platform> <Platform value="iOSSimARM64">False</Platform> </Platforms> 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 @@ <MainSource>dclPythonVcl.dpk</MainSource> <Platform Condition="'$(Platform)'==''">Win32</Platform> <ProjectGuid>{48DDC28A-E154-4CA0-864A-30EB8C4CCBB3}</ProjectGuid> - <ProjectVersion>19.5</ProjectVersion> + <ProjectName Condition="'$(ProjectName)'==''">dclPythonVcl</ProjectName> + <ProjectVersion>20.1</ProjectVersion> <TargetedPlatforms>1</TargetedPlatforms> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> @@ -125,6 +126,7 @@ <Platform value="OSXARM64">False</Platform> <Platform value="Win32">True</Platform> <Platform value="Win64">False</Platform> + <Platform value="Win64x">False</Platform> <Platform value="iOSDevice64">False</Platform> <Platform value="iOSSimARM64">False</Platform> </Platforms> 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 @@ -<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <ProjectGuid>{8BE1193B-E609-445D-9BA3-F57DBEA042F5}</ProjectGuid> - </PropertyGroup> - <ItemGroup> - <Projects Include="Delphi 10.4+\Python.dproj"> - <Dependencies/> - </Projects> - <Projects Include="Delphi 10.4+\dclPython.dproj"> - <Dependencies>Delphi 10.4+\Python.dproj</Dependencies> - </Projects> - <Projects Include="Delphi 10.4+\PythonVcl.dproj"> - <Dependencies>Delphi 10.4+\Python.dproj</Dependencies> - </Projects> - <Projects Include="Delphi 10.4+\dclPythonVcl.dproj"> - <Dependencies>Delphi 10.4+\PythonVcl.dproj</Dependencies> - </Projects> - <Projects Include="Delphi 10.4+\PythonFmx.dproj"> - <Dependencies/> - </Projects> - <Projects Include="Delphi 10.4+\PythonFmxLinux.dproj"> - <Dependencies/> - </Projects> - <Projects Include="Delphi 10.4+\dclPythonFmx.dproj"> - <Dependencies/> - </Projects> - </ItemGroup> - <ProjectExtensions> - <Borland.Personality>Default.Personality.12</Borland.Personality> - <Borland.ProjectType/> - <BorlandProject> - <Default.Personality/> - </BorlandProject> - </ProjectExtensions> - <Target Name="Python"> - <MSBuild Projects="Delphi 10.4+\Python.dproj"/> - </Target> - <Target Name="Python:Clean"> - <MSBuild Projects="Delphi 10.4+\Python.dproj" Targets="Clean"/> - </Target> - <Target Name="Python:Make"> - <MSBuild Projects="Delphi 10.4+\Python.dproj" Targets="Make"/> - </Target> - <Target Name="dclPython" DependsOnTargets="Python"> - <MSBuild Projects="Delphi 10.4+\dclPython.dproj"/> - </Target> - <Target Name="dclPython:Clean" DependsOnTargets="Python:Clean"> - <MSBuild Projects="Delphi 10.4+\dclPython.dproj" Targets="Clean"/> - </Target> - <Target Name="dclPython:Make" DependsOnTargets="Python:Make"> - <MSBuild Projects="Delphi 10.4+\dclPython.dproj" Targets="Make"/> - </Target> - <Target Name="PythonVcl" DependsOnTargets="Python"> - <MSBuild Projects="Delphi 10.4+\PythonVcl.dproj"/> - </Target> - <Target Name="PythonVcl:Clean" DependsOnTargets="Python:Clean"> - <MSBuild Projects="Delphi 10.4+\PythonVcl.dproj" Targets="Clean"/> - </Target> - <Target Name="PythonVcl:Make" DependsOnTargets="Python:Make"> - <MSBuild Projects="Delphi 10.4+\PythonVcl.dproj" Targets="Make"/> - </Target> - <Target Name="dclPythonVcl" DependsOnTargets="PythonVcl"> - <MSBuild Projects="Delphi 10.4+\dclPythonVcl.dproj"/> - </Target> - <Target Name="dclPythonVcl:Clean" DependsOnTargets="PythonVcl:Clean"> - <MSBuild Projects="Delphi 10.4+\dclPythonVcl.dproj" Targets="Clean"/> - </Target> - <Target Name="dclPythonVcl:Make" DependsOnTargets="PythonVcl:Make"> - <MSBuild Projects="Delphi 10.4+\dclPythonVcl.dproj" Targets="Make"/> - </Target> - <Target Name="PythonFmx"> - <MSBuild Projects="Delphi 10.4+\PythonFmx.dproj"/> - </Target> - <Target Name="PythonFmx:Clean"> - <MSBuild Projects="Delphi 10.4+\PythonFmx.dproj" Targets="Clean"/> - </Target> - <Target Name="PythonFmx:Make"> - <MSBuild Projects="Delphi 10.4+\PythonFmx.dproj" Targets="Make"/> - </Target> - <Target Name="PythonFmxLinux"> - <MSBuild Projects="Delphi 10.4+\PythonFmxLinux.dproj"/> - </Target> - <Target Name="PythonFmxLinux:Clean"> - <MSBuild Projects="Delphi 10.4+\PythonFmxLinux.dproj" Targets="Clean"/> - </Target> - <Target Name="PythonFmxLinux:Make"> - <MSBuild Projects="Delphi 10.4+\PythonFmxLinux.dproj" Targets="Make"/> - </Target> - <Target Name="dclPythonFmx"> - <MSBuild Projects="Delphi 10.4+\dclPythonFmx.dproj"/> - </Target> - <Target Name="dclPythonFmx:Clean"> - <MSBuild Projects="Delphi 10.4+\dclPythonFmx.dproj" Targets="Clean"/> - </Target> - <Target Name="dclPythonFmx:Make"> - <MSBuild Projects="Delphi 10.4+\dclPythonFmx.dproj" Targets="Make"/> - </Target> - <Target Name="Build"> - <CallTarget Targets="Python;dclPython;PythonVcl;dclPythonVcl;PythonFmx;PythonFmxLinux;dclPythonFmx"/> - </Target> - <Target Name="Clean"> - <CallTarget Targets="Python:Clean;dclPython:Clean;PythonVcl:Clean;dclPythonVcl:Clean;PythonFmx:Clean;PythonFmxLinux:Clean;dclPythonFmx:Clean"/> - </Target> - <Target Name="Make"> - <CallTarget Targets="Python:Make;dclPython:Make;PythonVcl:Make;dclPythonVcl:Make;PythonFmx:Make;PythonFmxLinux:Make;dclPythonFmx:Make"/> - </Target> - <Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/> -</Project> 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 <pyscripter@gmail.com> Date: Tue, 10 Dec 2024 02:08:08 +0200 Subject: [PATCH 37/55] 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 <pyscripter@gmail.com> Date: Tue, 10 Dec 2024 02:46:24 +0200 Subject: [PATCH 38/55] 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 <pyscripter@gmail.com> Date: Tue, 10 Dec 2024 03:15:44 +0200 Subject: [PATCH 39/55] 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 <pyscripter@gmail.com> Date: Fri, 13 Dec 2024 18:12:04 +0200 Subject: [PATCH 40/55] 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 <pyscripter@gmail.com> Date: Tue, 17 Dec 2024 01:55:40 +0200 Subject: [PATCH 41/55] 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 <pyscripter@gmail.com> Date: Sun, 29 Dec 2024 01:07:50 +0200 Subject: [PATCH 42/55] 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 <pyscripter@gmail.com> Date: Tue, 7 Jan 2025 13:20:47 +0200 Subject: [PATCH 43/55] 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 <pyscripter@gmail.com> Date: Sat, 8 Mar 2025 00:54:27 +0200 Subject: [PATCH 44/55] 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 <pyscripter@gmail.com> Date: Wed, 9 Apr 2025 17:28:47 +0300 Subject: [PATCH 45/55] 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 <pyscripter@gmail.com> Date: Thu, 10 Apr 2025 05:23:15 +0300 Subject: [PATCH 46/55] 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<PPyObject>(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<Pointer>(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<PPyObject> then + if Value.TypeInfo = TypeInfo(PPyObject) then Result := Value.AsType<PPyObject> else - begin - Result := nil; - ErrMsg := rs_ErrValueToPython; - end; + Result := DelphiWrapper.Engine.PyLong_FromVoidPtr(Value.AsType<Pointer>); 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<string>(List.GetItem(0), 'abc'); end; +procedure TTestWrapDelphi.TestPointers; +begin + rtti_var.PointerField := $FFFF; + Assert.AreEqual<NativeUInt>(rtti_var.PointerField, $FFFF); +end; + procedure TTestWrapDelphi.TestRecord; begin Rtti_rec.StringField := 'abcd'; From 92717b84a747285b5cb932f71ec454317329239d Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Sun, 13 Apr 2025 02:15:28 +0300 Subject: [PATCH 47/55] 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 <pyscripter@gmail.com> Date: Thu, 1 May 2025 16:15:52 +0300 Subject: [PATCH 48/55] 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 <pyscripter@gmail.com> Date: Sat, 21 Jun 2025 23:17:48 +0300 Subject: [PATCH 49/55] 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 <pyscripter@gmail.com> Date: Wed, 9 Jul 2025 05:15:52 +0300 Subject: [PATCH 50/55] 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 <pyscripter@gmail.com> Date: Wed, 9 Jul 2025 14:55:43 +0300 Subject: [PATCH 51/55] 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 + From 94b179ac0bc5d03a6f80298ae3036bd19e7461a1 Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Sat, 12 Jul 2025 21:59:25 +0300 Subject: [PATCH 52/55] CreateModuleFunctions can be called before the Module is initialized --- Source/WrapDelphi.pas | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index a19bc718..779ce506 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -5419,12 +5419,11 @@ procedure TPyDelphiWrapper.Initialize; with TPythonType(fHelperClassRegister.Objects[i]) do if not Initialized then Initialize; // Initialize module - if Assigned(FModule) then begin + if Assigned(FModule) then + begin + CreateModuleFunctions; if Module.Initialized then - begin - CreateModuleFunctions; - CreateModuleVars; - end + CreateModuleVars else Module.AddClient( Self ); end; @@ -5433,7 +5432,6 @@ procedure TPyDelphiWrapper.Initialize; procedure TPyDelphiWrapper.ModuleReady(Sender : TObject); begin inherited; - CreateModuleFunctions; CreateModuleVars; end; @@ -5542,13 +5540,13 @@ procedure TPyDelphiWrapper.SetModule(const Value: TPythonModule); TPythonType(fHelperClassRegister.Objects[i]).Module := Value; if Assigned(FModule) then if Initialized and (ComponentState * [csDesigning, csLoading] = []) then + begin + CreateModuleFunctions; if FModule.Initialized then - begin - CreateModuleFunctions; - CreateModuleVars; - end + CreateModuleVars else FModule.AddClient(Self); + end; end; end; From 2f9efc333a6b5f4f550de6f399891e2fc8ebe907 Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Sat, 12 Jul 2025 23:00:50 +0300 Subject: [PATCH 53/55] A call to Free is needed in TestVCL.py --- Modules/DelphiVCL/TestVCL.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/DelphiVCL/TestVCL.py b/Modules/DelphiVCL/TestVCL.py index 2641d390..deae197c 100644 --- a/Modules/DelphiVCL/TestVCL.py +++ b/Modules/DelphiVCL/TestVCL.py @@ -40,6 +40,7 @@ def main(): f.Show() FreeConsole() Application.Run() + f.Free() main() From 2957db674d944e94367792e610faf06f4514170f Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Sat, 12 Jul 2025 23:12:09 +0300 Subject: [PATCH 54/55] Multi-phase module initialization implemented. DemoModule/uMain.pas and RttiModule/uMain.pas have been updated to showcase multi-phase initialization --- Modules/DemoModule/uMain.pas | 18 ++- Modules/RttiModule/uMain.pas | 35 ++-- Source/PythonEngine.pas | 306 ++++++++++++++++++++++------------- Source/WrapDelphi.pas | 2 +- 4 files changed, 235 insertions(+), 126 deletions(-) diff --git a/Modules/DemoModule/uMain.pas b/Modules/DemoModule/uMain.pas index 8df2b082..922ef62e 100644 --- a/Modules/DemoModule/uMain.pas +++ b/Modules/DemoModule/uMain.pas @@ -7,13 +7,14 @@ interface function PyInit_DemoModule: PPyObject; cdecl; implementation -Uses +uses + Winapi.Windows, System.Math, WrapDelphi; var - gEngine : TPythonEngine; - gModule : TPythonModule; + gEngine : TPythonEngine = nil; + gModule : TPythonModule = nil; function IsPrime(x: Integer): Boolean; // Naive implementation. It is just a demo @@ -46,6 +47,7 @@ function delphi_is_prime(self, args : PPyObject) : PPyObject; cdecl; function PyInit_DemoModule: PPyObject; begin + if not Assigned(gEngine) then try gEngine := TPythonEngine.Create(nil); gEngine.AutoFinalize := False; @@ -56,12 +58,18 @@ function PyInit_DemoModule: PPyObject; gModule.ModuleName := 'DemoModule'; gModule.AddMethod('is_prime', delphi_is_prime, 'is_prime(n) -> bool' ); + // We need to set this so that the module is not created by Initialzize + gModule.IsExtensionModule := True; + gModule.MultInterpretersSupport := mmiPerInterpreterGIL; + gEngine.LoadDllInExtensionModule; except + Exit(nil); end; - Result := gModule.Module; -end; + // The python import machinery will create the python module from ModuleDef + Result := gEngine.PyModuleDef_Init(@gModule.ModuleDef); +end; initialization finalization diff --git a/Modules/RttiModule/uMain.pas b/Modules/RttiModule/uMain.pas index 386b522f..38b5be84 100644 --- a/Modules/RttiModule/uMain.pas +++ b/Modules/RttiModule/uMain.pas @@ -17,6 +17,7 @@ implementation TDelphiFunctions = class public class function is_prime(const N: Integer): Boolean; static; + class procedure AfterModuleInit(Sender: TObject); end; var @@ -25,32 +26,37 @@ TDelphiFunctions = class gDelphiWrapper : TPyDelphiWrapper; DelphiFunctions: TDelphiFunctions; - - function PyInit_DemoModule: PPyObject; -var - Py : PPyObject; begin + if not Assigned(gEngine) then try gEngine := TPythonEngine.Create(nil); gEngine.AutoFinalize := False; gEngine.UseLastKnownVersion := True; + gDelphiWrapper := TPyDelphiWrapper.Create(nil); + gDelphiWrapper.Engine := gEngine; + + // !!It is important that the extension module is the last + // Engine client created gModule := TPythonModule.Create(nil); gModule.Engine := gEngine; gModule.ModuleName := 'DemoModule'; - gDelphiWrapper := TPyDelphiWrapper.Create(nil); - gDelphiWrapper.Engine := gEngine; + // Set IsExtensionModule so that the module is not created by Initialzize + gModule.IsExtensionModule := True; + gModule.MultInterpretersSupport := mmiPerInterpreterGIL; + gModule.OnAfterInitialization := TDelphiFunctions.AfterModuleInit; + gDelphiWrapper.Module := gModule; gEngine.LoadDllInExtensionModule; - Py := gDelphiWrapper.Wrap(DelphiFunctions, TObjectOwnership.soReference); - gModule.SetVar('delphi_funcs', Py); - gEngine.Py_DecRef(Py); except + Exit(nil); end; - Result := gModule.Module; + + // The python import machinery will create the python module from ModuleDef + Result := gEngine.PyModuleDef_Init(@gModule.ModuleDef); end; { TTestRttiAccess } @@ -58,6 +64,15 @@ function PyInit_DemoModule: PPyObject; { TDelphiFunctions } +class procedure TDelphiFunctions.AfterModuleInit(Sender: TObject); +var + Py : PPyObject; +begin + Py := gDelphiWrapper.Wrap(DelphiFunctions, TObjectOwnership.soReference); + gModule.SetVar('delphi_funcs', Py); + gEngine.Py_DecRef(Py); +end; + class function TDelphiFunctions.is_prime(const N: Integer): Boolean; // Naive implementation. It is just a demo... begin diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 11ad3803..1d3cd846 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -642,6 +642,7 @@ TPythonVersionProp = record PyModuleDef_Slot = {$IFDEF CPUX86}packed{$ENDIF} record slot: integer; value: Pointer; + class function Make(slot: integer; value: Pointer): PyModuleDef_Slot; static; end; PPyModuleDef = ^PyModuleDef; @@ -1953,7 +1954,6 @@ TPythonInterface=class(TDynamicDll) function PyWeakref_CheckProxy( obj : PPyObject ) : Boolean; function PyBool_Check( obj : PPyObject ) : Boolean; function PyEnum_Check( obj : PPyObject ) : Boolean; - function Py_InitModule( const md : PyModuleDef) : PPyObject; // The following are defined as non-exported inline functions in object.h function Py_Type(ob: PPyObject): PPyTypeObject; inline; @@ -2138,6 +2138,7 @@ TPythonEngine = class(TPythonInterface) function ArrayToPyDict( const items : array of const) : PPyObject; function StringsToPyList( strings : TStrings ) : PPyObject; function StringsToPyTuple( strings : TStrings ) : PPyObject; + function Py_InitModule( const md : PyModuleDef) : PPyObject; procedure PyListToStrings(list: PPyObject; Strings: TStrings; ClearStrings: Boolean = True); procedure PyTupleToStrings( tuple: PPyObject; strings : TStrings ); function GetSequenceItem( sequence : PPyObject; idx : Integer ) : Variant; @@ -2303,7 +2304,6 @@ TMethodsContainer = class(TEngineClient) FMethodCount : Integer; FAllocatedMethodCount : Integer; FMethods : PPyMethodDef; - FModuleDef : PyModuleDef; FEventDefs: TEventDefs; procedure AllocMethods; @@ -2347,7 +2347,6 @@ TMethodsContainer = class(TEngineClient) property MethodCount : Integer read FMethodCount; property Methods[ idx : Integer ] : PPyMethodDef read GetMethods; property MethodsData : PPyMethodDef read FMethods; - property ModuleDef : PyModuleDef read FModuleDef; published property Events: TEventDefs read fEventDefs write fEventDefs stored StoreEventDefs; @@ -2502,56 +2501,68 @@ TErrors = class(TCollection) property Items[Index: Integer]: TError read GetError write SetError; default; end; + TMultIntperpretersSupport = (mmiSupported, mmiNotSupported, mmiPerInterpreterGIL); + {$IF not Defined(FPC) and (CompilerVersion >= 23)} [ComponentPlatformsAttribute(pidSupportedPlatforms)] {$IFEND} TPythonModule = class(TMethodsContainer) - protected - FModuleName : AnsiString; - FModule : PPyObject; - FClients : TList; - FErrors : TErrors; - FOnAfterInitialization : TNotifyEvent; - FDocString : TStringList; - - function GetClientCount : Integer; - function GetClients( idx : Integer ) : TEngineClient; - procedure SetErrors( val : TErrors ); - procedure SetModuleName( const val : AnsiString ); - procedure SetDocString( value : TStringList ); - public - // Constructors & destructors - constructor Create( AOwner : TComponent ); override; - destructor Destroy; override; + private + FModuleDef : PyModuleDef; + FMultInterpretersSupport: TMultIntperpretersSupport; + FEncodedDocString: AnsiString; + FIsExtensionModule: Boolean; + function Exec_Module(module: PPyObject): Integer; cdecl; // used in the slot + protected + FModuleName : AnsiString; + FModule : PPyObject; + FSlots: TArray<PyModuleDef_Slot>; + FClients : TList; + FErrors : TErrors; + FDocString : TStringList; + FOnAfterInitialization : TNotifyEvent; + + function GetClientCount : Integer; + function GetClients( idx : Integer ) : TEngineClient; + procedure SetErrors( val : TErrors ); + procedure SetModuleName( const val : AnsiString ); + procedure SetDocString( value : TStringList ); + public + // Constructors & destructors + constructor Create( AOwner : TComponent ); override; + destructor Destroy; override; - // Public methods - procedure MakeModule; - procedure DefineDocString; - procedure Initialize; override; - procedure InitializeForNewInterpreter; - procedure AddClient(Client : TEngineClient); - procedure RemoveClient(Client : TEngineClient); - function ErrorByName( const AName : AnsiString ) : TError; - procedure RaiseError( const error, msg : AnsiString ); - procedure RaiseErrorFmt( const error, format : AnsiString; const Args : array of const ); - procedure RaiseErrorObj( const error, msg : AnsiString; obj : PPyObject ); - procedure BuildErrors; - procedure SetVar( const varName : AnsiString; value : PPyObject ); - function GetVar( const varName : AnsiString ) : PPyObject; - procedure DeleteVar( const varName : AnsiString ); - procedure ClearVars; - procedure SetVarFromVariant( const varName : AnsiString; const value : Variant ); - function GetVarAsVariant( const varName: AnsiString ) : Variant; + // Public methods + procedure MakeModuleDef; + procedure Initialize; override; + procedure InitializeForNewInterpreter; + procedure AddClient(Client : TEngineClient); + procedure RemoveClient(Client : TEngineClient); + function ErrorByName( const AName : AnsiString ) : TError; + procedure RaiseError( const error, msg : AnsiString ); + procedure RaiseErrorFmt( const error, format : AnsiString; const Args : array of const ); + procedure RaiseErrorObj( const error, msg : AnsiString; obj : PPyObject ); + procedure BuildErrors; + procedure SetVar( const varName : AnsiString; value : PPyObject ); + function GetVar( const varName : AnsiString ) : PPyObject; + procedure DeleteVar( const varName : AnsiString ); + procedure ClearVars; + procedure SetVarFromVariant( const varName : AnsiString; const value : Variant ); + function GetVarAsVariant( const varName: AnsiString ) : Variant; - // Public properties - property Module : PPyObject read FModule; - property Clients[ idx : Integer ] : TEngineClient read GetClients; - property ClientCount : Integer read GetClientCount; - published - property DocString : TStringList read FDocString write SetDocString; - property ModuleName : AnsiString read FModuleName write SetModuleName; - property Errors : TErrors read FErrors write SetErrors; - property OnAfterInitialization : TNotifyEvent read FOnAfterInitialization write FOnAfterInitialization; + // Public properties + property Module : PPyObject read FModule; + property ModuleDef : PyModuleDef read FModuleDef; + property IsExtensionModule: Boolean read FIsExtensionModule write FIsExtensionModule; + property Clients[ idx : Integer ] : TEngineClient read GetClients; + property ClientCount : Integer read GetClientCount; + published + property DocString : TStringList read FDocString write SetDocString; + property ModuleName : AnsiString read FModuleName write SetModuleName; + property MultInterpretersSupport: TMultIntperpretersSupport + read FMultInterpretersSupport write FMultInterpretersSupport; + property Errors : TErrors read FErrors write SetErrors; + property OnAfterInitialization : TNotifyEvent read FOnAfterInitialization write FOnAfterInitialization; end; @@ -4449,21 +4460,6 @@ function TPythonInterface.PyObject_TypeCheck(obj: PPyObject; t: PPyTypeObject): Result := IsType(obj, t) or (PyType_IsSubtype(obj^.ob_type, t) = 1); end; -function TPythonInterface.Py_InitModule(const md: PyModuleDef): PPyObject; -Var - modules : PPyObject; -begin - CheckPython; - Result:= PyModule_Create2(@md, APIVersion); - if not Assigned(Result) then - GetPythonEngine.CheckError; - // To emulate Py_InitModule4 we need to add the module to sys.modules - modules := PyImport_GetModuleDict; - if PyDict_SetItemString(modules, md.m_name, Result) <> 0 then - GetPythonEngine.CheckError; -end; - - (*******************************************************) (** **) (** class TPythonTraceback **) @@ -5100,13 +5096,13 @@ procedure TPythonEngine.Initialize; // fix #504 if not FRedirectIO and UseWindowsConsole then PyRun_SimpleString( - 'import sys, io'#10 + + '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); + 'encoding="utf-8", errors="replace", line_buffering=True)'#10); {$ENDIF} if InitScript.Count > 0 then @@ -5837,13 +5833,13 @@ function TPythonEngine.TypeByName( const aTypeName : AnsiString ) : PPyTypeObjec raise Exception.CreateFmt(SCannotFindType, [aTypeName]); end; -function TPythonEngine.ModuleByName( const aModuleName : AnsiString ) : PPyObject; +function TPythonEngine.ModuleByName( const aModuleName : AnsiString ) : PPyObject; var i : Integer; begin for i := 0 to ClientCount - 1 do if Clients[i] is TPythonModule then - with TPythonModule( Clients[i] ) do + with TPythonModule(Clients[i]) do if ModuleName = aModuleName then begin Result := Module; @@ -6748,6 +6744,64 @@ function TPythonEngine.PyUnicodeFromString(const AString: AnsiString): PPyObject end; +function TPythonEngine.Py_InitModule(const md: PyModuleDef): PPyObject; +// Implements multi-phase module intialization +var + modules, importlib, spec_func, module_name, args, spec: PPyObject; +begin + CheckPython; + + importlib := nil; + spec_func := nil; + module_name := nil; + args := nil; + spec := nil; + + try + // We need a spec and for that we need importlib; + importlib := PyImport_ImportModule('importlib.util'); + if not Assigned(importlib) then CheckError; + + // Get spec_from_loader function + spec_func := PyObject_GetAttrString(importlib, 'spec_from_loader'); + if not Assigned(spec_func) then CheckError; + + // Create module name + module_name := PyUnicode_FromString(md.m_name); + if not Assigned(module_name) then CheckError; + + // Create arguments tuple for spec_from_loader(name, loader) + args := MakePyTuple([module_name, Py_None]); + + // Create the module specification + spec := PyObject_CallObject(spec_func, args); + if not Assigned(spec) then CheckError; + + // Create the module from the definition and spec + Result := PyModule_FromDefAndSpec2(@md, spec, APIVersion); + if not Assigned(spec) then CheckError; + + // Execute the module (triggers Py_mod_exec slot) + if (PyModule_ExecDef(Result, @md) < 0) then + begin + Py_DECREF(Result); + CheckError; + end; + + finally + Py_XDECREF(importlib); + Py_XDECREF(spec_func); + Py_XDECREF(module_name); + Py_XDECREF(args); + Py_XDECREF(spec); + end; + + // We need to add the module to sys.modules + modules := PyImport_GetModuleDict; + if PyDict_SetItemString(modules, md.m_name, Result) <> 0 then + GetPythonEngine.CheckError; +end; + (*******************************************************) (** **) (** class TEngineClient **) @@ -7610,6 +7664,7 @@ constructor TPythonModule.Create( AOwner : TComponent ); FClients := TList.Create; FErrors := TErrors.Create(Self); FDocString := TStringList.Create; + FDocString.TrailingLineBreak := False; end; destructor TPythonModule.Destroy; @@ -7625,52 +7680,59 @@ procedure TPythonModule.SetDocString( value : TStringList ); FDocString.Assign( value ); end; -procedure TPythonModule.DefineDocString; +procedure TPythonModule.MakeModuleDef; var - doc : PPyObject; + P: Pointer; begin - with Engine do - begin - if DocString.Text <> '' then - begin - doc := - PyUnicodeFromString(CleanString(FDocString.Text, False)); - PyObject_SetAttrString( FModule, '__doc__', doc ); - Py_XDecRef(doc); - CheckError(False); - end; - end; -end; + FillChar(FModuleDef, SizeOf(FModuleDef), 0); + FModuleDef.m_base.ob_refcnt := 1; + FModuleDef.m_name := PAnsiChar(ModuleName); + FModuleDef.m_methods := MethodsData; + FModuleDef.m_size := 0; -procedure TPythonModule.MakeModule; -begin - CheckEngine; - if Assigned(FModule) then - Exit; - with Engine do - begin - FillChar(FModuleDef, SizeOf(FModuleDef), 0); - FModuleDef.m_base.ob_refcnt := 1; - FModuleDef.m_name := PAnsiChar(ModuleName); - FModuleDef.m_methods := MethodsData; - FModuleDef.m_size := -1; - FModule := Py_InitModule( ModuleDef ); - DefineDocString; + // Doc string + if FDocString.Count > 0 then + begin + FEncodedDocString := UTF8Encode(CleanString(FDocString.Text, False)); + FModuleDef.m_doc := PAnsiChar(FEncodedDocString); + end; + + // Fill the m_slots for multi-phase initialization + FSlots := [PyModuleDef_Slot.Make(Py_mod_exec, + GetCallBack(Self, @TPythonModule.Exec_Module, 1, DEFAULT_CALLBACK_TYPE))]; + + if (Engine.MajorVersion > 3) or (Engine.MinorVersion >= 12) then + begin + case FMultInterpretersSupport of + mmiNotSupported: P := Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED; + mmiPerInterpreterGIL: P := Py_MOD_PER_INTERPRETER_GIL_SUPPORTED; + else + P := Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED; end; + FSlots := FSlots + [PyModuleDef_Slot.Make(Py_mod_multiple_interpreters, P)]; + end; + FSlots := FSlots + [PyModuleDef_Slot.Make(0, nil)]; + + FModuleDef.m_slots := @FSlots[0]; end; procedure TPythonModule.Initialize; -var - i : Integer; begin inherited; - FModule := nil; - MakeModule; - for i := 0 to ClientCount - 1 do - Clients[i].ModuleReady(Self); - BuildErrors; - if Assigned(FOnAfterInitialization) then - FOnAfterInitialization( Self ); + + if Assigned(FModule) then Exit; + + MakeModuleDef; + // Py_InitModule will call Exec_Module which will + // - Set FModule + // - initialize clients + // - Call OnInitialized + CheckEngine; + + // Extension modules are intilized directly from ModuleDef + if FIsExtensionModule then Exit; + + FModule := Engine.Py_InitModule(FModuleDef); end; procedure TPythonModule.InitializeForNewInterpreter; @@ -7709,6 +7771,21 @@ function TPythonModule.ErrorByName( const AName : AnsiString ) : TError; raise Exception.CreateFmt(SCouldNotFindError, [AName] ); end; +function TPythonModule.Exec_Module(module: PPyObject): Integer; +// Executed via the m_slots of PyModuleDef as part of the +// multi-phase module initialization +var + I : Integer; +begin + FModule := module; + for I := 0 to ClientCount - 1 do + Clients[I].ModuleReady(Self); + BuildErrors; + if Assigned(FOnAfterInitialization) then + FOnAfterInitialization(Self); + Result := 0; +end; + procedure TPythonModule.RaiseError( const error, msg : AnsiString ); begin ErrorByName( error ).RaiseError( msg ); @@ -7738,7 +7815,7 @@ procedure TPythonModule.BuildErrors; CheckEngine; with Engine do begin - d := PyModule_GetDict( Module ); + d := PyModule_GetDict(FModule); if not Assigned(d) then Exit; for i := 0 to Errors.Count - 1 do @@ -7757,7 +7834,7 @@ procedure TPythonModule.SetVar( const varName : AnsiString; value : PPyObject ); begin if Assigned(FEngine) and Assigned( FModule ) then begin - if Engine.PyObject_SetAttrString(Module, PAnsiChar(varName), value ) <> 0 then + if Engine.PyObject_SetAttrString(FModule, PAnsiChar(varName), value ) <> 0 then raise EPythonError.CreateFmt(SCouldNotSetVar, [varName, ModuleName]); end else @@ -7771,21 +7848,21 @@ function TPythonModule.GetVar( const varName : AnsiString ) : PPyObject; begin if Assigned(FEngine) and Assigned( FModule ) then begin - Result := Engine.PyObject_GetAttrString(Module, PAnsiChar(varName) ); + Result := Engine.PyObject_GetAttrString(FModule, PAnsiChar(varName) ); Engine.PyErr_Clear; end else raise EPythonError.CreateFmt(SCannotSetVarNoInit, [varName, ModuleName]); end; -procedure TPythonModule.DeleteVar( const varName : AnsiString ); +procedure TPythonModule.DeleteVar(const varName : AnsiString); var dict : PPyObject; begin if Assigned(FEngine) and Assigned( FModule ) then with Engine do begin - dict := PyModule_GetDict( Module ); + dict := PyModule_GetDict(FModule); if not Assigned(dict) then raise EPythonError.CreateFmt(SCannotGetDict, [ModuleName] ); PyDict_DelItemString( dict, PAnsiChar(varName) ); @@ -7800,7 +7877,7 @@ procedure TPythonModule.ClearVars; begin if Assigned(FEngine) and Assigned( FModule ) then with Engine do begin - dict := PyModule_GetDict( Module ); + dict := PyModule_GetDict(FModule); PyDict_Clear(dict); end; end; @@ -8932,7 +9009,7 @@ procedure TPythonType.InitServices; begin tp_init := TPythonType_InitSubtype; tp_alloc := FEngine.PyType_GenericAlloc; - tp_new := GetCallBack( Self, @TPythonType.NewSubtypeInst, 3, DEFAULT_CALLBACK_TYPE); + tp_new := GetCallBack(Self, @TPythonType.NewSubtypeInst, 3, DEFAULT_CALLBACK_TYPE); tp_free := FEngine.PyObject_Free; tp_methods := MethodsData; tp_members := MembersData; @@ -10173,5 +10250,14 @@ procedure ThreadPythonExec(ExecuteProc : TProc; TerminateProc : TProc; {$ENDIF FPC} +{ PyModuleDef_Slot } + +class function PyModuleDef_Slot.Make(slot: integer; + value: Pointer): PyModuleDef_Slot; +begin + Result.slot := slot; + Result.value := value; +end; + end. diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index 779ce506..03961972 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -1003,7 +1003,7 @@ TPyDelphiWrapper = class(TEngineClient, IFreeNotificationSubscriber) implementation -Uses +uses Math, StrUtils, RTLConsts, From a3d020ed979ec39866cef71618035771d3106f32 Mon Sep 17 00:00:00 2001 From: pyscripter <pyscripter@gmail.com> Date: Sat, 12 Jul 2025 23:35:57 +0300 Subject: [PATCH 55/55] Added 3.14 InterpreterPoolExecutor demo. --- Modules/DemoModule/InterpreterExecutor.py | 35 +++++++++++++++++++++++ Modules/DemoModule/prime_utils.py | 5 ++++ 2 files changed, 40 insertions(+) create mode 100644 Modules/DemoModule/InterpreterExecutor.py create mode 100644 Modules/DemoModule/prime_utils.py diff --git a/Modules/DemoModule/InterpreterExecutor.py b/Modules/DemoModule/InterpreterExecutor.py new file mode 100644 index 00000000..97cca2ab --- /dev/null +++ b/Modules/DemoModule/InterpreterExecutor.py @@ -0,0 +1,35 @@ +#------------------------------------------------------------------------------- +# Name: InterpreterExecutor.py +# Purpose: Showcases the use of extension modules created with Delphi +# with the new in Python 3.14 InterpreterPoolExecutor +# You need python 3.14 to run this demo +# It uses the support module prime_utils which imports +# the delphi created extension module. +# Note that each interpreters has its own GIL and +# they are all running in parallel. +#------------------------------------------------------------------------------- + +from concurrent.futures import InterpreterPoolExecutor +from prime_utils import count_primes_in_range +import time + +def count_primes(max_num, num_interpreters=4): + chunk_size = max_num // num_interpreters + ranges = [(i, min(i + chunk_size - 1, max_num)) for i in range(2, max_num + 1, chunk_size)] + print(ranges) + + total = 0 + with InterpreterPoolExecutor(max_workers=num_interpreters) as executor: + results = executor.map(count_primes_in_range, ranges) + total = sum(results) + + return total + +if __name__ == "__main__": + max_number = 1_000_000 + start_time = time.time() + prime_count = count_primes(max_number) + end_time = time.time() + + print(f"Count of prime numbers up to {max_number}: {prime_count}") + print(f"Time taken: {end_time - start_time:.2f} seconds") \ No newline at end of file diff --git a/Modules/DemoModule/prime_utils.py b/Modules/DemoModule/prime_utils.py new file mode 100644 index 00000000..29abdea3 --- /dev/null +++ b/Modules/DemoModule/prime_utils.py @@ -0,0 +1,5 @@ +# prime_utils.py +from DemoModule import is_prime + +def count_primes_in_range(arange): + return sum(1 for n in range(arange[0], arange[1] + 1) if is_prime(n))