Skip to content

Commit c5a1cdb

Browse files
committed
Add support for linux virtual environments
1 parent acb2244 commit c5a1cdb

File tree

2 files changed

+70
-33
lines changed

2 files changed

+70
-33
lines changed

src/Bonsai.Scripting.Python/EnvironmentHelper.cs

+66-23
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,105 @@
11
using System;
22
using System.IO;
3-
using System.Linq;
3+
using System.Runtime.InteropServices;
44
using Python.Runtime;
55

66
namespace Bonsai.Scripting.Python
77
{
88
static class EnvironmentHelper
99
{
10-
public static string GetPythonDLL(string path)
10+
public static string GetPythonDLL(string pythonVersion)
1111
{
12-
return Directory
13-
.EnumerateFiles(path, searchPattern: "python3?*.*")
14-
.Select(Path.GetFileNameWithoutExtension)
15-
.Where(match => match.Length > "python3".Length)
16-
.Select(match => match.Replace(".", string.Empty))
17-
.FirstOrDefault();
12+
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
13+
? $"python{pythonVersion.Replace(".", string.Empty)}.dll"
14+
: $"libpython{pythonVersion}.so";
1815
}
1916

2017
public static void SetRuntimePath(string pythonHome)
2118
{
22-
var path = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process).TrimEnd(Path.PathSeparator);
23-
path = string.IsNullOrEmpty(path) ? pythonHome : pythonHome + Path.PathSeparator + path;
24-
Environment.SetEnvironmentVariable("PATH", path, EnvironmentVariableTarget.Process);
19+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
20+
{
21+
var path = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process).TrimEnd(Path.PathSeparator);
22+
path = string.IsNullOrEmpty(path) ? pythonHome : pythonHome + Path.PathSeparator + path;
23+
Environment.SetEnvironmentVariable("PATH", path, EnvironmentVariableTarget.Process);
24+
}
25+
}
26+
27+
public static string GetVirtualEnvironmentPath(string path)
28+
{
29+
if (string.IsNullOrEmpty(path))
30+
{
31+
path = Environment.GetEnvironmentVariable("VIRTUAL_ENV", EnvironmentVariableTarget.Process);
32+
if (path == null) return path;
33+
}
34+
35+
return Path.GetFullPath(path);
2536
}
2637

27-
public static string GetPythonHome(string path)
38+
public static string GetPythonHome(string path, out string pythonVersion)
2839
{
40+
var pythonHome = path;
41+
pythonVersion = string.Empty;
2942
var configFileName = Path.Combine(path, "pyvenv.cfg");
3043
if (File.Exists(configFileName))
3144
{
3245
using var configReader = new StreamReader(File.OpenRead(configFileName));
3346
while (!configReader.EndOfStream)
3447
{
3548
var line = configReader.ReadLine();
36-
if (line.StartsWith("home"))
49+
static string GetConfigValue(string line)
3750
{
3851
var parts = line.Split('=');
39-
return parts[parts.Length - 1].Trim();
52+
return parts.Length > 1 ? parts[1].Trim() : string.Empty;
53+
}
54+
55+
if (line.StartsWith("home"))
56+
{
57+
pythonHome = GetConfigValue(line);
58+
}
59+
else if (line.StartsWith("version"))
60+
{
61+
pythonVersion = GetConfigValue(line);
62+
if (!string.IsNullOrEmpty(pythonVersion))
63+
{
64+
pythonVersion = pythonVersion.Substring(0, pythonVersion.LastIndexOf('.'));
65+
}
4066
}
4167
}
4268
}
4369

44-
return path;
70+
return pythonHome;
4571
}
4672

47-
public static string GetPythonPath(string pythonHome, string path)
73+
public static string GetPythonPath(string pythonHome, string pythonVersion, string path)
4874
{
75+
string sitePackages;
4976
var basePath = PythonEngine.PythonPath;
50-
if (string.IsNullOrEmpty(basePath))
77+
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
78+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
5179
{
52-
var pythonZip = Path.Combine(pythonHome, Path.ChangeExtension(Runtime.PythonDLL, ".zip"));
53-
var pythonDLLs = Path.Combine(pythonHome, "DLLs");
54-
var pythonLib = Path.Combine(pythonHome, "Lib");
55-
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
56-
basePath = string.Join(Path.PathSeparator.ToString(), pythonZip, pythonDLLs, pythonLib, baseDirectory);
80+
if (string.IsNullOrEmpty(basePath))
81+
{
82+
var pythonZip = Path.Combine(pythonHome, Path.ChangeExtension(Runtime.PythonDLL, ".zip"));
83+
var pythonDLLs = Path.Combine(pythonHome, "DLLs");
84+
var pythonLib = Path.Combine(pythonHome, "Lib");
85+
basePath = string.Join(Path.PathSeparator.ToString(), pythonZip, pythonDLLs, pythonLib, baseDirectory);
86+
}
87+
88+
sitePackages = Path.Combine(path, "Lib", "site-packages");
89+
}
90+
else
91+
{
92+
if (string.IsNullOrEmpty(basePath))
93+
{
94+
var pythonBase = Path.GetDirectoryName(pythonHome);
95+
pythonBase = Path.Combine(pythonBase, "lib", $"python{pythonVersion}");
96+
var pythonLibDynload = Path.Combine(pythonBase, "lib-dynload");
97+
basePath = string.Join(Path.PathSeparator.ToString(), pythonBase, pythonLibDynload, baseDirectory);
98+
}
99+
100+
sitePackages = Path.Combine(path, "lib", $"python{pythonVersion}", "site-packages");
57101
}
58102

59-
var sitePackages = Path.Combine(path, "Lib", "site-packages");
60103
return $"{basePath}{Path.PathSeparator}{path}{Path.PathSeparator}{sitePackages}";
61104
}
62105
}

src/Bonsai.Scripting.Python/RuntimeManager.cs

+4-10
Original file line numberDiff line numberDiff line change
@@ -115,21 +115,15 @@ static void Initialize(string path)
115115
{
116116
if (!PythonEngine.IsInitialized)
117117
{
118-
if (string.IsNullOrEmpty(path))
119-
{
120-
path = Environment.GetEnvironmentVariable("VIRTUAL_ENV", EnvironmentVariableTarget.Process);
121-
if (string.IsNullOrEmpty(path)) path = Environment.CurrentDirectory;
122-
}
123-
124-
path = Path.GetFullPath(path);
125-
var pythonHome = EnvironmentHelper.GetPythonHome(path);
126-
Runtime.PythonDLL = EnvironmentHelper.GetPythonDLL(pythonHome);
118+
path = EnvironmentHelper.GetVirtualEnvironmentPath(path);
119+
var pythonHome = EnvironmentHelper.GetPythonHome(path, out string pythonVersion);
120+
Runtime.PythonDLL = EnvironmentHelper.GetPythonDLL(pythonVersion);
127121
EnvironmentHelper.SetRuntimePath(pythonHome);
128122
PythonEngine.PythonHome = pythonHome;
129123
if (pythonHome != path)
130124
{
131125
var version = PythonEngine.Version;
132-
PythonEngine.PythonPath = EnvironmentHelper.GetPythonPath(pythonHome, path);
126+
PythonEngine.PythonPath = EnvironmentHelper.GetPythonPath(pythonHome, pythonVersion, path);
133127
}
134128
PythonEngine.Initialize();
135129
}

0 commit comments

Comments
 (0)