

iqrf
Members-
Content Count
26 -
Joined
-
Last visited
Community Reputation
2 NeutralTechnical Information
-
Delphi-Version
Delphi 11 Alexandria
-
Hi, I confirm that both CTRL+F and CTRL+C do not work under Delphi Alexandria + Win11 64b. Not working is: HtmlHelp(0, Application.HelpFile, HH_DISPLAY_TOC, 0); HtmlHelp(0, Application.HelpFile, HH_DISPLAY_INDEX, DWORD(PWideChar(''))); HtmlHelp(0, Application.HelpFile, HH_DISPLAY_SEARCH, DWORD(@Query)); Application.HelpContext() Calling HtmlHelpW instead of HtmlHelp works. A broken Application.HelpContext solved them like this: function TFormMain.ApplicationEvents1Help(Command: Word; Data: NativeInt; var CallHelp: Boolean): Boolean; begin HtmlHelpW(0, PWideChar(Application.HelpFile), HH_HELP_CONTEXT, Data); CallHelp := False; end; I used HH_HELP_CONTEXT because even when calling the Application.HelpContext the Command parameter contained 1 instead of 15. Of course, this solution does not work if HelpKeyword is used for components. A universal solution could be made by possibly recoding these constants. const { Commands to pass to WinHelp() } {$EXTERNALSYM HELP_CONTEXT} HELP_CONTEXT = 1; { Display topic in ulTopic } {$EXTERNALSYM HELP_QUIT} HELP_QUIT = 2; { Terminate help } {$EXTERNALSYM HELP_INDEX} HELP_INDEX = 3; { Display index } {$EXTERNALSYM HELP_CONTENTS} HELP_CONTENTS = 3; {$EXTERNALSYM HELP_HELPONHELP} HELP_HELPONHELP = 4; { Display help on using help } {$EXTERNALSYM HELP_SETINDEX} HELP_SETINDEX = 5; { Set current Index for multi index help } {$EXTERNALSYM HELP_SETCONTENTS} HELP_SETCONTENTS = 5; {$EXTERNALSYM HELP_CONTEXTPOPUP} HELP_CONTEXTPOPUP = 8; {$EXTERNALSYM HELP_FORCEFILE} HELP_FORCEFILE = 9; {$EXTERNALSYM HELP_KEY} HELP_KEY = 257; { Display topic for keyword in offabData } {$EXTERNALSYM HELP_COMMAND} HELP_COMMAND = 258; {$EXTERNALSYM HELP_PARTIALKEY} HELP_PARTIALKEY = 261; {$EXTERNALSYM HELP_MULTIKEY} HELP_MULTIKEY = 513; {$EXTERNALSYM HELP_SETWINPOS} HELP_SETWINPOS = 515; {$EXTERNALSYM HELP_CONTEXTMENU} HELP_CONTEXTMENU = 10; {$EXTERNALSYM HELP_FINDER} HELP_FINDER = 11; {$EXTERNALSYM HELP_WM_HELP} HELP_WM_HELP = 12; {$EXTERNALSYM HELP_SETPOPUP_POS} HELP_SETPOPUP_POS = 13; const {$EXTERNALSYM HH_DISPLAY_TOPIC } HH_DISPLAY_TOPIC = 0; {$EXTERNALSYM HH_HELP_FINDER } HH_HELP_FINDER = 0; {$EXTERNALSYM HH_DISPLAY_TOC } HH_DISPLAY_TOC = 1; {$EXTERNALSYM HH_DISPLAY_INDEX } HH_DISPLAY_INDEX = 2; {$EXTERNALSYM HH_DISPLAY_SEARCH } HH_DISPLAY_SEARCH = 3; {$EXTERNALSYM HH_SET_WIN_TYPE } HH_SET_WIN_TYPE = 4; {$EXTERNALSYM HH_GET_WIN_TYPE } HH_GET_WIN_TYPE = 5; {$EXTERNALSYM HH_GET_WIN_HANDLE } HH_GET_WIN_HANDLE = 6; {$EXTERNALSYM HH_ENUM_INFO_TYPE } HH_ENUM_INFO_TYPE = 7; {$EXTERNALSYM HH_SET_INFO_TYPE } HH_SET_INFO_TYPE = 8; {$EXTERNALSYM HH_SYNC } HH_SYNC = 9; {$EXTERNALSYM HH_KEYWORD_LOOKUP } HH_KEYWORD_LOOKUP = $d; {$EXTERNALSYM HH_DISPLAY_TEXT_POPUP } HH_DISPLAY_TEXT_POPUP = $e; {$EXTERNALSYM HH_HELP_CONTEXT } HH_HELP_CONTEXT = $f; {$EXTERNALSYM HH_TP_HELP_CONTEXTMENU } HH_TP_HELP_CONTEXTMENU = $10; {$EXTERNALSYM HH_TP_HELP_WM_HELP } HH_TP_HELP_WM_HELP = $11; {$EXTERNALSYM HH_CLOSE_ALL } HH_CLOSE_ALL = $12; {$EXTERNALSYM HH_ALINK_LOOKUP } HH_ALINK_LOOKUP = $13; {$EXTERNALSYM HH_GET_LAST_ERROR } HH_GET_LAST_ERROR = $14; {$EXTERNALSYM HH_ENUM_CATEGORY } HH_ENUM_CATEGORY = $15; {$EXTERNALSYM HH_ENUM_CATEGORY_IT } HH_ENUM_CATEGORY_IT = $16; {$EXTERNALSYM HH_RESET_IT_FILTER } HH_RESET_IT_FILTER = $17; {$EXTERNALSYM HH_SET_INCLUSIVE_FILTER } HH_SET_INCLUSIVE_FILTER = $18; {$EXTERNALSYM HH_SET_EXCLUSIVE_FILTER } HH_SET_EXCLUSIVE_FILTER = $19; {$EXTERNALSYM HH_INITIALIZE } HH_INITIALIZE = $1c; {$EXTERNALSYM HH_UNINITIALIZE } HH_UNINITIALIZE = $1d; {$EXTERNALSYM HH_SET_QUERYSERVICE } HH_SET_QUERYSERVICE = $1e; {$EXTERNALSYM HH_PRETRANSLATEMESSAGE } HH_PRETRANSLATEMESSAGE = $fd; {$EXTERNALSYM HH_GLOBALPROPERTY } HH_GLOBALPROPERTY = $fc;
-
I will answer myself. To register a method, you need to use AddMethodWithKeywords instead of AddMethod. It was enough to look at WrapDelphi.pas. I think it would be beneficial if Demo32 included an example of such a method. and still to fix KeyPointerArray := [PAnsiChar(KeyArray[0]), PAnsiChar(KeyArray[1]), PAnsiChar(KeyArray[2]), nil];
-
Yes, according to Demo32 I implemented it. But it is an example of use in CreateWidth. I am trying to use it in a method.
-
Hi, I have a TPythonType object TPyDevice = class(TPyObject) and Interface methods in it function DoSendAndReceive(args: PPyObject): PPyObject; cdecl; function TPyDevice.DoSendAndReceive(args: PPyObject): PPyObject; cdecl; var data: TBytes; pyBytes: PPyObject; timeout: Single; logging: Boolean; begin with GetPythonEngine do begin Adjust(@Self); logging := False; if PyArg_ParseTuple( args, 'S|fp:device.send_and_receive', @pyBytes, @timeout, @logging) <> 0 then begin data := PyBytesAsBytes(pyBytes); var response := False; .... .... if response then begin pyBytes := PyBytes_FromStringAndSize(PAnsiChar(data), Length(data)); Result := pyBytes; end else Result := ReturnNone; end else Result := nil; end; end; I use it like this response = device_manager.device.send_and_receive(dat, 0, True) or response = device_manager.device.send_and_receive(dat) I would like to call the function like this device_manager.device.send_and_receive(data=dat, timeout 0, logging=True) or device_manager.device.send_and_receive(data=dat, logging=True) I edited it like this function TPyDevice.DoSendAndReceive(args, kwds: PPyObject): PPyObject; cdecl; var data: TBytes; pyBytes: PPyObject; timeout: Single; logging: Boolean; keyArray: array of AnsiString; keyPointerArray: array of PAnsiChar; begin with GetPythonEngine do begin Adjust(@Self); logging := False; KeyArray := ['data', 'timeout', 'logging']; KeyPointerArray := [PAnsiChar(KeyArray[0]), PAnsiChar(KeyArray[1]), PAnsiChar(KeyArray[2])]; if PyArg_ParseTupleAndKeywords(args, kwds, 'S|fp:device.send_and_receive', @keyPointerArray[0], @pyBytes, @timeout, @logging) <> 0 then begin data := PyBytesAsBytes(pyBytes); var response := False; .... .... if response then begin pyBytes := PyBytes_FromStringAndSize(PAnsiChar(data), Length(data)); Result := pyBytes; end else Result := ReturnNone; end else Result := nil; end; end; TPyDevice = class(TPyObject) ... constructor CreateWith( PythonType : TPythonType; args : PPyObject ); override; // Basic services function Repr : PPyObject; override; function Str : PPyObject; override; function GetAttr(Key: PAnsiChar): PPyObject; override; function SetAttr(Key: PAnsiChar; Value: PPyObject): Integer; override; // Methods of TPyDevice ... // Class methods class procedure RegisterMethods(PythonType: TPythonType); override; class procedure RegisterMembers(PythonType: TPythonType); override; class procedure RegisterGetSets(PythonType: TPythonType); override; // Interface methods function DoSendAndReceive(args, kwds: PPyObject): PPyObject; cdecl; ... end; class procedure TPyDevice.RegisterMethods(PythonType: TPythonType); begin inherited; with PythonType do begin AddMethod('send_and_receive', @TPyDevice.DoSendAndReceive, 'device_manager.device.send_and_recive(data: bytes)'); .... end; end; FPythonType_Device := TPythonType.Create(nil); FPythonType_Device.Name := 'FPythonType_Device'; FPythonType_Device.GenerateCreateFunction := False; FPythonType_Device.Engine := FEngine; FPythonType_Device.OnInitialization := OnInitialization_PythonType_Device; FPythonType_Device.TypeName := 'Device'; FPythonType_Device.Prefix := ''; FPythonType_Device.Services.Basic := [bsGetAttr, bsSetAttr, bsRepr, bsStr]; FPythonType_Device.Module := FPythonModule_DeviceManager; pDevice := FPythonType_Device.CreateInstance; FEngine.CheckError; device := TPyDevice(PythonToDelphi(pDevice)); FPythonModule_DeviceManager.SetVar('device', pDevice); FEngine.Py_DecRef(pDevice); But I get TypeError: send_and_receive() takes no keyword arguments. Execution of the send_and_receive function will not start at all. I looked at the Demo32 example, but there it is used with CreateWith which has parameters args, kwds: PPyObject already PythoEngine.pas Thank you in advance for your help.
-
It's really not easy, so I'll accept the imperfection and try to solve it sometime in the future. Thanks
-
Couldn't this be done at the Python level using a decorator above the module? import types class MyModule(types.ModuleType): def __setattr__(self, name, value): print(f"Setting attribute {name} to value {value}") super().__setattr__(name, value) mymodule = MyModule('mymodule') mymodule.my_attribute = 42 print(mymodule.my_attribute)
-
Hi, Let's take Demo08 as an example where a myPoint object is created in Delphi. I need to detect on the Delphi side if the assignment spam.myPoint = None is made in Python. Cyclic polling using PythonModule1.GetVar('myPoint') is inappropriate for me. I would need something like OnChange in TPythonDelphiVar. I've studied PythonEngine.pas and can't think of anything. Thank you for your opinion.
-
I finally found a way to make a package import importlib import types import sys # Package name package_name = 'my_package' # List of modules to be part of the package module_names = ['module1', 'module2'] # Create an empty package package = types.ModuleType(package_name) package.__path__ = [] # Import and add individual modules to the package for module_name in module_names: module = importlib.import_module(module_name) setattr(package, module_name, module) # Set __all__ to the list of module names package.__all__ = module_names # Add the package to the list of imported modules sys.modules[package_name] = package Then it is possible import my_package from my_package import module1 from my_package import module2 as T print(dir(module1)) print(dir(my_package.module1)) print(dir(T)) Only this import my_package.module1 as T is not possible. ModuleNotFoundError: No module named 'my_package.sub_module1' Does anyone know why?
-
Hi, I finally solved it at the Python level. I have two TPython modules, one named main_module and the other sub_module. Just add to the InitScript import main_module import sub_module main_module.sub_module = sub_module And you can use in Python main_module.sub_module.function1() but of course, also sub_module.function1(). In this way, a pseudo-hierarchical structure of modules can be created. Because this doesn't import main_module.sub_module as a test. main_module is not a package!
-
Hello, I have such a dictionary ... AddMethod( 'TestArray', @TPyPoint.DoTestArray, 'Point.TestArray()' ); function TPyPoint.DoTestArray(args : PPyObject): PPyObject; cdecl; type TDevice = record ValueA: Integer; ValueB: String; end; TDevices = array of TDevice; var DeviceArray: TDevices; I: Integer; DeviceList: PPyObject; DeviceDict: PPyObject; function TDeviceToPyObject(const Device: TDevice): PPyObject; var DeviceDict: PPyObject; begin with GetPythonEngine do begin DeviceDict := PyDict_New; PyDict_SetItemString(DeviceDict, 'ValueA', PyLong_FromLong(Device.ValueA)); PyDict_SetItemString(DeviceDict, 'ValueB', PyUnicodeFromString(PAnsiChar(AnsiString(Device.ValueB)))); Result := DeviceDict; end; end; begin SetLength(DeviceArray, 2); DeviceArray[0].ValueA := 1; DeviceArray[0].ValueB := 'Device 1'; DeviceArray[1].ValueA := 2; DeviceArray[1].ValueB := 'Device 2'; with GetPythonEngine do begin Adjust(@Self); DeviceList := PyList_New(0); for I := 0 to High(DeviceArray) do begin DeviceDict := TDeviceToPyObject(DeviceArray[I]); PyList_Append(DeviceList, DeviceDict); Py_DecRef(DeviceDict); end; Result := DeviceList; end; end; Is there any possibility to make the data read-only in Python? I can only do this if I pass them as Tuples using ArrayToPyTuple(MyArray), but then it's just a one-dimensional array. And one more question, how to pass TDevice data to Python so that it can be written in Python instead of this one a = spam.myPoint.TestArray() print(a[0]['ValueA']) print(a[0]['ValueB']) this one a = spam.myPoint.TestArray() print(a[0].ValueA) print(a[0].ValueB) Thanks.
-
Thanks, but understanding this code is beyond my abilities.
-
Hello, is it possible to somehow create a submodule. Something like this MainModule := TPythonModule.Create(nil); MainModule.ModuleName := 'spam'; SubModule := TPythonModule.Create(nil); SubModule.ModuleName := 'spam.test'; and call in Python import spam import spam.test spam.function1() spam.test.function2() it reports an error if i do it like this it's fine import spam import spam.test as T spam.function1() T.function2() Can it be solved somehow? Thanks for the ideas.
-
Thanks, it works. try MaskFPUExceptions(True); PythonEngine1.ExecStrings(Memo1.Lines); except errorMessage := MainModule.mystderr.getvalue(); ErrorLog(errorMessage); end; I would just like to continuously catch errors if someone writes in the Python code for example print("Error example 1", file=sys.stderr) or sys.stderr.write("Error Example 2") The current solution only prints everything at once, with the same timestamp. Thanks.
-
Hello, is there any way to remap PyErr_Print using a custom function? I would like to log the error output on a separate sheet. Now everything ends up in TPythonInputOutput. Or can it be done differently? Thanks for the idea.
-
I will answer myself, this is functional import builtins def myinput(prompt): builtins._input_prompt = prompt return builtins._input(prompt) builtins._input = builtins.input builtins.input = myinput Thanks again, I'm learning Python and I'm still amazed at what it can do.