Skip to content

Commit 43618b8

Browse files
committed
This version includes customizations to Python 3.x, 64bit and FireDAC.
1 parent 922cbbe commit 43618b8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+2918
-3693
lines changed

PythonForDelphi/Components/Sources/Core/Definition.Inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
//{$DEFINE PYTHON33}
3838
//{$DEFINE PYTHON34}
3939
//{$DEFINE PYTHON35}
40-
//{$DEFINE PYTHON36}
40+
{$DEFINE PYTHON36}
4141
//{$DEFINE PYTHON37}
4242

4343
/////////////////////////////////////////////////////////////////////////////

PythonForDelphi/Components/Sources/Core/PythonEngine.pas

Lines changed: 119 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ interface
7878
SysUtils,
7979
SyncObjs,
8080
Variants,
81+
//DAV>>>
82+
System.AnsiStrings, Data.SqlTimSt,
83+
//DAV<<<
8184
{$IFDEF DELPHI2005_OR_HIGHER}
8285
{$IFNDEF UNICODE}
8386
WideStrings,
@@ -138,7 +141,12 @@ interface
138141
(DllName: 'python33.dll'; RegVersion: '3.3'; APIVersion: 1013; CanUseLatest: True),
139142
(DllName: 'python34.dll'; RegVersion: '3.4'; APIVersion: 1013; CanUseLatest: True),
140143
(DllName: 'python35.dll'; RegVersion: '3.5'; APIVersion: 1013; CanUseLatest: True),
144+
{$IFDEF DEBUG}
145+
// (DllName: 'python36_d.dll'; RegVersion: '3.6'; APIVersion: 1013; CanUseLatest: True) );
141146
(DllName: 'python36.dll'; RegVersion: '3.6'; APIVersion: 1013; CanUseLatest: True),
147+
{$ELSE}
148+
(DllName: 'python36.dll'; RegVersion: '3.6'; APIVersion: 1013; CanUseLatest: True),
149+
{$ENDIF}
142150
(DllName: 'python37.dll'; RegVersion: '3.7'; APIVersion: 1013; CanUseLatest: True) );
143151
{$ENDIF}
144152
{$IFDEF LINUX}
@@ -193,12 +201,14 @@ interface
193201
{$IFDEF PYTHON36}
194202
COMPILED_FOR_PYTHON_VERSION_INDEX = 12;
195203
{$ENDIF}
196-
{$IFDEF PYTHON36}
204+
{$IFDEF PYTHON37}
197205
COMPILED_FOR_PYTHON_VERSION_INDEX = 13;
198206
{$ENDIF}
199-
PYT_METHOD_BUFFER_INCREASE = 10;
200-
PYT_MEMBER_BUFFER_INCREASE = 10;
201-
PYT_GETSET_BUFFER_INCREASE = 10;
207+
//DAV>>> !!! ReallocMethods, ReallocMembers, ReallocGetSets don't work correctly !!!
208+
PYT_METHOD_BUFFER_INCREASE = 100;
209+
PYT_MEMBER_BUFFER_INCREASE = 100;
210+
PYT_GETSET_BUFFER_INCREASE = 100;
211+
//DAV<<<
202212

203213
METH_VARARGS = $0001;
204214
METH_KEYWORDS = $0002;
@@ -1389,7 +1399,7 @@ EPyWindowsError = class (EPyOSError);
13891399

13901400
{$IF not Defined(FPC) and (CompilerVersion >= 23)}
13911401
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
1392-
{$IFEND}
1402+
{$ENDIF}
13931403
TPythonInputOutput = class(TComponent)
13941404
protected
13951405
FMaxLines : Integer;
@@ -1916,6 +1926,7 @@ TPythonInterface=class(TDynamicDll)
19161926
_PyObject_New:function (obt:PPyTypeObject;ob:PPyObject):PPyObject; cdecl;
19171927
_PyString_Resize:function (var ob:PPyObject;i:NativeInt):integer; cdecl;
19181928
Py_Finalize : procedure; cdecl;
1929+
Py_FinalizeEx : function : Integer;
19191930
PyErr_ExceptionMatches : function ( exc : PPyObject) : Integer; cdecl;
19201931
PyErr_GivenExceptionMatches : function ( raised_exc, exc : PPyObject) : Integer; cdecl;
19211932
PyEval_EvalCode : function ( co : PPyCodeObject; globals, locals : PPyObject) : PPyObject; cdecl;
@@ -2130,7 +2141,7 @@ TPythonTraceback = class
21302141

