type
TXXXXXXPython =
class(TObject)
private
FPythonEngine: TPythonEngine;
FPythonInputOutput: TPythonInputOutput;
FPythonModule: TPythonModule;
FPythonDelphiWrapper: TPyDelphiWrapper;
FPythonDelphiVar: TPythonDelphiVar;
FPythonOutput: RawByteString;
FInitScript:
String;
FUseInstalledPython: Boolean;
FDLLFilename:
string;
//leer sucht installiertes Python (Achtung: muß 32 Bit sein, egal ob Installiert oder Embedded)
//
function GetPythonOutput:
string;
function GetParamCount(Args: PPyObject): Integer;
function GetParam(Args: PPyObject;
Index: Integer; IsOptional: Boolean=False): Variant;
function CreateResult(Value: Variant): PPyObject;
function GetVariable(
Name:
string): Variant;
// [DCC Hinweis] H2219 Das private-Symbol 'GetVariable' wurde deklariert, aber nie verwendet -> aktuell auskommentiert, siehe TXXXXXXPython.Engine_Initialize
procedure SetVariable(
Name:
string; Value: Variant);
//
procedure InputOutputSendData(Sender: TObject;
const Data: AnsiString);
procedure ExecuteInitScript;
procedure FindPythonDLL;
public class var
_GetValueFromEdit:
function(FrameOrForm: TComponent; EditName:
string; UseParamsIfEmpty: Boolean=False): Variant;
// XXXXXXUtils.GetValueFromEdit für Py_GetValueFromEdit
_FillQueryParamsWithFormValues:
procedure(
Query: TCimQuery2; _Self: TComponent; DebugInfo:
string; AddPercent: Boolean=False; pOverride: Boolean=False);
// XXXXXXUtils._FillQueryParamsWithFormValues für Py_DBExecute/Py_DBSelect
public
RuntimeForm: TForm;
// TfrmToDesign
OwnerModul: TForm;
// TModulForm usw. (für GetValueFromEdit und FillQueryParamsWithFormValues)
constructor Create;
destructor Destroy;
override;
procedure Engine_Initialize;
procedure Engine_Finalize(doLog: Boolean = True);
//
function CheckExecute(Script:
string; RaiseError: Boolean = True): Boolean;
function Execute (Script:
string):
string;
//
function CheckEval (Script:
string; RaiseError: Boolean = True): Boolean;
function Eval (Script:
string): Variant;
//
property InitScript:
string read FInitScript
write FInitScript;
property Output:
string read GetPythonOutput;
property UseInstalledPython: Boolean
read FUseInstalledPython
write FUseInstalledPython;
property Engine: TPythonEngine
read FPythonEngine;
private
// Beschreibng der Parameter
// siehe in Implementation als Kommentar an den Funktionen
// bzw. siehe TXXXXXXPython.Engine_Initialize als Kommentar an Python (TODO: schauen wie das ins CodeComplete des SynEdit gelangt)
function Method_Test (PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_GetValueFromEdit(PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_GetSetting (PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_SetSetting (PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_GetBoolSetting (PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_SetBoolSetting (PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_GetIntSetting (PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_SetIntSetting (PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_DBExecute (PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_DBSelect (PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_DMSFileByDokID (PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_DMSFileByRecNo (PSelf, Args: PPyObject): PPyObject;
cdecl;
function Py_DMSFileImport (PSelf, Args: PPyObject): PPyObject;
cdecl;
end;
function EscapePythonString(S:
string):
string;
procedure TXXXXXXPython.Engine_Initialize;
begin
Engine_Finalize(False);
FPythonOutput := '
';
FPythonInputOutput := TPythonInputOutput.Create(
nil);
FPythonInputOutput.UnicodeIO := False;
FPythonInputOutput.OnSendData := InputOutputSendData;
// Non-RawOutput könnte zu Problemen führen,
// da 'unvollständige' Implementierung
FPythonInputOutput.RawOutput := True;
FPythonInputOutput.DelayWrites := False;
//https://github.com/pyscripter/python4delphi/wiki/FindingPython
FPythonEngine := TPythonEngine.Create(
nil);
FPythonEngine.AutoLoad := False;
FPythonEngine.FatalAbort := False;
FPythonEngine.FatalMsgDlg := False;
FPythonEngine.UseLastKnownVersion := UseInstalledPython;
//
if FDLLFilename <> '
'
then begin
FPythonEngine.DllName := ExtractFileName(FDLLFilename);
FPythonEngine.DllPath := ExtractFilePath(FDLLFilename);
FPythonEngine.SetPythonHome(FPythonEngine.DllPath);
//FPythonEngine.RegVersion := '3.9';
end;
//
FPythonEngine.IO := FPythonInputOutput;
FPythonModule := TPythonModule.Create(
nil);
FPythonModule.Engine := FPythonEngine;
FPythonModule.ModuleName := '
XXXXXX';
FPythonModule.DocString.Text := '
our XXXXXX-Modul: Functions and Variables inside XXXXXX-Client';
FPythonDelphiWrapper := TPyDelphiWrapper.Create(
nil);
FPythonDelphiWrapper.Engine := FPythonEngine;
FPythonDelphiWrapper.Module := FPythonModule;
// TODO: Ich weiß nicht warum, aber bei André funktioniert es, und bei mir nicht,
// weder im Embedded (DLLName) noch im installierten Python (UseLastKnownVersion).
// -> 'VariableXyz' object has no attribute 'Value'
// DemoCode im Scipt-Memo auskommentert (#)
//erledigt! gefixt: https://en.delphipraxis.net/topic/4323-pythondelphivar-thows-attributeerror-that-object-has-no-attribute-value-python-391-32bit/
FPythonDelphiVar := TPythonDelphiVar.Create(
nil);
FPythonDelphiVar.Engine := FPythonEngine;
FPythonDelphiVar.VarName := '
VariableXyz';
//FPythonDelphiVar.Module := '__main__'; // Python-MainModule: Variable global "VariableXyz.Value" oder als "__main__.VariableXyz.Value"
{ FPythonDelphiVar.OnChange := PythonDelphiVarOnChange;
FPythonDelphiVar.OnGetData := PythonDelphiVarOnGetData;
FPythonDelphiVar.OnSetData := PythonDelphiVarOnSetData; }
FPythonEngine.LoadDll;
if not(FPythonEngine.IsHandleValid)
then
raise Exception.Create('
PythonEngine.LoadDll: ' + SysErrorMessage(GetLastError));
if not(FPythonEngine.Initialized)
then begin
TPythonEngineAccess(FPythonEngine).Initialize;
if not(FPythonEngine.Initialized)
then
raise Exception.Create('
PythonEngine.Initialize: ' + SysErrorMessage(GetLastError));
end;
{$REGION 'PythonModule.OnInitialization'}
FPythonModule.AddDelphiMethod('
Method_Test', Method_Test, '
Method_Test(a, b)');
FPythonModule.AddDelphiMethod('
GetValueFromEdit', Py_GetValueFromEdit, '
GetValueFromEdit(EditName): Variant');
//FPythonModule.AddDelphiMethod('GetControlValue', Py_GetControlValue, 'GetControlValue(EditName): Variant');
//FPythonModule.AddDelphiMethod('SetControlValue', Py_SetControlValue, 'SetControlValue(EditName, Value)');
FPythonModule.AddDelphiMethod('
GetSetting', Py_GetSetting, '
GetSetting(Name): String');
FPythonModule.AddDelphiMethod('
SetSetting', Py_SetSetting, '
SetSetting(Name, StrValue)');
FPythonModule.AddDelphiMethod('
GetBoolSetting', Py_GetBoolSetting, '
GetBoolSetting(Name): Boolean');
FPythonModule.AddDelphiMethod('
SetBoolSetting', Py_SetBoolSetting, '
SetBoolSetting(Name, BoolValue)');
FPythonModule.AddDelphiMethod('
GetIntSetting', Py_GetIntSetting, '
GetIntSetting(Name): Integer');
FPythonModule.AddDelphiMethod('
SetIntSetting', Py_SetIntSetting, '
SetIntSetting(Name, IntValue)');
FPythonModule.AddDelphiMethod('
DBExecute', Py_DBExecute, '
DBExecute(InsertOrUpdateStatement)');
FPythonModule.AddDelphiMethod('
DBSelect', Py_DBSelect, '
DBSelect(SelectStatement): FirstStringBooleanOrInteger');
FPythonModule.AddDelphiMethod('
DMSFileByDokID', Py_DMSFileByDokID, '
DMSFileByDokID(pd_id): String');
FPythonModule.AddDelphiMethod('
DMSFileByRecNo', Py_DMSFileByRecNo, '
DMSFileByRecNo(TableName, RecId, [DokType], [OnlyStandard]): String');
FPythonModule.AddDelphiMethod('
DMSFileImport', Py_DMSFileImport, '
DMSFileImport(FileName, TableName, DBRID, [DokType], [DokIdent], [Caption]): Integer');
FPythonModule.Initialize;
FPythonDelphiWrapper.Initialize;
if Assigned(FPythonDelphiVar)
then
FPythonDelphiVar.Initialize;
//FPythonDelphiVar.Value := 20; //kann man vom Code setzen
FPythonModule.SetVarFromVariant('
Var123', 123456);
SetVariable('
Var456', 987654);
//v := GetVariable('Var456'); //es geht
//v := GetVariable('VariableXyz'); //es geht nicht
FPythonEngine.PyObject_SetAttrString(FPythonEngine.GetMainModule, '
Var456', FPythonEngine.VariantAsPyObject(987654));
{$ENDREGION}
//FPythonEngine.ExecString('weiterer Python-Code für Initialisierung'); // Standard-Module importieren, Variablen setzen, ...
//DoLogEvent('Python-Init: %dms', [Integer(TThread.GetTickCount - PythonRuntime)]);
end;
function TXXXXXXPython.Execute(Script:
string):
string;
var
Temp: RawByteString;
begin
Engine_Initialize;
try
ExecuteInitScript;
Temp := UTF8Encode(Script);
SetCodePage(Temp, CP_ACP, False);
// damit Delphi das UTF-8 nicht nach ANSI konvertiert, da die Parameter als ANSI deklariert wurden
FPythonEngine.ExecString(AnsiString(Temp));
//FPythonEngine.ExecString(FPythonEngine.EncodeString(Script)); -> EncodeString ist defekt
Result := Self.Output;
finally
Engine_Finalize;
end;
end;