Skip to content

Commit e5a441d

Browse files
author
Alextp
committed
big sync with P4D to support Py3.10
1 parent d69b064 commit e5a441d

File tree

1 file changed

+142
-63
lines changed

1 file changed

+142
-63
lines changed

python4lazarus/PythonEngine.pas

Lines changed: 142 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
{$ENDIF}
6666

6767
{$ifdef UNIX}
68-
{$define POSIX} // to bo compatible with Python4Delphi
68+
{$define POSIX} // to be compatible with Python4Delphi
6969
{$endif}
7070

7171
interface
@@ -176,17 +176,32 @@ interface
176176
// Delphi equivalent used by TPyObject
177177
TRichComparisonOpcode = (pyLT, pyLE, pyEQ, pyNE, pyGT, pyGE);
178178

179-
{$IFDEF WINDOWS}
179+
180+
// C long is 8 bytes in non-Windows 64-bit operating systems
181+
// Same Delphi's LongInt but not fpc LongInt which is always 4 bytes
182+
// Hence the following
183+
{$IFDEF MSWINDOWS}
180184
C_Long = Integer;
181185
C_ULong = Cardinal;
182186
{$ELSE}
183-
C_Long= NativeInt;
187+
C_Long = NativeInt;
184188
C_ULong = NativeUInt;
185189
{$ENDIF}
186190