21312142
{$IF not Defined(FPC) and (CompilerVersion >= 23)}
21322143
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
2133-
{$IFEND}
2144+
{$ENDIF}
21342145
TPythonEngine = class(TPythonInterface)
21352146
private
21362147
FInitScript: TStrings;
@@ -2598,7 +2609,7 @@ TErrors = class(TCollection)
25982609

25992610
{$IF not Defined(FPC) and (CompilerVersion >= 23)}
26002611
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
2601-
{$IFEND}
2612+
{$ENDIF}
26022613
TPythonModule = class(TMethodsContainer)
26032614
protected
26042615
FModuleName : AnsiString;
@@ -2633,6 +2644,9 @@ TPythonModule = class(TMethodsContainer)
26332644
procedure SetVar( const varName : AnsiString; value : PPyObject );
26342645
function GetVar( const varName : AnsiString ) : PPyObject;
26352646
procedure DeleteVar( const varName : AnsiString );
2647+
//DAV>>>
2648+
procedure ClearVars;
2649+
//DAV<<<
26362650
procedure SetVarFromVariant( const varName : AnsiString; const value : Variant );
26372651
function GetVarAsVariant( const varName: AnsiString ) : Variant;
26382652

@@ -2863,7 +2877,7 @@ TTypeServices = class(TPersistent)
28632877
// that creates instances of itself.
28642878
{$IF not Defined(FPC) and (CompilerVersion >= 23)}
28652879
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
2866-
{$IFEND}
2880+
{$ENDIF}
28672881
TPythonType = class(TGetSetContainer)
28682882
protected
28692883
FType : PyTypeObject;
@@ -2951,7 +2965,7 @@ TPythonType = class(TGetSetContainer)
29512965

