5

I am using python4delphi. How can I return an object from a wrapped Delphi class function?

Code Snippet:

I have a simple Delphi Class that I wrapped to Python Script, right?

TSimple = Class
Private
  function getvar1:string;
Public    
Published
  property var1:string read getVar1;
  function getObj:TSimple;
end;
... 
function TSimple.getVar1:string;
begin
  result:='hello';
end;
function TSimple.getObj:TSimple;
begin
  result:=self;
end;

I made the TPySimple like the demo32 to give class access to the Python code. My Python module name is test.

TPySimple = class(TPyDelphiPersistent)
  // Constructors & Destructors
  constructor Create( APythonType : TPythonType ); override;
  constructor CreateWith( PythonType : TPythonType; args : PPyObject ); override;
  // Basic services
  function  Repr : PPyObject; override;

  class function  DelphiObjectClass : TClass; override;
end;
...

{ TPySimple }

constructor TPySimple.Create(APythonType: TPythonType);
begin
  inherited;
  // we need to set DelphiObject property
  DelphiObject := TSimple.Create;
  with TSimple(DelphiObject) do begin
  end;
  Owned := True; // We own the objects we create
end;

constructor TPySimple.CreateWith(PythonType: TPythonType; args: PPyObject);
begin
  inherited;
  with GetPythonEngine, DelphiObject as TSimple do
    begin
      if PyArg_ParseTuple( args, ':CreateSimple' ) = 0 then
        Exit;
    end;
end;

class function TPySimple.DelphiObjectClass: TClass;
begin
  Result := TSimple;
end;

function TPySimple.Repr: PPyObject;
begin
  with GetPythonEngine, DelphiObject as TSimple do
    Result := VariantAsPyObject(Format('',[]));
    // or Result := PyString_FromString( PAnsiChar(Format('()',[])) );
end;

And now the python code:

import test

a = test.Simple()
# try access the property var1 and everything is right
print a.var1
# work's, but..
b = a.getObj();
# raise a exception that not find any attributes named getObj.
# if the function returns a string for example, it's work.
Johan
  • 74,508
  • 24
  • 191
  • 319
Gabriel Fonseca
  • 345
  • 3
  • 12
  • 4
    Someone down voted without saying why (a bad habit some people have, I wish I could downvote them!) My guess though is that you should explain more about what you mean (maybe a code snippet) and what isn't working or what you've tried already. – David Mar 19 '12 at 16:50
  • 1
    This question does seem pretty vague to me. The lack of activity backs up that feeling. – David Heffernan Mar 19 '12 at 19:43
  • Alright guys, take some code snippets. – Gabriel Fonseca Mar 19 '12 at 20:26
  • It does seem odd at first sight. Does a simpler method work, e.g. one returning an integer? Maybe the fact it's returning a pointer to the class itself confuses the wrapper - how would it handle that? How do you "make the TPySimple like the demo32 to give class access to the python code"? Can you link to their documentation or show what's inside the generated import file (if that's human-readable, I don't know.) – David Mar 20 '12 at 09:47
  • This is a poor documented-component (http://code.google.com/p/python4delphi/) but you can download the sources and run out the demos, in the demo32 they show us how to use a delphi class in your python script, i think the code of TPySimple won't help us, but the in here now. – Gabriel Fonseca Mar 20 '12 at 12:20
  • You said that the pointer of class itself confuses the wrapper, but i already try to return a new object but the first problem is what type of object i'll need return in the function? I try a few classes but any can't return to python. The idea is create a Chain-of-responsibility design. – Gabriel Fonseca Mar 20 '12 at 12:33
  • @Gabriel: I'm looking a exposing a Delphi class to Python and there is a convesation at http://code.google.com/p/python4delphi/issues/detail?id=17 re the DelphiWrapper. Did you get anywhere with your demo? – Brian Frost Jan 14 '13 at 10:25
  • @BrianFrost I have found the solution in example 06. – Gabriel Fonseca Jan 14 '13 at 15:16

2 Answers2

1

I have run into the same problem while using DelphiWrapper.

First, enable RTTI using {$METHODINFO ON} will prevent exception:

raise a exception that not find any attributes named getObj.

Write TSimple class like this:

{$METHODINFO ON}
TSimple = Class
Private
  function getvar1:string;
Public    
Published
  property var1:string read getVar1;
  function getObj:TSimple;
end;
{$METHODINFO OFF}

Now getObj function returns a value -- an Integer!!

I'll show you guys what I did. I modified Demo32:

Unit1.pas:

TPoint = class(TPersistent)
private
  fx, fy : Integer;
  fName : String;
public
  constructor Create();
  procedure OffsetBy( dx, dy : integer );
  function MySelf: TPoint;  //**access self using function**
published
  property x : integer read fx write fx;
  property y : integer read fy write fy;
  property Name : string read fName write fName;
  property MySelf2: TPoint read MySelf; //**access self using property**
end;

Python code in Memo1.Lines:

import spam

p = spam.Point(2, 5)

b = p.MySelf()  //**using function**
print 'Using MySelf: ', type(b), b
c = p.MySelf2   //**using property**
print 'Using MySelf2: ', type(c), c

Then it gives a result like this:

Using MySelf:  <type 'int'> 31957664
Using MySelf2:  <type 'Point'> (2, 5)

The function returns an int, that's wired. Maybe it's a pointer to a TPoint object incorrectly wrapped by DelphiWrapper.

Finally I found a compromise way in Demo8 using "AddMethod". Not beautiful at all!! But it works.

Jason Y
  • 11
  • 2
0

According to the OP he's found the answer here: http://code.google.com/p/python4delphi/issues/detail?id=17

(A copy-paste for reference)

Hi,

I've a suggestion - make exposing Delphi objects to python painless by utilizing the new RTTI (runtime type information) feature in D2010 (and above).

Currently exposing a class to the hosted Python code needs to you to write too much code (check demo06), I guess if we take advantage of the new RTTI feature in the newer versions of Delphi, the process can be improved a lot.

For example, check out the Delphi chromium embedded project, all you have to do to expose the interface of any Delphi class to the JavaScript environment, is to register the class:

// this is your class exposed to JS 
  Test = class 
    class procedure doit(const v: string); 
  end; 

initialization 
// Register your class 
  TCefRTTIExtension.Register('app', Test);

// and in JavaScript code to call that class above:
app.doit(''foo'')', '', 0); 

Cool! Isn't it?

The above code was extracted from: http://groups.google.com/group/delphichromiumembedded/browse_thread/thread/1793e7ca66012f0c/8ab31a5ecdb6bf48?lnk=gst&q=JavaScript+return+#

Some intro about RTTI introduced since D2010: http://robstechcorner.blogspot.com/2009/09/delphi-2010-rtti-basics.html

Johan
  • 74,508
  • 24
  • 191
  • 319