Jump to content

pyscripter

Members
  • Content Count

    1005
  • Joined

  • Last visited

  • Days Won

    65

Posts posted by pyscripter


  1. 29 minutes ago, aehimself said:

    Does TJSonSerializer work with TObjectList and TObjectDictionary already? As far as I remember this is why I started to (de)serialize objects manually back around Delphi 10.4 but would love to automate things finally 🙂

    It includes a number of converters to handle generic collections, but I think you have to add them manually:

     

    image.thumb.png.227259b88e9cefe181f6b54c5856f9b4.png


  2. Since you asked for Serializer benchmakrs:

     

    paolo-rossi/delphi-neon: JSON Serialization library for Delphi includes a benchmark against the Rest.Json serializer and it beats it hand down:

     

    image.thumb.png.d8d3caa2c25afcda0c606f7c4951a2f5.png

     

    I have replaced the Rest.Json serializer with the System.Json.Serializers TJSONSerializer.  Here are the results:

     

    image.thumb.png.ab71e4cbcea5cb822d8bb9d3b33699cc.png

     

    So now TJsonSerializer beats Neon hands down.

     

    TJsonSerializer looks good but it has some rough edges.   To run the benchmarks I had to add a converter that handles Enumerated values as strings instead of the default integers:

    type
      TEnumStringConverter = class(TJsonConverter)
      public
        function CanConvert(ATypeInf: PTypeInfo): Boolean; override;
        function ReadJson(const AReader: TJsonReader; ATypeInf: PTypeInfo; const AExistingValue: TValue;
          const ASerializer: TJsonSerializer): TValue; override;
        procedure WriteJson(const AWriter: TJsonWriter; const AValue: TValue;
          const ASerializer: TJsonSerializer); override;
      end;
    
    { TEnumStringConverter }
    
    function TEnumStringConverter.CanConvert(ATypeInf: PTypeInfo): Boolean;
    begin
      // This converter can handle any type that is an enumeration
      Result := (ATypeInf.Kind = TTypeKind.tkEnumeration) and
        (ATypeInf <> TypeInfo(Boolean));
    end;
    
    function TEnumStringConverter.ReadJson(const AReader: TJsonReader; ATypeInf:
        PTypeInfo; const AExistingValue: TValue; const ASerializer:
        TJsonSerializer): TValue;
    var
      LIntValue: Integer;
    begin
      LIntValue := System.TypInfo.GetEnumValue(ATypeInf, AReader.Value.AsString);
    
      if LIntValue = -1 then // GetEnumValue returns -1 if the name is not found
        raise EJsonSerializationException.CreateFmt('Invalid string value "%s" for enumeration "%s".', [AExistingValue.AsString, ATypeInf.Name]);
    
      // Create a TValue of the specific enum type using its ordinal value.
      Result := TValue.FromOrdinal(ATypeInf, LIntValue);
    end;
    
    procedure TEnumStringConverter.WriteJson(const AWriter: TJsonWriter; const
        AValue: TValue; const ASerializer: TJsonSerializer);
    begin
        AWriter.WriteValue(System.TypInfo.GetEnumName(AValue.TypeInfo, AValue.AsOrdinal));
    end;

    See also:  

     

    Bummer: System.Json.Converters already includes TJsonEnumNameConverter that does the job.

     

     


  3. 1 hour ago, Tommi Prami said:

    Is there test/comparison is Objects and/or Record serialization supported and speed etc??

    No. Most of the alternatives do not support serialization.  Grizzy and Superobject do.   Delphi offers a couple of ways.   But serialization is not  necessarily dependent on JSON parsing.   For example NEON is using System.JSON.   

    • Like 1

  4. hydrobyte/TestJSON: A simple project to test JSON libraries with Delphi and C++Builder. presents JSON library benchmarks comparing a large number of alternatives.

     

    One thing that strikes me, is that the System.JSON rtl library is doing relatively well compared to the competition, both in terms of performance and in terms of JSON validation.   With the exception of Find, is very competitive in all other areas.

     

    I have seen many claims that System.JSON is very slow and that the xyz library is so many times faster.   Do these benchmarks suck (like most benchmarks)?   Or is it the case that System.JSON is not that bad?  What is your experience?

    • Like 5
    • Thanks 1

  5. When I serialize a an object with object fields that are nil  I get null values in the Json result e.g.

     

     
    {
        "capabilities": {
            "positionEncoding": [],
            "textDocumentSync": {
                "openClose": true,
                "change": 2,
                "willSave": false,
                "willSaveWaitUntil": false,
                "save": null
            },
            "notebookDocumentSync": null,
            "completionProvider": null,
    }

     

    How can I ignore fields that have nil values?


    System.JSON.Types defines the following:

      TJsonDefaultValueHandling = (Include, Ignore, Populate, IgnoreAndPopulate);
    

    but it is not used anywhere.

     

    I also tried to use a converter, but I could not get it to work.  And in any case converters are used after the property name is written.

     

    Any ideas?


  6. 11 minutes ago, Anders Melander said:

    Ohwaitamoment!

    I think DevExpress use a custom property editor to get the events listed. I'll investigate.

    It works with Components if you call SetSubComponent or set csSubComponent.  Then Events are displayed.     e.g,

     

    image.png.abeab2ba62815cc15f4cf7730727d7bd.png

     

    So you can change TTestSub to inherit from TComponent.


  7. 1 hour ago, dummzeuch said:

    This passes the raw bytes received to the callback. Maybe it is possible to convert them to a string first? Or maybe call every time a line feed is received? Also, maybe the callbacks are enough so collecting the whole output is no longer necessary.

    This is roughly what I had in mind.

     

    Suggestions:

    • Have one event with an Enumerated parameter TExecOutput = (eoStdout, eoStdErr)
    • Pass to the callback only the newly added bytes in a TBytes.  They can be easily converted to strings using the ISshClient encoding.
    • Keep the output as is.  The user has a choice of not providing a callback.  The overhead is small.

     


  8. ISshExec.Exec was substantially revised and now works in non-blocking mode.

    • Are you using the latest source?
    • Are you using the latest linssh2 binaries?


    You can execute ISshExec in a thread.  Note that then it can be cancelled from the main thread using ISshExec.Cancel.

     

    Also you memory leak in TSshExec.Exec · Issue #18 · pyscripter/Ssh-Pascal has been fixed.  Can you confirm that?

     


  9. In the latest commits, I have added the ability to handle pointer fields and properties.  They are converted to python integers.

     

    So you could store for example an integer to the TTreeNode.Data.

    You could also store pointers to python objects using ctypes.   

    See for example the following:

    from ctypes import py_object, pointer, addressof, cast, POINTER
    
    # Create a py_object
    original = "Hello"
    py_obj = py_object(original)
    
    # Get its address
    addr = addressof(py_obj)  # e.g., 0x7f8b5c403020
    
    # Recover the py_object
    py_ptr = cast(addr, POINTER(py_object))
    recovered_py_obj = py_ptr.contents
    recovered = recovered_py_obj.value
    
    print(recovered)  # "Hello"
    print(original is recovered)  # True (same object)

    addr is an int type (python integer) that can be stored in Delphi pointer property. 


    • TTreeNode.Data is a Pointer property and WrapDelphi does not support raw pointer properties.
    • The only pointer property supported is PPyObject.   So if your wrapped class had a property declared as PPyObject it would work.  This also explains the error message.
    •  To be able to use the Data property you would need to modify the TTreeNode wrapper and do some custom wrapping of the TreeNode.Data property.   Alternatively you could save whatever info you need to store in a python data structure (possibly dict for easy access).
    • Thanks 1

  10. @Alex7691Good work.  It is useful to have a drop-in fast generics replacement.

     

    A couple of questions:

    • Is there an impact on code size?
    • I see a lot of code included that it is not directly related to generics.  (e.g. TSyncSpinlock, TSyncLocker, TaggedPointer, TCustomObject. TLiteCustomObject  etc.).  Are they actually essential for the rapid collections?   

  11. 28 minutes ago, bravesofts said:

    Microsoft’s WinUI 3, the latest iteration of its modern Windows UI framework

    Not quite.   See for instance Ohh...WinUI3 is really dead! - When can we expect the announcement? · microsoft/microsoft-ui-xaml · Discussion #9417

     

    The Microsoft strategy for GUI App development is utterly messed up:

    • WinForms
    • WPF
    • Xamarin Forms
    • UWP
    • WinUI3
    • MAUI

    And there is no longer a GUI designer.  You have to develop XAML in a text editor.  Discussion: WinUI 3.0 XAML Designer · Issue #5917 · microsoft/microsoft-ui-xaml

    • Like 7
    • Thanks 1

  12. 9 minutes ago, ToddFrankson said:

      (right hand side during install)

    This is the 64 bit IDE.   My problem was that the Win64 platform was not available.   After trying many things, I had to do a full uninstall/install to get the platform available again.


  13. 41 minutes ago, softtouch said:

    val contains 'testing' again, even it does not exist in python2.py.

    Of course it does.

     

    What you are doing is like running the following python script:

    exec("a = 1; print(a)")
    exec("b = 1; print(a)")
    

    a is created in the first statement and still exists when the second statement is executed.

     

    but if you do

    exec("a = 1; print(a)", {}, {})
    exec("b = 1; print(a)", {}, {})
    

    then the second statement raises an error.

     

    ExecFile has the following signature:

     

        procedure  ExecFile(const FileName: string; locals: PPyObject = nil; globals: PPyObject = nil); 

     

    If you provide no arguments for locals and globals, the code is executed in the namespace of the __main__ module.    If you do not want this to happen then you should provide empty dictionaries as arguments for the locals and globals parameters (or just the locals).  But then MainModule.VALUE will raise an error.

     

    Example code (not tested):

    var Py := GetPythonEngine;
    var NewDict := NewPythonDict;
    Py.ExecFile('python1.py', ExtractPythonObjectFrom(NewDict));
    var val := NewDict.GetItem("VALUE");
    
    NewDict := NewPythonDict;
    Py.ExecFile('python2.py', ExtractPythonObject(NewDict));
    val := NewDict.GetItem("VALUE");  // will raise an error since VALUE does not exist
    VarClear(NewDict);

     

×