Skip to content

Commit f5fb751

Browse files
committed
WrapDelphi:
- Generic class wrapper - Use Rtti to expose methods, fields and properties to the created python type. Here is the first stage with methods exposed. - IDocServer interface to provide docstrings to the exposed members - New WrapDelphi tests added PythonEngine: - FindPythonType overload - Minor changes and comments
1 parent e4ab3a8 commit f5fb751

File tree

3 files changed

+495
-74
lines changed

3 files changed

+495
-74
lines changed

Source/PythonEngine.pas

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,7 +1902,8 @@ TPythonEngine = class(TPythonInterface)
19021902
procedure AddClient( client : TEngineClient );
19031903
procedure RemoveClient( client : TEngineClient );
19041904
function FindClient( const aName : string ) : TEngineClient;
1905-
function FindPythonType( const TypeName : AnsiString ) : TPythonType;
1905+
function FindPythonType(const TypeName : AnsiString): TPythonType; overload;
1906+
function FindPythonType(PyType: PPyTypeObject): TPythonType; overload;
19061907
function TypeByName( const aTypeName : AnsiString ) : PPyTypeObject;
19071908
function ModuleByName( const aModuleName : AnsiString ) : PPyObject;
19081909
function MethodsByName( const aMethodsContainer: string ) : PPyMethodDef;
@@ -2362,6 +2363,20 @@ TPythonModule = class(TMethodsContainer)
23622363
- When turning a Delphi instance into a Python object pointer, GetSelf will offset
23632364
Self from B to A.
23642365
- Properties ob_refcnt and ob_type will call GetSelf to access their data.
2366+
2367+
Further Notes:
2368+
- PyObject instances are not created directly, but via their python type
2369+
See TPythonType.CreateInstance and TPythonType.NewSubtypeInst (tp_new
2370+
slot). In the second case TPy_Object.NewInstance is not called and
2371+
the size of the memory is determined by the tp_basicsize slot.
2372+
- Their memory can be allocated either by pascal or python. PythonAlloc
2373+
keeps track of how the PyObject memory was allocated.
2374+
- PyObject instances are not destroyed directly, but by PyObjectDestructor
2375+
when their reference count goes down to zero (tp_dealloc slot)
2376+
- The value of PythonAlloc determines how the memory is freed
2377+
using either PyObject_Free (tp_free slot) or in the overwritten
2378+
FreeInstance.
2379+
- This class is heart of the P4D library. Pure magic!!
23652380
}
23662381
// The base class of all new Python types
23672382
TPyObject = class
@@ -2767,7 +2782,6 @@ function PythonOK : Boolean;
27672782
function PythonToDelphi( obj : PPyObject ) : TPyObject;
27682783
function IsDelphiObject( obj : PPyObject ) : Boolean;
27692784
procedure PyObjectDestructor( pSelf : PPyObject); cdecl;
2770-
procedure FreeSubtypeInst(ob:PPyObject); cdecl;
27712785
procedure Register;
27722786
function PyType_HasFeature(AType : PPyTypeObject; AFlag : Integer) : Boolean;
27732787
function SysVersionFromDLLName(const DLLFileName : string): string;
@@ -6139,6 +6153,19 @@ function TPythonEngine.FindPythonType(const TypeName: AnsiString): TPythonType;
61396153
end;
61406154
end;
61416155

6156+
function TPythonEngine.FindPythonType(PyType: PPyTypeObject): TPythonType;
6157+
var
6158+
I : Integer;
6159+
begin
6160+
Result := nil;
6161+
for I := 0 to ClientCount - 1 do
6162+
if (Clients[I] is TPythonType) and (TPythonType(Clients[I]).TheTypePtr = PyType) then
6163+
begin
6164+
Result := TPythonType(Clients[I]);
6165+
Break;
6166+
end;
6167+
end;
6168+
61426169
function TPythonEngine.FindFunction(const ModuleName,FuncName: AnsiString): PPyObject;
61436170
var
61446171
module,func: PPyObject;
@@ -8178,6 +8205,9 @@ function TPythonType.NewSubtypeInst( aType: PPyTypeObject; args, kwds : PPyObje
81788205
var
81798206
obj : TPyObject;
81808207
begin
8208+
// Allocate memory in the python heap for both the pascal and the python
8209+
// PyObject (see tp_basicsize in SetPyObjectClass)
8210+
// nitems = 0 because PyType_GenericAlloc adds +1
81818211
Result := aType^.tp_alloc(aType, 0);
81828212
if Assigned(Result) then
81838213
begin
@@ -8191,21 +8221,11 @@ function TPythonType.NewSubtypeInst( aType: PPyTypeObject; args, kwds : PPyObje
81918221
begin
81928222
Engine.Py_DECREF(Result);
81938223
Result := nil;
8224+
obj.Free;
81948225
end;
81958226
end;
81968227
end;
81978228

8198-
function TPythonType_AllocSubtypeInst( pSelf: PPyTypeObject; nitems : NativeInt) : PPyObject; cdecl;
8199-
begin
8200-
Result := GetPythonEngine.PyType_GenericAlloc(pSelf, nitems);
8201-
end;
8202-
8203-
procedure FreeSubtypeInst(ob:PPyObject);
8204-
begin
8205-
GetPythonEngine.PyObject_Free(ob);
8206-
end;
8207-
8208-
82098229
// Number services
82108230

82118231
function TPythonType_NbAdd( pSelf, obj : PPyObject) : PPyObject; cdecl;
@@ -8484,9 +8504,9 @@ procedure TPythonType.InitServices;
84848504
if tpfBaseType in TypeFlags then
84858505
begin
84868506
tp_init := TPythonType_InitSubtype;
8487-
tp_alloc := TPythonType_AllocSubtypeInst;
8507+
tp_alloc := FEngine.PyType_GenericAlloc;
84888508
tp_new := GetCallBack( Self, @TPythonType.NewSubtypeInst, 3, DEFAULT_CALLBACK_TYPE);
8489-
tp_free := FreeSubtypeInst;
8509+
tp_free := FEngine.PyObject_Free;
84908510
tp_methods := MethodsData;
84918511
tp_members := MembersData;
84928512
tp_getset := GetSetData;

0 commit comments

Comments
 (0)