Skip to content

Commit 0209f11

Browse files
committed
1 parent 0d606f5 commit 0209f11

File tree

2 files changed

+58
-4
lines changed

2 files changed

+58
-4
lines changed

PythonForDelphi/Components/Sources/Core/PythonEngine.pas

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2201,6 +2201,7 @@ TPythonTraceback = class
22012201
{$IFEND}
22022202
TPythonEngine = class(TPythonInterface)
22032203
private
2204+
FVenvPythonExe: string;
22042205
FInitScript: TStrings;
22052206
FIO: TPythonInputOutput;
22062207
FRedirectIO: Boolean;
@@ -2352,6 +2353,7 @@ TPythonEngine = class(TPythonInterface)
23522353
property IOPythonModule: TObject read FIOPythonModule; {TPythonModule}
23532354
published
23542355
property AutoFinalize: Boolean read FAutoFinalize write FAutoFinalize default True;
2356+
property VenvPythonExe: string read FVenvPythonExe write FVenvPythonExe;
23552357
property DatetimeConversionMode: TDatetimeConversionMode read FDatetimeConversionMode write FDatetimeConversionMode default DEFAULT_DATETIME_CONVERSION_MODE;
23562358
property InitScript: TStrings read FInitScript write SetInitScript;
23572359
property InitThreads: Boolean read FInitThreads write SetInitThreads default False;
@@ -4828,7 +4830,19 @@ procedure TPythonEngine.Initialize;
48284830
procedure InitSysPath;
48294831
var
48304832
_path : PPyObject;
4833+
const Script =
4834+
'import sys' + sLineBreak +
4835+
'sys.executable = r"%s"' + sLineBreak +
4836+
'path = sys.path' + sLineBreak +
4837+
'for i in range(len(path)-1, -1, -1):' + sLineBreak +
4838+
' if path[i].find("site-packages") > 0:' + sLineBreak +
4839+
' path.pop(i)' + sLineBreak +
4840+
'import site' + sLineBreak +
4841+
'site.main()' + sLineBreak +
4842+
'del sys, path, i, site';
48314843
begin
4844+
if VenvPythonExe <> '' then
4845+
ExecString(Format(Script, [VenvPythonExe]));
48324846
_path := PySys_GetObject('path');
48334847
if Assigned(FOnSysPathInit) then
48344848
FOnSysPathInit(Self, _path);

PythonForDelphi/Components/Sources/Core/PythonVersions.pas

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ TPythonVersion = record
7272
function GetRegisteredPythonVersions : TPythonVersions;
7373
(* Returns the highest numbered registered Python version *)
7474
function GetLatestRegisteredPythonVersion(out PythonVersion: TPythonVersion): Boolean;
75-
function PythonVersionFromPath(const Path: string; out PythonVersion: TPythonVersion): Boolean;
75+
function PythonVersionFromPath(const Path: string; out PythonVersion: TPythonVersion;
76+
AcceptVirtualEnvs: Boolean = True): Boolean;
7677
{$ENDIF}
7778

7879
implementation
@@ -122,6 +123,11 @@ procedure TPythonVersion.AssignTo(PythonEngine: TPersistent);
122123
TPythonEngine(PythonEngine).DllName := DLLName;
123124
TPythonEngine(PythonEngine).DllPath := DLLPath;
124125
TPythonEngine(PythonEngine).APIVersion := ApiVersion;
126+
if Is_venv then begin
127+
TPythonEngine(PythonEngine).VenvPythonExe := PythonExecutable;
128+
TPythonEngine(PythonEngine).SetPythonHome(DLLPath);
129+
end else if not IsRegistered then
130+
TPythonEngine(PythonEngine).SetPythonHome(InstallPath);
125131
end;
126132
end;
127133

@@ -416,7 +422,9 @@ function GetLatestRegisteredPythonVersion(out PythonVersion: TPythonVersion): Bo
416422
end;
417423
end;
418424

419-
function PythonVersionFromPath(const Path: string; out PythonVersion: TPythonVersion): Boolean;
425+
function PythonVersionFromPath(const Path: string; out PythonVersion: TPythonVersion;
426+
AcceptVirtualEnvs: Boolean = True): Boolean;
427+
420428
function FindPythonDLL(APath : string): string;
421429
Var
422430
FindFileData: TWIN32FindData;
@@ -436,10 +444,29 @@ function PythonVersionFromPath(const Path: string; out PythonVersion: TPythonVer
436444
Result := DLLFileName;
437445
end;
438446

447+
function GetVenvBasePrefix(InstallPath: string): string;
448+
var
449+
SL : TStringList;
450+
begin
451+
SL := TStringList.Create;
452+
try
453+
try
454+
SL.LoadFromFile(IncludeTrailingPathDelimiter(InstallPath)+'pyvenv.cfg');
455+
Result := Trim(SL.Values['home']);
456+
if Result = '' then
457+
Result := Trim(SL.Values['home ']);
458+
except
459+
end;
460+
finally
461+
SL.Free;
462+
end;
463+
end;
464+
439465
Var
440466
DLLFileName: string;
441467
DLLPath: string;
442468
SysVersion: string;
469+
BasePrefix: string;
443470
I: integer;
444471
begin
445472
Result := False;
@@ -450,11 +477,24 @@ function PythonVersionFromPath(const Path: string; out PythonVersion: TPythonVer
450477
PythonVersion.InstallPath := DLLPath;
451478

452479
DLLFileName := FindPythonDLL(DLLPath);
453-
if DLLFileName = '' then begin
480+
481+
if (DLLFileName = '') and AcceptVirtualEnvs then begin
454482
DLLPath := DLLPath + '\Scripts';
455483
DLLFileName := FindPythonDLL(DLLPath);
456484
end;
457-
if DLLFileName = '' then Exit;
485+
if DLLFileName = '' then begin
486+
if AcceptVirtualEnvs and PythonVersion.Is_venv then
487+
begin
488+
BasePrefix := GetVenvBasePrefix(PythonVersion.InstallPath);
489+
if (BasePrefix <> '') and PythonVersionFromPath(BasePrefix, PythonVersion, False) then
490+
begin
491+
// Install path points to venv but the rest of the info is from base_prefix
492+
PythonVersion.InstallPath := ExcludeTrailingPathDelimiter(Path);
493+
Result := True;
494+
end;
495+
end;
496+
Exit;
497+
end;
458498

459499
// check if same platform
460500
try

0 commit comments

Comments
 (0)