pyscripter / python4delphi

Free components that wrap up Python into Delphi and Lazarus (FPC)
MIT License
895 stars 307 forks source link

Error in ExtractPythonObjectFrom when creating Enum? #467

Closed Vobsoft closed 3 months ago

Vobsoft commented 3 months ago

Hi, If I edit Demo05

function spam_foo( self, args : PPyObject ) : PPyObject; cdecl;
begin
  with GetPythonEngine do
    begin
      ShowMessage( 'args of foo: '+PyObjectAsString(args) );
     // Result := ReturnNone;
     Result := ExtractPythonObjectFrom(MainModule.color.RED);
    end;
end;
import spam
from enum import Enum
from enum import unique

@unique
class color (Enum):
         RED = 0
         GREEN = 1
         BLUE = 2

print (spam.foo('hello world', 1))
print (spam.foo('hello world', 1))
print (spam.foo('hello world', 1))
print (spam.foo('hello world', 1))  #Error
print (spam.foo('hello world', 1))

Will throw an error when repeatedly calling Foo Project Demo05.exe raised exception class $C0000005 with message 'access violation at 0x79530e00: read of address 0x79530e00'. If I add Py_IncRef(result); it's OK

function spam_foo( self, args : PPyObject ) : PPyObject; cdecl;
begin
  with GetPythonEngine do
    begin
      ShowMessage( 'args of foo: '+PyObjectAsString(args) );
     // Result := ReturnNone;
     Result := ExtractPythonObjectFrom(MainModule.color.RED);
     Py_IncRef(result);
    end;
end;

This is also OK

function spam_foo( self, args : PPyObject ) : PPyObject; cdecl;
begin
  with GetPythonEngine do
    begin
      ShowMessage( 'args of foo: '+PyObjectAsString(args) );
     var MainM := PyImport_AddModule('__main__');
     var ColorEnum := PyObject_GetAttrString(MainM, 'color');
     result := PyObject_GetAttrString(ColorEnum, 'RED');
     Py_DecRef(ColorEnum);
      end;
end;

Is this a bug or just my inexperience? Delphi 11, Python Dll: 3.12.1 (tags/v3.12.1:2305ca5, Dec 7 2023, 21:47:43) [MSC v.1937 32 bit (Intel)]

pyscripter commented 3 months ago

The refcount of result needs to be incremented.

ExtractPythonObjectFrom does not increment the result, so you need to do it as in your second routine.

In your third routine PyObject_GetAttrString returns a new reference so you are also OK.