|
![]() |
|
Registriert seit: 5. Nov 2014 Ort: Baden Württemberg 136 Beiträge Delphi 12 Athens |
#1
Jetzt habe ich es tatsächlich hinbekommen, dass er das entsprechende embedded python lädt.
Verwendest du immer das Embedded Python oder wechselst du auch zum "normal installierten" Python / oder zu einem venv?
Bastian
|
![]() |
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.338 Beiträge Delphi 12 Athens |
#2
Nee, wir nutzen immer das selbstmitgebrachte Python.
Da wir nicht kontrollieren können ob und welche Python-Version auf Kundensystemen installiert sind, haben wir so unser eigenes Python, mit welchem wir bei uns auch Testen konnten. Wäre es z.B. als 64 Bit installiert, dann kann es im Delphi unter 32 Bit nicht benutzt werden und es knallt. Sowie eben (noch) die etwas ältere Version, welche aber noch mit den meisten Scripten kompatibel ist. (sie Scripte sind bei uns in der Datenbank gespeichert, mit einer Synchronisation von/zu uns) Ansonsten nutzen wir einen Fork vom ![]() da sind die Änderungen für "unsere" automatische Versions-Suche im Embedded-Verzeichnis. Und wir könnten gezielt die Updates übernehmen (oder auch nicht) PS: Da der Entwickler bösartig AnsiString für seine Parameter benutzt hat, die das Python aber eigentlich mit UTF-8 nutzt, mußte ich da bissl rumtricksen, damit Unicode/Umlaute nicht kaputt gehn. Auszug:
Delphi-Quellcode:
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;
Delphi-Quellcode:
Python := TProdatPython.Create;
try //if not Python.CheckExecute(Script, False) then raise .... edPythonResult.Text := Python.Execute(Script); finally Python.Free; end;
Delphi-Quellcode:
TDM1.ScreenCursorSwitchToHoureGlass(True);
Python := TXXXXXPython.Create; try {$IFDEF EUREKALOG} // Eurekalog deaktiveren > Grund: 5 Fehler und das war es ELActive := IsEurekaLogActive; SetEurekaLogState(False); {$ENDIF} Python.RuntimeForm := nil; Python.OwnerModul := FindModule(TModulForm, True); ... if Python.CheckExecute(Script, False) then try {Res :=} Python.Execute(Script); finally // auch bei einem Fehler den bereits vorhandenen Output anzeigen (inkl. Fehlerposition, Stacktrace und Fehlermeldung) edPythonResult.Text := TrimRight(TRegEx.Replace(Python.Output, '^( *\r?\n)*', '', [roSingleLine])); // das Resultat des Scriptes von StdOut end else edPythonResult.Text := Format('Error: Skript kann nicht ausgeführt werden%s%s', [sLineBreak + sLineBreak, Python.Output]); finally {$IFDEF EUREKALOG} SetEurekaLogState(ELActive); {$ENDIF} Python.Free; TDM1.ScreenCursorSwitchToHoureGlass(False); end;
Ein Therapeut entspricht 1024 Gigapeut.
Geändert von himitsu ( 9. Okt 2023 um 15:44 Uhr) |
![]() |
Registriert seit: 5. Nov 2014 Ort: Baden Württemberg 136 Beiträge Delphi 12 Athens |
#3
Danke fürs Teilen von deinen Code Schnipseln. Ich denke, ich werde mir auch einen Wrapper um die Engine bauen.
Spaßhalber habe ich gestern versucht das Environment mittels TPyEmbeddedEnvironment aufzusetzen. ![]() das hat erstaunlich problemlos funktioniert. Die installieren in dem Environment auch gleich pip mit. Sieht nicht schlecht aus, um sich eine Umgebung komplett zusammenbauen zu lassen. Jetzt muss ich nur noch herausfinden, wie man über das mitinstallierte PIP Pakete installieren kann.
Bastian
|
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |