Jump to content

iqrf

Members
  • Content Count

    26
  • Joined

  • Last visited

Community Reputation

2 Neutral

Technical Information

  • Delphi-Version
    Delphi 11 Alexandria
  1. iqrf

    Html Help: Ctrl+F not working

    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;
  2. 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];
  3. 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.
  4. 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.
  5. It's really not easy, so I'll accept the imperfection and try to solve it sometime in the future. Thanks
  6. 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)
  7. 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.
  8. iqrf

    TPythonModule - submodule

    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?
  9. iqrf

    TPythonModule - submodule

    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!
  10. 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.
  11. iqrf

    TPythonModule - submodule

    Thanks, but understanding this code is beyond my abilities.
  12. 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.
  13. 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.
  14. 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.
  15. iqrf

    Get the propt value of input()

    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.
×