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

Add submodules to completion list #1896

Merged
merged 30 commits into from
Feb 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c6a9c22
Remove stale reference
Sep 30, 2019
1360827
Merge branch 'master' of https://github.com/microsoft/python-language…
Oct 1, 2019
ccaaa02
Merge branch 'master' of https://github.com/microsoft/python-language…
Oct 4, 2019
da40dcc
Merge branch 'master' of https://github.com/microsoft/python-language…
Oct 4, 2019
c348ac3
Merge branch 'master' of https://github.com/microsoft/python-language…
Oct 5, 2019
53bc044
Merge branch 'master' of https://github.com/microsoft/python-language…
Oct 7, 2019
484a92a
Merge branch 'master' of https://github.com/MikhailArkhipov/python-la…
Oct 7, 2019
e6df3aa
Merge branch 'master' of https://github.com/microsoft/python-language…
Oct 8, 2019
1d289d8
Merge branch 'master' of https://github.com/microsoft/python-language…
Oct 8, 2019
126f355
Merge branch 'master' of https://github.com/microsoft/python-language…
Oct 12, 2019
7e715f3
Merge branch 'master' of https://github.com/microsoft/python-language…
Oct 25, 2019
32923a5
Merge branch 'master' of https://github.com/microsoft/python-language…
Oct 31, 2019
1b72f4b
Merge branch 'master' of https://github.com/microsoft/python-language…
Nov 2, 2019
f74d5b6
Merge branch 'master' of https://github.com/microsoft/python-language…
Nov 7, 2019
0b28fa4
Merge branch 'master' of https://github.com/microsoft/python-language…
Nov 12, 2019
6109ac7
Don't suppress LHS diagnostics on augmented assign
Nov 12, 2019
bcfc3b7
Revert "Don't suppress LHS diagnostics on augmented assign"
Nov 12, 2019
dc286b8
Merge branch 'master' of https://github.com/microsoft/python-language…
Nov 13, 2019
0aab4f5
Merge branch 'master' of https://github.com/microsoft/python-language…
Nov 16, 2019
b953ce7
Merge branch 'master' of https://github.com/microsoft/python-language…
Nov 18, 2019
aef887d
Merge branch 'master' of https://github.com/microsoft/python-language…
Dec 10, 2019
b97b641
Merge branch 'master' of https://github.com/microsoft/python-language…
Dec 11, 2019
c16646d
Escape [ and ]
Dec 13, 2019
f3e08d5
Merge branch 'master' of https://github.com/MikhailArkhipov/python-la…
Dec 13, 2019
5700642
PR feedback
Dec 13, 2019
1d091db
Merge branch 'master' of https://github.com/microsoft/python-language…
Dec 13, 2019
b8c3615
Merge branch 'master' of https://github.com/microsoft/python-language…
Dec 16, 2019
6a88069
Merge branch 'master' of https://github.com/microsoft/python-language…
Jan 28, 2020
9f129b9
Add imported submodules to completions
Jan 30, 2020
6ac53c9
Fix test
Jan 30, 2020
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
22 changes: 20 additions & 2 deletions src/Analysis/Ast/Impl/Modules/PythonModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using Microsoft.Python.Analysis.Analyzer;
using Microsoft.Python.Analysis.Analyzer.Evaluation;
using Microsoft.Python.Analysis.Analyzer.Handlers;
using Microsoft.Python.Analysis.Core.DependencyResolution;
using Microsoft.Python.Analysis.Dependencies;
using Microsoft.Python.Analysis.Diagnostics;
using Microsoft.Python.Analysis.Documents;
Expand Down Expand Up @@ -148,9 +149,26 @@ public virtual string Documentation {
#endregion

#region IMemberContainer
public virtual IMember GetMember(string name) => GlobalScope.Variables[name]?.Value;

public virtual IEnumerable<string> GetMemberNames() => GlobalScope.GetExportableVariableNames();
public virtual IMember GetMember(string name) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This modifies all accesses, not just the completion for imports. Is this what you expect? Not sure if we had removed this behavior or modified at some point in the past or not... Vaguely remember something like this previously and having to be careful to present things in the right place.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if it is a legal member Python can find, it should be exposed. I looked into past history and found that handling of submodules was added for import statement completion specifically. This code is basically borrowed from there.

var v = GlobalScope.Variables[name]?.Value;
if (v == null) {
var mres = Interpreter.ModuleResolution;
var result = mres.CurrentPathResolver.FindImports(FilePath, Enumerable.Repeat(name, 1), 0, false);
if (result is ModuleImport moduleImports) {
v = mres.GetImportedModule(moduleImports.FullName);
}
}
return v;
}

