Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Look into PATH for python if not provided in initialization options #1949

Merged
merged 2 commits into from
Mar 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/Core/Impl/IO/PathUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -518,5 +518,30 @@ public static string NormalizePath(string path) {
}

public static string NormalizePathAndTrim(string path) => TrimEndSeparator(NormalizePath(path));

public static string LookPath(IFileSystem fs, string exeName) {
var path = Environment.GetEnvironmentVariable("PATH");
if (string.IsNullOrWhiteSpace(path)) {
return null;
}

foreach (var p in path.Split(Path.PathSeparator)) {
var x = Path.Combine(p, exeName);

if (IsWindows) {
x += ".exe"; // TODO: other extensions?
}

if (!fs.FileExists(x)) {
continue;
}

// TODO: check executable on non-Windows platforms.

return x;
}

return null;
}
}
}
48 changes: 46 additions & 2 deletions src/LanguageServer/Impl/Implementation/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Python.Analysis;
Expand Down Expand Up @@ -138,10 +139,24 @@ public async Task InitializedAsync(InitializedParams @params, CancellationToken
_services.AddService(new RunningDocumentTable(_services));
_rdt = _services.GetService<IRunningDocumentTable>();

Version.TryParse(initializationOptions?.interpreter.properties?.Version, out var version);
var interpeterPath = initializationOptions?.interpreter.properties?.InterpreterPath;
Version version = null;

if (!string.IsNullOrWhiteSpace(interpeterPath)) {
Version.TryParse(initializationOptions?.interpreter.properties?.Version, out version);
} else {
var fs = _services.GetService<IFileSystem>();
var exePath = PathUtils.LookPath(fs, "python");
if (exePath != null && TryGetPythonVersion(exePath, out version)) {
_log?.Log(TraceEventType.Information, Resources.UsingPythonFromPATH);
interpeterPath = exePath;
} else {
interpeterPath = null;
}
}

var configuration = new InterpreterConfiguration(
interpreterPath: initializationOptions?.interpreter.properties?.InterpreterPath,
interpreterPath: interpeterPath,
version: version
);
_services.AddService(new ModuleDatabase(_services));
Expand Down Expand Up @@ -286,6 +301,35 @@ private void ResetAnalyzer() {
_log?.Log(TraceEventType.Information, Resources.AnalysisRestarted);
}).DoNotWait();
}

private bool TryGetPythonVersion(string exePath, out Version version) {
try {
using var process = new Process {
StartInfo = new ProcessStartInfo {
FileName = exePath,
Arguments = "-c \"import sys; print('{}.{}.{}'.format(*sys.version_info))\"",
UseShellExecute = false,
ErrorDialog = false,
CreateNoWindow = true,
StandardOutputEncoding = Encoding.UTF8,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true
}
};

process.ErrorDataReceived += (s, e) => { };
process.Start();
process.BeginErrorReadLine();

var output = process.StandardOutput.ReadToEnd();

return Version.TryParse(output, out version);
} catch (Exception ex) when (!ex.IsCriticalException()) { }

version = null;
return false;
}
#endregion
}
}
9 changes: 9 additions & 0 deletions src/LanguageServer/Impl/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/LanguageServer/Impl/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@
<data name="RenameVariable_CannotRename" xml:space="preserve">
<value>Cannot rename</value>
</data>
<data name="UsingPythonFromPATH" xml:space="preserve">
<value>No interpreter specified, using Python from PATH.</value>
</data>
<data name="WorkspaceRoot" xml:space="preserve">
<value>Workspace root: {0}</value>
</data>
Expand Down