29522966
{$IF not Defined(FPC) and (CompilerVersion >= 23)}
29532967
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
2954-
{$IFEND}
2968+
{$ENDIF}
29552969
TPythonDelphiVar = class( TEngineClient )
29562970
protected
29572971
FModule : AnsiString;
@@ -4002,6 +4016,8 @@ procedure TPythonInterface.MapDll;
40024016
else
40034017
_PyString_Resize :=Import('_PyBytes_Resize');
40044018
Py_Finalize :=Import('Py_Finalize');
4019+
if IsPython3000 then
4020+
Py_FinalizeEx :=Import('Py_FinalizeEx');
40054021
if getProcAddress( FDLLHandle, 'PyCode_Addr2Line' ) <> nil then
40064022
DLL_PyCode_Addr2Line := Import('PyCode_Addr2Line');
40074023
if getProcAddress( FDLLHandle, 'PyImport_ExecCodeModule' ) <> nil then
@@ -4614,13 +4630,16 @@ procedure TPythonEngine.Finalize;
46144630
Finalize;
46154631
end;
46164632
// Then finalize Python, if we have to
4617-
if Initialized and FAutoFinalize then
4633+
if Initialized and FAutoFinalize then begin
46184634
try
4619-
FFinalizing := True;
4620-
Py_Finalize;
4621-
finally
4622-
FFinalizing := False;
4623-
end;
4635+
try
4636+
FFinalizing := True;
4637+
Py_Finalize;
4638+
finally
4639+
FFinalizing := False;
4640+
end;
4641+
except end;
4642+
end;
46244643
// Detach our clients, when engine is beeing destroyed or one of its clients.
46254644
canDetachClients := csDestroying in ComponentState;
46264645
if not canDetachClients then
@@ -4899,48 +4918,37 @@ procedure TPythonEngine.Notification( AComponent: TComponent;
48994918
procedure TPythonEngine.CheckRegistry;
49004919
{$IFDEF MSWINDOWS}
49014920
var
4902-
key : string;
4903-
Path : string;
4904-
NewPath : string;
4905-
MajorVersion : integer;
4906-
MinorVersion : integer;
4907-
VersionSuffix: string;
4921+
key : String;
4922+
path : String;
49084923
{$ENDIF}
49094924
begin
49104925
{$IFDEF MSWINDOWS}
4911-
if Assigned( FOnPathInitialization ) then
49124926
try
4913-
with TRegistry.Create(KEY_ALL_ACCESS and not KEY_NOTIFY) do
4927+
with TRegistry.Create(KEY_READ and not KEY_NOTIFY) do
49144928
try
4915-
MajorVersion := StrToInt(RegVersion[1]);
4916-
MinorVersion := StrToInt(RegVersion[3]);
4917-
VersionSuffix := '';
4918-
{$IFDEF CPUX86}
4919-
if (MajorVersion > 3) or ((MajorVersion = 3) and (MinorVersion >= 5)) then
4920-
VersionSuffix := '-32';
4921-
{$ENDIF}
4922-
key := Format('\Software\Python\PythonCore\%s%s\PythonPath', [RegVersion, VersionSuffix]);
4923-
4929+
//Access := KEY_READ; // works only with Delphi5 or greater
49244930
RootKey := HKEY_LOCAL_MACHINE;
4931+
key := Format('\Software\Python\PythonCore\%s\PythonPath', [RegVersion]);
49254932
if not KeyExists( key ) then
4926-
begin
4927-
// try a current user installation
4928-
RootKey := HKEY_CURRENT_USER;
4929-
if not KeyExists( key ) then Exit;
4930-
end;
4931-
// Key found
4932-
OpenKey( key, True );
4933-
try
4934-
Path := ReadString('');
4935-
NewPath := Path;
4936-
FOnPathInitialization( Self, NewPath );
4937-
if NewPath <> Path then
49384933
begin
4939-
WriteString( '', NewPath );
4934+
// try a current user installation
4935+
RootKey := HKEY_CURRENT_USER;
4936+
if not KeyExists( key ) then
4937+
begin
4938+
if Assigned( FOnPathInitialization ) then
4939+
begin
4940+
path := '';
4941+
FOnPathInitialization( Self, path );
4942+
if path <> '' then
4943+
begin
4944+
//Access := KEY_ALL_ACCESS; // works only with Delphi5 or greater
4945+
OpenKey( key, True );
4946+
WriteString( '', path );
4947+
CloseKey;
4948+
end;
4949+
end;
4950+
end;
49404951
end;
4941-
finally
4942-
CloseKey;
4943-
end;
49444952
finally
49454953
Free;
49464954
end;
@@ -5731,6 +5739,9 @@ function TPythonEngine.VariantAsPyObject( const V : Variant ) : PPyObject;
57315739
Disp : IDispatch;
57325740
DispID : Integer;
57335741
args : PPyObject;
5742+
//DAV>>>
5743+
l_dtSQLTimeStamp: TSQLTimeStamp;
5744+
//DAV<<<
57345745
begin
57355746
Disp := nil;
57365747
//Dereference Variant
@@ -5829,22 +5840,51 @@ function TPythonEngine.VariantAsPyObject( const V : Variant ) : PPyObject;
58295840
Result := ReturnNone;
58305841
end
58315842
else
5832-
try
5833-
Disp := DeRefV;
5834-
wStr := '__asPPyObject__';
5835-
// detect if the variant supports this special property
5836-
if Assigned(Disp) and (Disp.GetIDsOfNames(GUID_NULL, @wStr, 1, 0, @DispID) = S_OK) then
5837-
begin
5838-
myInt := DeRefV.__asPPyObject__; //Returns the address to PPyObject as integer. (See impl. in PythonAtom.pas)
5839-
Result := PPyObject(myInt);
5840-
Py_XIncRef(Result);
5843+
//DAV>>>
5844+
if VarIsSQLTimeStamp(V) then begin
5845+
l_dtSQLTimeStamp := VarToSQLTimeStamp(V);
5846+
dt := SQLTimeStampToDateTime(l_dtSQLTimeStamp);
5847+
DecodeDate( dt, y, m, d );
5848+
DecodeTime( dt, h, mi, sec, ms );
5849+
if (DatetimeConversionMode = dcmToTuple) then begin
5850+
wd := (DayOfWeek( dt ) + 7 - 2) mod 7; // In Python, Monday is the first day (=0)
5851+
jd := Round(EncodeDate(y,m,d)-EncodeDate(y,1,1))+1; // This shoud be the Julian day, the day in a year (0-366)
5852+
dl := -1; // This is daylight save...
5853+
Result := ArrayToPyTuple( [y, m, d, h, mi, sec, wd, jd, dl] );
5854+
end
5855+
else if (DatetimeConversionMode = dcmToDatetime) then begin
5856+
if not Assigned(FPyDateTime_DateTimeType) then
5857+
raise EPythonError.Create('dcmToDatetime DatetimeConversionMode cannot be used with this version of python. Missing module datetime');
5858+
args := ArrayToPyTuple([y, m, d, h, mi, sec, ms*1000]);
5859+
try
5860+
Result := PyEval_CallObjectWithKeywords(FPyDateTime_DateTimeType, args, nil);
5861+
CheckError(False);
5862+
finally
5863+
Py_DecRef(args);
5864+
end;
58415865
end
5842-
else //If variant don't implement __asPPyObject__, then we have to return nothing.
5866+
else
5867+
raise EPythonError.Create('Invalid DatetimeConversionMode');
5868+
end
5869+
else begin
5870+
//DAV<<<
5871+
try
5872+
Disp := DeRefV;
5873+
wStr := '__asPPyObject__';
5874+
// detect if the variant supports this special property
5875+
if Assigned(Disp) and (Disp.GetIDsOfNames(GUID_NULL, @wStr, 1, 0, @DispID) = S_OK) then
5876+
begin
5877+
myInt := DeRefV.__asPPyObject__; //Returns the address to PPyObject as integer. (See impl. in PythonAtom.pas)
5878+
Result := PPyObject(myInt);
5879+
Py_XIncRef(Result);
5880+
end
5881+
else //If variant don't implement __asPPyObject__, then we have to return nothing.
5882+
Result := ReturnNone;
5883+
except
5884+
// if something went wrong, just return none!
58435885
Result := ReturnNone;
5844-
except
5845-
// if something went wrong, just return none!
5846-
Result := ReturnNone;
5847-
end; // of try
5886+
end; // of try
5887+
end;
58485888
end; // of case
58495889
end;
58505890

@@ -6029,7 +6069,7 @@ function TPythonEngine.VarRecAsPyObject( v : TVarRec ) : PPyObject;
60296069
vtString:
60306070
begin
60316071
if Assigned(v.VString) then
6032-
Result := PyString_FromString( StrPCopy( buff, v.VString^) )
6072+
Result := PyString_FromString( System.AnsiStrings.StrPCopy( buff, v.VString^) )
60336073
else
60346074
Result := PyString_FromString( '' );
60356075
end;
@@ -6155,7 +6195,7 @@ function TPythonEngine.ArrayToPyDict( items : array of const) : PPyObject;
61556195
vtAnsiString:
61566196
begin
61576197
if Assigned(v.VAnsiString) then
6158-
Result := StrPas(PAnsiChar(Ansistring(v.VAnsiString)))
6198+
Result := System.AnsiStrings.StrPas(PAnsiChar(Ansistring(v.VAnsiString)))
61596199
else
61606200
Result := '';
61616201
end;
@@ -6807,8 +6847,9 @@ function TMethodsContainer.AddMethod( AMethodName : PAnsiChar;
68076847
AMethod : PyCFunction;
68086848
ADocString : PAnsiChar ) : PPyMethodDef;
68096849
begin
6810-
if FMethodCount = FAllocatedMethodCount then
6850+
if FMethodCount = FAllocatedMethodCount then begin
68116851
ReallocMethods;
6852+
end;
68126853
Result := Methods[ MethodCount ];
68136854
Result^.ml_name := AMethodName;
68146855
Result^.ml_meth := AMethod;
@@ -7582,6 +7623,19 @@ procedure TPythonModule.DeleteVar( const varName : AnsiString );
75827623
raise EPythonError.CreateFmt( 'Can''t delete var "%s" in module "%s", because it is not yet initialized', [varName, ModuleName] );
75837624
end;
75847625

7626+
//DAV>>>
7627+
procedure TPythonModule.ClearVars;
7628+
var
7629+
dict : PPyObject;
7630+
begin
7631+
if Assigned(FEngine) and Assigned( FModule ) then
7632+
with Engine do begin
7633+
dict := PyModule_GetDict( Module );
7634+
PyDict_Clear(dict);
7635+
end;
7636+
end;
7637+
//DAV<<<
7638+
75857639
procedure TPythonModule.SetVarFromVariant( const varName : AnsiString; const value : Variant );
75867640
var
75877641
obj : PPyObject;

0 commit comments

Comments
 (0)