diff --git a/src/Analysis/Ast/Test/PathClassificationTests.cs b/src/Analysis/Ast/Test/PathClassificationTests.cs index 429df72b7..b6dac71eb 100644 --- a/src/Analysis/Ast/Test/PathClassificationTests.cs +++ b/src/Analysis/Ast/Test/PathClassificationTests.cs @@ -214,5 +214,39 @@ public void InsideStdLib() { new PythonLibraryPath(src, PythonLibraryPathType.Unspecified), }); } + + [TestMethod] + public void SiteOutsideStdlib() { + var appPath = TestData.GetTestSpecificPath("app.py"); + var root = Path.GetDirectoryName(appPath); + + var venv = Path.Combine(root, "venv"); + var venvLib = Path.Combine(venv, "Lib"); + var sitePackages = Path.Combine(root, "site-packages"); + + var src = Path.Combine(root, "src"); + + var fromInterpreter = new[] { + new PythonLibraryPath(venvLib, PythonLibraryPathType.StdLib), + new PythonLibraryPath(venv, PythonLibraryPathType.StdLib), + new PythonLibraryPath(sitePackages, PythonLibraryPathType.Site), + }; + + var fromUser = new[] { + "./src", + }; + + var (interpreterPaths, userPaths) = PythonLibraryPath.ClassifyPaths(root, _fs, fromInterpreter, fromUser); + + interpreterPaths.Should().BeEquivalentToWithStrictOrdering(new[] { + new PythonLibraryPath(venvLib, PythonLibraryPathType.StdLib), + new PythonLibraryPath(venv, PythonLibraryPathType.StdLib), + new PythonLibraryPath(sitePackages, PythonLibraryPathType.Site), + }); + + userPaths.Should().BeEquivalentToWithStrictOrdering(new[] { + new PythonLibraryPath(src, PythonLibraryPathType.Unspecified), + }); + } } } diff --git a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs index 5a1b3e4a0..dfb9760a1 100644 --- a/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs +++ b/src/Analysis/Core/Impl/Interpreter/PythonLibraryPath.cs @@ -186,11 +186,14 @@ public static async Task> GetSearchPathsFromInterpreterA try { var output = await ps.ExecuteAndCaptureOutputAsync(startInfo, cancellationToken); return output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Select(s => { - if (PathUtils.PathStartsWith(s, tempWorkingDir)) { - return null; - } try { - return Parse(s); + var p = Parse(s); + + if (PathUtils.PathStartsWith(p.Path, tempWorkingDir)) { + return null; + } + + return p; } catch (ArgumentException) { Debug.Fail("Invalid search path: " + (s ?? "")); return null; @@ -249,6 +252,12 @@ IEnumerable fromUser continue; } + // If Python says it's site, then treat is as interpreter. + if (p.Type == PythonLibraryPathType.Site) { + interpreterPaths.Add(p); + continue; + } + // If path is outside the workspace, then treat it as interpreter. if (root == null || !fs.IsPathUnderRoot(root, p.Path)) { interpreterPaths.Add(p);