191+
// wchar_t is 4 bytes on Linux/OS X/Android but 2 bytes on Windows
192+
{$IFDEF POSIX}
193+
PWCharT = PUCS4Char;
194+
PPWCharT = ^PUCS4Char;
195+
WCharTString = UCS4String;
196+
{$ELSE}
197+
PWCharT = PWideChar;
198+
PPWCharT = PPWideChar;
199+
WCharTString = UnicodeString;
200+
{$ENDIF}
201+
187202
const
188203
{
189-
Type flags (tp_flags) introduced in version 2.0
204+
Type flags (tp_flags)
190205
191206
These flags are used to change expected features and behavior for a
192207
particular type.
@@ -1210,8 +1225,17 @@ TDynamicDll = class(TComponent)
12101225
//-------------------------------------------------------
12111226

12121227
type
1228+
(*$HPPEMIT 'typedef int __cdecl (*TPyArg_Parse)(void * args, char * format, ...);' *)
1229+
TPyArg_Parse = function( args: PPyObject; format: PAnsiChar {;....}) : Integer; cdecl varargs;
1230+
{$EXTERNALSYM TPyArg_Parse}
1231+
1232+
(*$HPPEMIT 'typedef int __cdecl (*TPyArg_ParseTupleAndKeywords)(void * args, void * kw, char * format, char** kwargs, ...);' *)
1233+
TPyArg_ParseTupleAndKeywords = function( args: PPyObject; kw: PPyObject; format: PAnsiChar; kwargs: PPAnsiChar {;...}): Integer; cdecl varargs;
1234+
{$EXTERNALSYM TPyArg_ParseTupleAndKeywords}
12131235

1214-
{ TPythonInterface }
1236+
(*$HPPEMIT 'typedef int __cdecl (*TPy_BuildValue)(char * format, ...);' *)
1237+
TPy_BuildValue = function( format: PAnsiChar {;...}): Pointer; cdecl varargs;
1238+
{$EXTERNALSYM TPy_BuildValue}
12151239

12161240
TPythonInterface=class(TDynamicDll)
12171241
protected
@@ -1351,10 +1375,12 @@ TPythonInterface=class(TDynamicDll)
13511375
PyErr_WarnEx: function (ob: PPyObject; text: PAnsiChar; stack_level: NativeInt): integer; cdecl;
13521376
PyErr_WarnExplicit: function (ob: PPyObject; text: PAnsiChar; filename: PAnsiChar; lineno: integer; module: PAnsiChar; registry: PPyObject): integer; cdecl;
13531377
PyImport_GetModuleDict: function: PPyObject; cdecl;
1354-
PyArg_Parse: function( args: PPyObject; format: PAnsiChar {;....}) : Integer; cdecl varargs;
1355-
PyArg_ParseTuple: function( args: PPyObject; format: PAnsiChar {;...}): Integer; cdecl varargs;
1356-
PyArg_ParseTupleAndKeywords: function( args: PPyObject; kw: PPyObject; format: PAnsiChar; kwargs: PPAnsiChar {;...}): Integer; cdecl varargs;
1357-
Py_BuildValue: function( format: PAnsiChar {;...}): PPyObject; cdecl varargs;
1378+
1379+
PyArg_Parse: TPyArg_Parse;
1380+
PyArg_ParseTuple: TPyArg_Parse;
1381+
PyArg_ParseTupleAndKeywords: TPyArg_ParseTupleAndKeywords;
1382+
Py_BuildValue: TPy_BuildValue;
1383+
13581384
Py_Initialize: procedure; cdecl;
13591385
Py_Exit: procedure( RetVal: Integer); cdecl;
13601386
PyEval_GetBuiltins: function: PPyObject; cdecl;
@@ -1382,7 +1408,7 @@ TPythonInterface=class(TDynamicDll)
13821408
PyRun_SimpleString: function( str: PAnsiChar): Integer; cdecl;
13831409
PyBytes_AsString: function( ob: PPyObject): PAnsiChar; cdecl;
13841410
PyBytes_AsStringAndSize: function( ob: PPyObject; var buffer: PAnsiChar; var size: NativeInt): integer; cdecl;
1385-
PySys_SetArgv: procedure( argc: Integer; argv: PPWideChar); cdecl;
1411+
PySys_SetArgv: procedure( argc: Integer; argv: PPWCharT); cdecl;
13861412

13871413
PyCFunction_NewEx: function(md:PPyMethodDef;self, ob:PPyObject):PPyObject; cdecl;
13881414
// Removed. Use PyEval_CallObjectWithKeywords with third argument nil
@@ -1423,13 +1449,13 @@ TPythonInterface=class(TDynamicDll)
14231449
PyList_Size:function (ob:PPyObject):NativeInt; cdecl;
14241450
PyList_Sort:function (ob:PPyObject):integer; cdecl;
14251451
PyLong_AsDouble:function (ob:PPyObject):DOUBLE; cdecl;
1426-
PyLong_FromDouble:function (db:double):PPyObject; cdecl;
14271452
PyLong_AsLong:function (ob:PPyObject):C_Long; cdecl;
1453+
PyLong_FromDouble:function (db:double):PPyObject; cdecl;
14281454
PyLong_FromLong:function (l:C_Long):PPyObject; cdecl;
14291455
PyLong_FromString:function (pc:PAnsiChar;var ppc:PAnsiChar;i:integer):PPyObject; cdecl;
14301456
PyLong_FromUnsignedLong:function(val:C_ULong): PPyObject; cdecl;
14311457
PyLong_AsUnsignedLong:function(ob:PPyObject): C_ULong; cdecl;
1432-
PyLong_FromUnicode:function(ob:PPyObject; a, b : integer): PPyObject; cdecl;
1458+
PyLong_FromUnicodeObject:function(ob:PPyObject; base : integer): PPyObject; cdecl;
14331459
PyLong_FromLongLong:function(val:Int64): PPyObject; cdecl;
14341460
PyLong_FromUnsignedLongLong:function(val:UInt64) : PPyObject; cdecl;
14351461
PyLong_AsLongLong:function(ob:PPyObject): Int64; cdecl;
@@ -1465,7 +1491,6 @@ TPythonInterface=class(TDynamicDll)
14651491
PyNumber_Rshift:function (ob1,ob2:PPyObject):PPyObject; cdecl;
14661492
PyNumber_Subtract:function (ob1,ob2:PPyObject):PPyObject; cdecl;
14671493
PyNumber_Xor:function (ob1,ob2:PPyObject):PPyObject; cdecl;
1468-
PyOS_InitInterrupts:procedure; cdecl;
14691494
PyOS_InterruptOccurred:function :integer; cdecl;
14701495
PyObject_CallObject:function (ob,args:PPyObject):PPyObject; cdecl;
14711496
PyObject_CallMethod : function ( obj : PPyObject; method, format : PAnsiChar {...}) : PPyObject; cdecl varargs;
@@ -1542,11 +1567,11 @@ TPythonInterface=class(TDynamicDll)
15421567
PyType_GenericAlloc:function(atype: PPyTypeObject; nitems:NativeInt) : PPyObject; cdecl;
15431568
PyType_GenericNew:function(atype: PPyTypeObject; args, kwds : PPyObject) : PPyObject; cdecl;
15441569
PyType_Ready:function(atype: PPyTypeObject) : integer; cdecl;
1545-
PyUnicode_FromWideChar:function (const w:PWideChar; size:NativeInt):PPyObject; cdecl;
1570+
PyUnicode_FromWideChar:function (const w:PWCharT; size:NativeInt):PPyObject; cdecl;
15461571
PyUnicode_FromString:function (s:PAnsiChar):PPyObject; cdecl;
15471572
PyUnicode_FromStringAndSize:function (s:PAnsiChar;i:NativeInt):PPyObject; cdecl;
15481573
PyUnicode_FromKindAndData:function (kind:integer;const buffer:pointer;size:NativeInt):PPyObject; cdecl;
1549-
PyUnicode_AsWideChar:function (unicode: PPyObject; w:PWideChar; size:NativeInt):integer; cdecl;
1574+
PyUnicode_AsWideChar:function (unicode: PPyObject; w:PWCharT; size:NativeInt):integer; cdecl;
15501575
PyUnicode_AsUTF8:function (unicode: PPyObject):PAnsiChar; cdecl;
15511576
PyUnicode_AsUTF8AndSize:function (unicode: PPyObject; size: PNativeInt):PAnsiChar; cdecl;
15521577
PyUnicode_Decode:function (const s:PAnsiChar; size: NativeInt; const encoding : PAnsiChar; const errors: PAnsiChar):PPyObject; cdecl;
@@ -1559,9 +1584,9 @@ TPythonInterface=class(TDynamicDll)
15591584
PyWeakref_NewRef: function ( ob, callback : PPyObject) : PPyObject; cdecl;
15601585
PyWrapper_New: function ( ob1, ob2 : PPyObject) : PPyObject; cdecl;
15611586
PyBool_FromLong: function ( ok : Integer) : PPyObject; cdecl;
1562-
PyThreadState_SetAsyncExc: function(t_id :C_ULong; exc :PPyObject) : Integer; cdecl;
1587+
PyThreadState_SetAsyncExc: function(t_id:C_ULong; exc:PPyObject) : Integer; cdecl;
15631588
Py_AtExit:function (proc: AtExitProc):integer; cdecl;
1564-
Py_CompileStringExFlags:function (s1,s2:PAnsiChar;i:integer;flags:PPyCompilerFlags;optimize:integer):PPyObject; cdecl;
1589+
Py_CompileStringExFlags:function (str,filename:PAnsiChar;start:integer;flags:PPyCompilerFlags;optimize:integer):PPyObject; cdecl;
15651590
Py_FatalError:procedure(s:PAnsiChar); cdecl;
15661591
_PyObject_New:function (obt:PPyTypeObject;ob:PPyObject):PPyObject; cdecl;
15671592
_PyBytes_Resize:function (var ob:PPyObject;i:NativeInt):integer; cdecl;
@@ -1571,20 +1596,20 @@ TPythonInterface=class(TDynamicDll)
15711596
PyEval_EvalCode : function ( co : PPyObject; globals, locals : PPyObject) : PPyObject; cdecl;
15721597
Py_GetVersion : function : PAnsiChar; cdecl;
15731598
Py_GetCopyright : function : PAnsiChar; cdecl;
1574-
Py_GetExecPrefix : function : PAnsiChar; cdecl;
1575-
Py_GetPath : function : PAnsiChar; cdecl;
1576-
Py_SetPythonHome : procedure (home : PWideChar); cdecl;
1577-
Py_GetPythonHome : function : PWideChar; cdecl;
1578-
Py_GetPrefix : function : PAnsiChar; cdecl;
1579-
Py_GetProgramName : function : PAnsiChar; cdecl;
1599+
Py_GetExecPrefix : function : PWCharT; cdecl;
1600+
Py_GetPath : function : PWCharT; cdecl;
1601+
Py_SetPath : procedure (path: PWCharT); cdecl;
1602+
Py_SetPythonHome : procedure (home : PWCharT); cdecl;
1603+
Py_GetPythonHome : function : PWCharT; cdecl;
1604+
Py_GetPrefix : function : PWCharT; cdecl;
1605+
Py_GetProgramName : function : PWCharT; cdecl;
15801606

15811607
PyParser_SimpleParseStringFlags : function ( str : PAnsiChar; start, flags : Integer) : PNode; cdecl;
15821608
PyNode_Free : procedure( n : PNode ); cdecl;
15831609
PyErr_NewException : function ( name : PAnsiChar; base, dict : PPyObject ) : PPyObject; cdecl;
1584-
Py_Malloc : function ( size : NativeInt ) : Pointer;
15851610
PyMem_Malloc : function ( size : NativeUInt ) : Pointer;
15861611

1587-
Py_SetProgramName : procedure( name: PWideChar); cdecl;
1612+
Py_SetProgramName : procedure( name: PWCharT); cdecl;
15881613
Py_IsInitialized : function : integer; cdecl;
15891614
Py_GetProgramFullPath : function : PAnsiChar; cdecl;
15901615
Py_NewInterpreter : function : PPyThreadState; cdecl;
@@ -1609,14 +1634,49 @@ TPythonInterface=class(TDynamicDll)
16091634
// TODO - deal with the following:
16101635
// the PyParser_* functions are deprecated in python 3.9 and will be removed in
16111636
// Python 3.10
1612-
function PyParser_SimpleParseString( str : PAnsiChar; start : Integer) : PNode; cdecl;
1613-
function Py_CompileString( s1,s2:PAnsiChar;i:integer) : PPyObject; cdecl;
1637+
function PyParser_SimpleParseString(str : PAnsiChar; start : Integer) : PNode; cdecl;
1638+
function Py_CompileString(str,filename:PAnsiChar;start:integer) : PPyObject; cdecl;
16141639

16151640
// functions redefined in Delphi
1616-
procedure Py_INCREF ( op: PPyObject);
1617-
procedure Py_DECREF ( op: PPyObject);
1618-
procedure Py_XINCREF ( op: PPyObject);
1619-
procedure Py_XDECREF ( op: PPyObject);
1641+
class procedure Py_INCREF(op: PPyObject); static; inline;
1642+
class procedure Py_DECREF(op: PPyObject); static; inline;
1643+
class procedure Py_XINCREF(op: PPyObject); static; inline;
1644+
class procedure Py_XDECREF(op: PPyObject); static; inline;
1645+
(* Safely decref `op` and set `op` to NULL, especially useful in tp_clear
1646+
* and tp_dealloc implementations.
1647+
*
1648+
* Note that "the obvious" code can be deadly:
1649+
*
1650+
* Py_XDECREF(op);
1651+
* op = NULL;
1652+
*
1653+
* Typically, `op` is something like self->containee, and `self` is done
1654+
* using its `containee` member. In the code sequence above, suppose
1655+
* `containee` is non-NULL with a refcount of 1. Its refcount falls to
1656+
* 0 on the first line, which can trigger an arbitrary amount of code,
1657+
* possibly including finalizers (like __del__ methods or weakref callbacks)
1658+
* coded in Python, which in turn can release the GIL and allow other threads
1659+
* to run, etc. Such code may even invoke methods of `self` again, or cause
1660+
* cyclic gc to trigger, but-- oops! --self->containee still points to the
1661+
* object being torn down, and it may be in an insane state while being torn
1662+
* down. This has in fact been a rich historic source of miserable (rare &
1663+
* hard-to-diagnose) segfaulting (and other) bugs.
1664+
*
1665+
* The safe way is:
1666+
*
1667+
* Py_CLEAR(op);
1668+
*
1669+
* That arranges to set `op` to NULL _before_ decref'ing, so that any code
1670+
* triggered as a side-effect of `op` getting torn down no longer believes
1671+
* `op` points to a valid object.
1672+
*
1673+
* There are cases where it's safe to use the naive code, but they're brittle.
1674+
* For example, if `op` points to a Python integer, you know that destroying
1675+
* one of those can't cause problems -- but in part that relies on that
1676+
* Python integers aren't currently weakly referencable. Best practice is
1677+
* to use Py_CLEAR() even if you can't think of a reason for why you need to.
1678+
*)
1679+
class procedure Py_CLEAR(var op: PPyObject); static; inline;
16201680

16211681
function PyBytes_Check( obj : PPyObject ) : Boolean;
16221682
function PyBytes_CheckExact( obj : PPyObject ) : Boolean;
@@ -3357,7 +3417,7 @@ procedure TPythonInterface.MapDll;
33573417
PyLong_FromString := Import('PyLong_FromString');
33583418
PyLong_FromUnsignedLong := Import('PyLong_FromUnsignedLong');
33593419
PyLong_AsUnsignedLong := Import('PyLong_AsUnsignedLong');
3360-
PyLong_FromUnicode := Import('PyLong_FromUnicode');
3420+
PyLong_FromUnicodeObject := Import('PyLong_FromUnicodeObject');
33613421
PyLong_FromLongLong := Import('PyLong_FromLongLong');
33623422
PyLong_FromUnsignedLongLong := Import('PyLong_FromUnsignedLongLong');
33633423
PyLong_AsLongLong := Import('PyLong_AsLongLong');
@@ -3393,7 +3453,6 @@ procedure TPythonInterface.MapDll;
33933453
PyNumber_Rshift := Import('PyNumber_Rshift');
33943454
PyNumber_Subtract := Import('PyNumber_Subtract');
33953455
PyNumber_Xor := Import('PyNumber_Xor');
3396-
PyOS_InitInterrupts := Import('PyOS_InitInterrupts');
33973456
PyOS_InterruptOccurred := Import('PyOS_InterruptOccurred');
33983457
PyObject_CallObject := Import('PyObject_CallObject');
33993458
PyObject_CallMethod := Import('PyObject_CallMethod');
@@ -3504,12 +3563,18 @@ procedure TPythonInterface.MapDll;
35043563
Py_GetCopyright := Import('Py_GetCopyright');
35053564
Py_GetExecPrefix := Import('Py_GetExecPrefix');
35063565
Py_GetPath := Import('Py_GetPath');
3566+
Py_SetPath := Import('Py_SetPath');
35073567
Py_SetPythonHome := Import('Py_SetPythonHome');
35083568
Py_GetPythonHome := Import('Py_GetPythonHome');
35093569
Py_GetPrefix := Import('Py_GetPrefix');
35103570
Py_GetProgramName := Import('Py_GetProgramName');
3511-
PyParser_SimpleParseStringFlags := Import('PyParser_SimpleParseStringFlags');
3512-
PyNode_Free := Import('PyNode_Free');
3571+
3572+
if (FMajorVersion = 3) and (MinorVersion < 10) then
3573+
begin
3574+
PyParser_SimpleParseStringFlags := Import('PyParser_SimpleParseStringFlags');
3575+
PyNode_Free := Import('PyNode_Free');
3576+
end;
3577+
35133578
PyErr_NewException := Import('PyErr_NewException');
35143579
try
35153580
PyMem_Malloc := Import ('PyMem_Malloc');
@@ -3538,22 +3603,22 @@ procedure TPythonInterface.MapDll;
35383603
PyGILState_Release := Import('PyGILState_Release');
35393604
end;
35403605

3541-
function TPythonInterface.Py_CompileString(s1,s2:PAnsiChar;i:integer):PPyObject;
3606+
function TPythonInterface.Py_CompileString(str,filename:PAnsiChar;start:integer):PPyObject;
35423607
begin
3543-
Result := Py_CompileStringExFlags(s1, s2, i, nil, -1);
3608+
Result := Py_CompileStringExFlags(str, filename, start, nil, -1);
35443609
end;
35453610

35463611
function TPythonInterface.PyParser_SimpleParseString( str : PAnsiChar; start : integer) : PNode; cdecl;
35473612
begin
35483613
Result := PyParser_SimpleParseStringFlags(str, start, 0);
35493614
end;
35503615

3551-
procedure TPythonInterface.Py_INCREF(op: PPyObject);
3616+
class procedure TPythonInterface.Py_INCREF(op: PPyObject);
35523617
begin
35533618
Inc(op^.ob_refcnt);
35543619
end;
35553620

3556-
procedure TPythonInterface.Py_DECREF(op: PPyObject);
3621+
class procedure TPythonInterface.Py_DECREF(op: PPyObject);
35573622
begin
35583623
with op^ do begin
35593624
Dec(ob_refcnt);
@@ -3563,16 +3628,29 @@ procedure TPythonInterface.Py_DECREF(op: PPyObject);
35633628
end;
35643629
end;
35653630

3566-
procedure TPythonInterface.Py_XINCREF(op: PPyObject);
3631+
class procedure TPythonInterface.Py_XINCREF(op: PPyObject);
35673632
begin
35683633
if op <> nil then Py_INCREF(op);
35693634
end;
35703635

3571-
procedure TPythonInterface.Py_XDECREF(op: PPyObject);
3636+
class procedure TPythonInterface.Py_XDECREF(op: PPyObject);
35723637
begin
35733638
if op <> nil then Py_DECREF(op);
35743639
end;
35753640

3641+
3642+
class procedure TPythonInterface.Py_CLEAR(var op: PPyObject);
3643+
Var
3644+
_py_tmp : PPyObject;
3645+
begin
3646+
_py_tmp := op;
3647+
if _py_tmp <> nil then
3648+
begin
3649+
op := nil;
3650+
Py_DECREF(_py_tmp);
3651+
end;
3652+
end;
3653+
35763654
function TPythonInterface.PyBytes_Check( obj : PPyObject ) : Boolean;
35773655
begin
35783656
Result := PyObject_TypeCheck(obj, PyBytes_Type);
@@ -4273,35 +4351,36 @@ procedure TPythonEngine.CheckRegistry;
42734351

42744352
procedure TPythonEngine.SetProgramArgs;
42754353
var
4276-
i, argc : Integer;
4277-
wargv : array of PWideChar;
4278-
{$IFDEF POSIX}
4279-
UCS4L : array of UCS4String;
4280-
{$ELSE}
4281-
WL : array of UnicodeString;
4282-
{$ENDIF}
4354+
I, argc : Integer;
4355+
wargv : array of PWCharT;
4356+
WL : array of WCharTString;
4357+
TempS: UnicodeString;
42834358
begin
42844359
// we build a string list of the arguments, because ParamStr returns a volatile string
4285-
// and we want to build an array of PAnsiChar, pointing to valid strings.
4360+
// and we want to build an array of PWCharT, pointing to valid strings.
42864361
argc := ParamCount;
42874362
SetLength(wargv, argc + 1);
4288-
// build the PWideChar array
4289-
{$IFDEF POSIX}
4290-
// Note that Linux uses UCS4 strings, whereas it declares using UCS2 strings!!!
4291-
SetLength(UCS4L, argc+1);
4292-
for i := 0 to argc do begin
4293-
UCS4L[i] := WideStringToUCS4String(ParamStr(i));
4294-
wargv[i] := @UCS4L[i][0];
4295-
end;
4296-
{$ELSE}
4363+
// build the PWCharT array
42974364
SetLength(WL, argc+1);
4298-
for i := 0 to argc do begin
4299-
WL[i] := UnicodeString(ParamStr(i));
4300-
wargv[i] := PWideChar(WL[i]);
4365+
for I := 0 to argc do begin
4366+
{
4367+
... the first entry should refer to the script file to be executed rather
4368+
than the executable hosting the Python interpreter. If there isn’t a
4369+
script that will be run, the first entry in argv can be an empty string.
4370+
}
4371+
if I = 0 then
4372+
TempS := ''
4373+
else
4374+
TempS := ParamStr(I);
4375+
{$IFDEF POSIX}
4376+
WL[I] := UnicodeStringToUCS4String(TempS);
4377+
{$ELSE}
4378+
WL[I] := UnicodeString(TempS);
4379+
{$ENDIF}
4380+
wargv[I] := PWCharT(WL[I]);
43014381
end;
4302-
{$ENDIF}
43034382
// set the argv list of the sys module with the application arguments
4304-
PySys_SetArgv( argc + 1, PPWideChar(wargv) );
4383+
PySys_SetArgv( argc + 1, PPWCharT(wargv) );
43054384
end;
43064385

43074386
procedure TPythonEngine.InitWinConsole;

0 commit comments

Comments
 (0)