softtouch 9 Posted March 30 Lets say I have an array with the following 2 strings in it: ClickElement_ByXPATH ClickElement_ByCSSSelector I have Python function with the same name, so I could call MainModule.ClickElement_ByXPATH or MainModule.ClickElement_ByCSSSelector, which works. Is there any way to create the funcname in the call MainModule.<funcname> based on the strings in the stringlist? For example, when I get the first item in the stringlist (ClickElement_ByXPATH), how could I create a call to MainModule.<here the element from the stringlist>, similar I can do with rtti and delphi functions, so it would call MainModule.ClickElement_ByXPATH? With other words, creating the call based on the text in a stringlist. Share this post Link to post
Remy Lebeau 1400 Posted March 30 Are you wanting to call a Python function dynamically from Delphi code? Or call a Delphi function dynamically from Python code? Its not clear what you are looking for. Can you provide an example? Share this post Link to post
softtouch 9 Posted March 30 1 hour ago, Remy Lebeau said: Are you wanting to call a Python function dynamically from Delphi code? Or call a Delphi function dynamically from Python code? Its not clear what you are looking for. Can you provide an example? I want to call python functions. Their names are in a stringlist. With other words, how could I call a python function when the function name is a string? Example: var s:='ClickElement_ByXPATH'; How can I call the corresponding python function, which has exactly that name? Share this post Link to post
Remy Lebeau 1400 Posted March 30 1 hour ago, softtouch said: I want to call python functions. Their names are in a stringlist. How are you calling Python functions from Delphi code to begin with? Share this post Link to post
softtouch 9 Posted March 30 (edited) 6 minutes ago, Remy Lebeau said: How are you calling Python functions from Delphi code to begin with? Via MainModule.<pythonfunction name here> (TPythonModule of P4D) If the python function ClickElement_ByXPATH exist, I call it like MainModule.ClickElement_ByXPATH(); Edited March 30 by softtouch Share this post Link to post
Remy Lebeau 1400 Posted March 31 (edited) 5 hours ago, softtouch said: TPythonModule of P4D THAT'S an important piece of information that was missing. Python4Delphi's MainModule is a function that returns a custom Variant holding a reference to Python's __main__ object. A custom class named TPythonVariantType derived from Delphi's TInvokeableVariantType is used to allow such Variants to access properties and methods of the Python objects they hold. So, in your example, when you call MainModule.ClickElement_ByXPATH, the Delphi compiler emits code to pass the MainModule Variant to Python4Delphi's implementation of TPythonVariantType.DoProcedure() or TPythonVariantType.DoFunction() (depending on whether a return value is used or not) to invoke the "ClickElement_ByXPATH" function by name at runtime. So, to do what you are asking for, you could invoke TPythonVariantType.DoProcedure() manually, eg (UNTESTED!): uses ..., Variants, VarPyth; var custType: TCustomVariantType; v: Variant; begin // MainModule.ClickElement_ByXPATH(); if FindCustomVariantType(VarPython, custType) then begin v := MainModule; custType.DoProcedure(TVarData(v), 'ClickElement_ByXPATH', nil); end; end; Edited March 31 by Remy Lebeau Share this post Link to post
pyscripter 689 Posted March 31 (edited) @Remy Lebeau approach should work. (not tested) Alternatively you can use the more efficient: var PyMainModule: PPyObject; PyMainModule := GetPythonEngine.GetMainModule; GetPythonEngine.PyObject_CallMethod (PyMainModule, PAnsiChar(AnsiString(method_name)), nil); Edited March 31 by pyscripter Share this post Link to post
softtouch 9 Posted March 31 7 hours ago, pyscripter said: @Remy Lebeau approach should work. (not tested) Alternatively you can use the more efficient: var PyMainModule: PPyObject; PyMainModule := GetPythonEngine.GetMainModule; GetPythonEngine.PyObject_CallMethod (PyMainModule, PAnsiChar(AnsiString(method_name)), nil); Thank you, but how can I provide parameter to the call when using this approach like result:=MainModule.ClickElement_ByXPATH(param1,param2,param3...) Share this post Link to post
pyscripter 689 Posted March 31 (edited) How about reading the documentation of PyObject_CallMethod or just googling for example usage? Edited March 31 by pyscripter Share this post Link to post
softtouch 9 Posted March 31 I did, but I cant get it to work unfortunately. Anyway, thanks for your help. Share this post Link to post
pyscripter 689 Posted March 31 Note that if you get the PyObject corresponding to the function by using for instance var PyMainModule: PPyObject; PyFunc: PPyObject; PyMainModule := GetPythonEngine.GetMainModule; PyFunc := GetPythonEngine.PyObject_GetAttrString (PyMainModule, PAnsiChar(AnsiString(method_name))); // When you finish with PyFunc you need to decrease the refcount You can then call the function in a number of different ways including the relatively high level: function EvalFunction(pyfunc:PPyObject; const args: array of const): Variant; Share this post Link to post
softtouch 9 Posted March 31 7 minutes ago, pyscripter said: Note that if you get the PyObject corresponding to the function by using for instance var PyMainModule: PPyObject; PyFunc: PPyObject; PyMainModule := GetPythonEngine.GetMainModule; PyFunc := GetPythonEngine.PyObject_GetAttrString (PyMainModule, PAnsiChar(AnsiString(method_name))); // When you finish with PyFunc you need to decrease the refcount You can then call the function in a number of different ways including the relatively high level: function EvalFunction(pyfunc:PPyObject; const args: array of const): Variant; Thank you! This is actually working just fine! Share this post Link to post