public virtual IEnumerable<string> GetMemberNames() {
var names = GlobalScope.GetExportableVariableNames();
// Get submodules since they may not be explicitly exported
// and yet are available. Consider 'pandas.io'.
var mi = Interpreter.ModuleResolution.CurrentPathResolver.GetModuleImportFromModuleName(Name);
return names.Concat(mi?.GetChildrenNames() ?? Enumerable.Empty<string>()).Distinct();
}

#endregion

Expand Down
2 changes: 1 addition & 1 deletion src/LanguageServer/Impl/Completion/ImportCompletion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ private static CompletionResult GetResultFromImportSearch(IImportSearchResult im
break;
}

if (name != null && !memberNames.Contains(name)) {
if (name != null && !completions.Any(c => c.label == name && c.kind == CompletionItemKind.Module)) {
completions.Add(CompletionItemSource.CreateCompletionItem(name, CompletionItemKind.Module));
}
}
Expand Down
36 changes: 35 additions & 1 deletion src/LanguageServer/Test/CompletionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1017,7 +1017,7 @@ public async Task FromDotInRootWithInitPy() {

var cs = new CompletionSource(new PlainTextDocumentationSource(), ServerSettings.completion, Services);
var result = cs.GetCompletions(analysis, new SourceLocation(1, 7));
result.Should().OnlyHaveLabels("__dict__", "__file__", "__doc__", "__package__", "__debug__", "__name__", "__path__", "__spec__");
result.Should().OnlyHaveLabels("__dict__", "__file__", "__doc__", "__package__", "__debug__", "__name__", "__path__", "__spec__", "module1");
}

[TestMethod, Priority(0)]
Expand Down Expand Up @@ -1511,5 +1511,39 @@ def print_EQ2(cls):
result = cs.GetCompletions(analysis, new SourceLocation(12, 13));
result.Should().HaveLabels("__EQ", "__NOT_EQ", "__OP_LIST");
}

[DataTestMethod, Priority(0)]
[DataRow(true)]
[DataRow(false)]
public async Task ImplicitSubmodule(bool imported) {
var appUri = TestData.GetTestSpecificUri("app.py");
await TestData.CreateTestSpecificFileAsync(
Path.Combine("package", "__init__.py"),
imported ? "import package.m1 as m2" : string.Empty
);
await TestData.CreateTestSpecificFileAsync(Path.Combine("package", "m1", "__init__.py"), "x = 1");

await CreateServicesAsync(PythonVersions.LatestAvailable3X);
var rdt = Services.GetService<IRunningDocumentTable>();
const string code = @"
import package
package.
package.m1.
";
var doc = rdt.OpenDocument(appUri, code);

await Services.GetService<IPythonAnalyzer>().WaitForCompleteAnalysisAsync();
var analysis = await doc.GetAnalysisAsync(Timeout.Infinite);
var cs = new CompletionSource(new PlainTextDocumentationSource(), ServerSettings.completion, Services);

var result = cs.GetCompletions(analysis, new SourceLocation(3, 9));
result.Should().HaveLabels("m1");
result = cs.GetCompletions(analysis, new SourceLocation(4, 12));
if (imported) {
result.Should().HaveLabels("x");
} else {
result.Should().NotContainLabels("x");
}
}
}
}