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

Commit 5764f7e

Browse files
Fix for extra paths inside workspace (#467)
Fix #281: Support "go to definition" for namespace packages Fix #466: Fix "go to definition" and resolving imports The fix is to put user search paths in front of workspace directory so that modules inside extra paths can be used as roots for packages
1 parent 64eae15 commit 5764f7e

File tree

4 files changed

+83
-7
lines changed

4 files changed

+83
-7
lines changed

src/Analysis/Engine/Impl/DependencyResolution/PathResolverSnapshot.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -359,11 +359,11 @@ private void CreateRootsWithDefault(string rootDirectory, string[] userSearchPat
359359
.ToArray();
360360

361361
var filteredInterpreterSearchPaths = interpreterSearchPaths.Select(FixPath)
362-
.Except(filteredUserSearchPaths.Prepend(rootDirectory))
362+
.Except(filteredUserSearchPaths.Append(rootDirectory))
363363
.ToArray();
364364

365365
userRootsCount = filteredUserSearchPaths.Length + 1;
366-
nodes = AddRootsFromSearchPaths(ImmutableArray<Node>.Empty.Add(GetOrCreateRoot(rootDirectory)), filteredUserSearchPaths, filteredInterpreterSearchPaths);
366+
nodes = AddRootsFromSearchPaths(rootDirectory, filteredUserSearchPaths, filteredInterpreterSearchPaths);
367367

368368
string FixPath(string p) => Path.IsPathRooted(p) ? PathUtils.NormalizePath(p) : PathUtils.NormalizePath(Path.Combine(rootDirectory, p));
369369
}
@@ -381,11 +381,18 @@ private void CreateRootsWithoutDefault(string[] userSearchPaths, string[] interp
381381
.ToArray();
382382

383383
userRootsCount = filteredUserSearchPaths.Length;
384-
nodes = AddRootsFromSearchPaths(ImmutableArray<Node>.Empty, filteredUserSearchPaths, filteredInterpreterSearchPaths);
384+
nodes = AddRootsFromSearchPaths(filteredUserSearchPaths, filteredInterpreterSearchPaths);
385385
}
386386

387-
private ImmutableArray<Node> AddRootsFromSearchPaths(ImmutableArray<Node> roots, string[] userSearchPaths, string[] interpreterSearchPaths) {
388-
return roots
387+
private ImmutableArray<Node> AddRootsFromSearchPaths(string rootDirectory, string[] userSearchPaths, string[] interpreterSearchPaths) {
388+
return ImmutableArray<Node>.Empty
389+
.AddRange(userSearchPaths.Select(GetOrCreateRoot).ToArray())
390+
.Add(GetOrCreateRoot(rootDirectory))
391+
.AddRange(interpreterSearchPaths.Select(GetOrCreateRoot).ToArray());
392+
}
393+
394+
private ImmutableArray<Node> AddRootsFromSearchPaths(string[] userSearchPaths, string[] interpreterSearchPaths) {
395+
return ImmutableArray<Node>.Empty
389396
.AddRange(userSearchPaths.Select(GetOrCreateRoot).ToArray())
390397
.AddRange(interpreterSearchPaths.Select(GetOrCreateRoot).ToArray());
391398
}

src/Analysis/Engine/Impl/PythonAnalyzer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ private async Task LoadKnownTypesAsync(CancellationToken token) {
129129
}
130130

131131
private void ReloadModulePaths(in IEnumerable<string> rootPaths) {
132-
foreach (var modulePath in rootPaths.Where(Directory.Exists).SelectMany(p => ModulePath.GetModulesInPath(p))) {
133-
_pathResolver.TryAddModulePath(modulePath.SourceFile, out _);
132+
foreach (var modulePath in rootPaths.Where(Directory.Exists).SelectMany(p => PathUtils.EnumerateFiles(p))) {
133+
_pathResolver.TryAddModulePath(modulePath, out _);
134134
}
135135
}
136136

src/Analysis/Engine/Test/ImportTests.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,67 @@ import package.sub_package.module2
9898
completionModule2.Should().HaveLabels("Y").And.NotContainLabels("X");
9999
}
100100

101+
[ServerTestMethod(LatestAvailable3X = true, TestSpecificRootUri = true), Priority(0)]
102+
public async Task Completions_ImportResolution_UserSearchPathsInsideWorkspace(Server server) {
103+
var folder1 = TestData.GetTestSpecificPath("folder1");
104+
var folder2 = TestData.GetTestSpecificPath("folder2");
105+
var packageInFolder1 = Path.Combine(folder1, "package");
106+
var packageInFolder2 = Path.Combine(folder2, "package");
107+
var module1Path = Path.Combine(packageInFolder1, "module1.py");
108+
var module2Path = Path.Combine(packageInFolder2, "module2.py");
109+
var module1Content = @"class A():
110+
@staticmethod
111+
def method1():
112+
pass";
113+
var module2Content = @"class B():
114+
@staticmethod
115+
def method2():
116+
pass";
117+
var mainContent = @"from package import module1 as mod1, module2 as mod2
118+
mod1.
119+
mod2.
120+
mod1.A.
121+
mod2.B.";
122+
123+
server.Analyzer.SetSearchPaths(new[] { folder1, folder2 });
124+
125+
await server.OpenDocumentAndGetUriAsync(module1Path, module1Content);
126+
await server.OpenDocumentAndGetUriAsync(module2Path, module2Content);
127+
var uri = await server.OpenDocumentAndGetUriAsync("main.py", mainContent);
128+
129+
await server.WaitForCompleteAnalysisAsync(CancellationToken.None);
130+
131+
var completionMod1 = await server.SendCompletion(uri, 1, 5);
132+
var completionMod2 = await server.SendCompletion(uri, 2, 5);
133+
var completionA = await server.SendCompletion(uri, 3, 7);
134+
var completionB = await server.SendCompletion(uri, 4, 7);
135+
completionMod1.Should().HaveLabels("A").And.NotContainLabels("B");
136+
completionMod2.Should().HaveLabels("B").And.NotContainLabels("A");
137+
completionA.Should().HaveLabels("method1");
138+
completionB.Should().HaveLabels("method2");
139+
}
140+
141+
[ServerTestMethod(LatestAvailable3X = true, TestSpecificRootUri = true), Priority(0)]
142+
[Ignore("https://github.com/Microsoft/python-language-server/issues/468")]
143+
public async Task Completions_ImportResolution_ModuleInWorkspaceAndInUserSearchPath(Server server) {
144+
var extraSearchPath = TestData.GetTestSpecificPath(Path.Combine("some", "other"));
145+
var module1Path = TestData.GetTestSpecificPath("module.py");
146+
var module2Path = Path.Combine(extraSearchPath, "module.py");
147+
var module1Content = "A = 1";
148+
var module2Content = "B = 2";
149+
var mainContent = @"import module as mod; mod.";
150+
151+
server.Analyzer.SetSearchPaths(new[] { extraSearchPath });
152+
153+
await server.OpenDocumentAndGetUriAsync(module1Path, module1Content);
154+
await server.OpenDocumentAndGetUriAsync(module2Path, module2Content);
155+
var uri = await server.OpenDocumentAndGetUriAsync("main.py", mainContent);
156+
157+
await server.WaitForCompleteAnalysisAsync(CancellationToken.None);
158+
var completion = await server.SendCompletion(uri, 0, 26);
159+
completion.Should().HaveLabels("A").And.NotContainLabels("B");
160+
}
161+
101162
[Ignore("https://github.com/Microsoft/python-language-server/issues/443")]
102163
[ServerTestMethod(LatestAvailable3X = true, TestSpecificRootUri = true), Priority(0)]
103164
public async Task Completions_ImportResolution_OneSearchPathInsideAnother(Server server) {

src/Analysis/Engine/Test/ServerExtensions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@ await server.DidOpenTextDocument(new DidOpenTextDocumentParams {
164164
}, GetCancellationToken());
165165
}
166166

167+
public static async Task<IModuleAnalysis> OpenDocumentAndGetAnalysisAsync(this Server server, string relativePath, string content, int failAfter = 30000, string languageId = null) {
168+
var cancellationToken = GetCancellationToken(failAfter);
169+
var uri = TestData.GetTestSpecificUri(relativePath);
170+
await server.SendDidOpenTextDocument(uri, content, languageId);
171+
cancellationToken.ThrowIfCancellationRequested();
172+
return await server.GetAnalysisAsync(uri, cancellationToken);
173+
}
174+
167175
public static async Task<IModuleAnalysis> OpenDefaultDocumentAndGetAnalysisAsync(this Server server, string content, int failAfter = 30000, string languageId = null) {
168176
var cancellationToken = GetCancellationToken(failAfter);
169177
await server.SendDidOpenTextDocument(TestData.GetDefaultModuleUri(), content, languageId);

0 commit comments

Comments
 (0)