Jump to content

pyscripter

Members
  • Content Count

    775
  • Joined

  • Last visited

  • Days Won

    40

Posts posted by pyscripter


  1. Forgot to say that unfortunately you cannot just set the __doc__ property of Wrapped classes and methods.  It has to be done at the time of wrapping.

     

    A trivial implementation of IDocServer would be:

    uses
      TypInfo;
    
    type
      TMyDocServer = class(TInterfacedObject, IDocServer)
      private
        function ReadTypeDocStr(ATypeInfo: PTypeInfo; out ADocStr: string): Boolean;
        function ReadMemberDocStr(AMember: TRttiMember; out ADocStr: string): Boolean;
        procedure Initialize;
        procedure Finalize;
        function Initialized: Boolean;
      end;{ TMyDocServer }
    
    procedure TMyDocServer.Finalize;
    begin
    end;
    
    procedure TMyDocServer.Initialize;
    begin
    end;
    
    function TMyDocServer.Initialized: Boolean;
    begin
      Result := True;
    end;
    
    function TMyDocServer.ReadMemberDocStr(AMember: TRttiMember;
      out ADocStr: string): Boolean;
    begin
      Result := False;
      if AMember.Name = 'getVersion' then
      begin
        Result := True;
        ADocStr := 'getVersion';
      end;
    end;
    
    function TMyDocServer.ReadTypeDocStr(ATypeInfo: PTypeInfo;
      out ADocStr: string): Boolean;
    begin
      Result := False;
      if ATypeInfo = TypeInfo(ThostAPI ) then
      begin
        Result := True;
        ADocStr := 'ThostAPI doc';
      end;
    end;

    and then

      PyDocServer := TMyDocServer.Create;
      DelphiWrapper.RegisterDelphiWrapper(TPyClassWrapper<THostAPI>).Initialize;

     


  2. WrapDelphi defines the following:

     

      IDocServer = interface
        ['{4AF0D319-47E9-4F0A-9C71-97B8CBB559FF}']
        function ReadTypeDocStr(ATypeInfo: PTypeInfo; out ADocStr: string): Boolean;
        function ReadMemberDocStr(AMember: TRttiMember; out ADocStr: string): Boolean;
        procedure Initialize;
        procedure Finalize;
        function Initialized: Boolean;
      end;
    
      var
        PyDocServer: IDocServer = nil;

    You need to implement the interface and assign the implemented interface to PyDocServer.   

     

    PythonDocs.pas provides an implementation based on xml files, which is used by delphivcl and delphifmx.   But if, what you are after is to provide docstrings to a few methods,  it would be easier to create your own implementation.

     

     


  3. 6 minutes ago, Remy Lebeau said:

    The System.AnsiStrings.AnsiCompareStr() function uses the Win32 CompareStringA() function on Windows.

    Unfortunately (see CompareStringA function (winnls.h) - Win32 apps | Microsoft Learn😞

    Quote

    If your application is calling the ANSI version of CompareString, the function converts parameters via the default code page of the supplied locale. Thus, an application can never use CompareString to handle UTF-8 text.

    It also appears that System.AnsiStrings.AnsiCompareStr ignores the code page of the ansi strings.


  4. Look at PyBytes_AsString, or PyBytes_AsStringAndSize functions.

     

    For example if obj is a bytes PPyObject. the following converts it to an AnsiString.

      AnsiString(PyBytes_AsString(obj))

     

    Also PyObjectAsVariant(obj) converts it to a variant.

     

    In the opposite direction to create a bytes object in Delphi use PyBytes_FromStringAndSize


  5. WrapDelphi was designed to expose Delphi classes, records and interfaces to python.   So it did not handle PPyObject parameters or return values.   You could handle that by using the low-level approach (adding an Event to TPythonModule).   However, I have now added to WrapDelphi support for exposing functions with parameters and/or results of type PPyObject.

     

    See WrapDelphiTest.pas in the latest version of the pyscripter/python4delphi: Free components that wrap up Python into Delphi and Lazarus (FPC) (github.com) repo.

     

    Example:

     

    Exposed Method:

    function TTestRttiAccess.PlaceInNewList(PyObj: PPyObject): PPyObject;
    begin
      with GetPythonEngine do
      begin
        Result := PyList_New(1);
        Py_XIncRef(PyObj);
        PyList_SetItem(Result, 0, PyObj);
      end;
    end;

    Usage in python

    from delphi import rtti_var
    list = rtti_var.PlaceInNewList('abc')
    

    The corresponding test in WrapDelphiTest:

    procedure TTestWrapDelphi.TestPPyObjects;
    var
      List: Variant;
    begin
      List := rtti_var.PlaceInNewList('abc');
      Assert.IsTrue(VarIsPythonList(List));
      Assert.AreEqual<string>(List.GetItem(0), 'abc');
    end;


     

     


  6. PyEnum_Check and VarIsEnum have to do with enumerators and not the enum.Enum class.

     

    There are many ways to get the value.  Using VarPyth:

     var a := VarPythonCreate(pColor);

      var val := a.value


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


  8. 6 minutes ago, iqrf said:

    But I have no idea how to use the same functionality for an enumeration type

    As mentioned above you just use python strings in place of enumerated values,

     

    eg.  exported delphi method using WrapDelphi

     

    procedure Test(Color: TColor)

     

    in python

     

    Test('RED')


  9. I have no idea what you are trying to do, but it does not make sense to define the enumeration both in Delphi and in Python.

     

    I recommend that you familiarize yourself with:

    •   WrapDelphi - high level access to Delphi from python
    •  VarPyth - high level access to python from Delphi. 

    The video tutorials offer a good introduction to both.

     

    If you use WrapDelphi to export delphi functions to python then you just use python strings in place of enumeration values.

     


  10. There is no need to export anything.   Delphi enum values are converted to python strings and sets to lists of strings.

     

    On the opposite direction you can access python enum values from Delphi in the same way you access other objects.  The easiest way is to use VarPyth.

     

    var colorEnum := MainModule.Color

    var Red := colorEnum.RED


  11. @Lainkes Under Project, Options, Version Info, you can choose to include version info with your project.  The version info includes the version number but also a number of other strings including Comments.

     

    Your application can read those in a number of ways.   See for instance How to determine Delphi Application Version - Stack Overflow,

    The most comprehensive way I found is using the Jcl library's unit JclFileInfo.  This unit includes a class TJclFileVersionInfo which provides easy access to all information stored in version info.

     

    Here is for example a function that retrieves the version number using jcl:

     

    function ApplicationVersion : string;
    var
      ExeFile : string;
    begin
      ExeFile := Application.ExeName;
      if VersionResourceAvailable(ExeFile) then begin
        with TJclFileVersionInfo.Create(ExeFile) do begin
          Result := BinFileVersion;
          Free;
        end;
      end else
        Result := '1.0.0';
    end;

    Note that this approach is Windows only.  For Andoid apps you can access the version info differently (e,g,How can I get at the file version info of a file when running Delphi on Android? - Stack Overflow


  12. Hint:  The answer is in PythonThreads · pyscripter/python4delphi Wiki (github.com)

     

    Other solutions include:

    • Modify your scripts so that they do not create global variables (wrap everything inside a function which you execute)
    • At the end of your python script delete (del) any global variables you create
    • Use Run_CommandAsObjectWithDict or ExecStrings, passing new empty dictionaries to the optional locals, and globals parameters, which you then destroy.

     


  13. Assuming you are on Windows use:

    import asyncio
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    loop = asyncio.new_event_loop()

    This should work both in the main thread and in other threads.

     

    Google for "set_wakeup_fd" to see this is a well known issue.

×