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

Commit 75e14ab

Browse files
author
Mikhail Arkhipov
authored
De-duplicate completions (#602)
* Part 7 * Buildable * PR feedback * Merge conflict * Fix #446 * Fix #446 * Part 8 * Part 9 * Buildable * Part 10 * Part 11 * Part 12 * Buildable * Part 14 * First passing test * Simplify configuration * Style * Fix test and move code to folders * Builtins import * Fix #470 * Fluents * Add search path * Import analysis, part I * Simplify builtins handling * Remove IMember * Handle import specific * More tests * Add typeshed * Renames * Make sure lazy modules are loaded * Renames * Move/rename * Rework importing * Derivation rework * Part 2 * Part 3 * Buildable * Module members * Async walk * Imports test pass * Remove lazy types * Fix from import * Stubs * Double overloads * Fix datetime test * Couple more tests + fluents * Few more tests * Additionl test + union type * Built-in scrape tests * Full stdlib scrape test * Complete async AST walker * Conditional defines test + variable loc cleanup * More stub tests Fix stub loading for packages (port from DDG) Split walker into multiple files * Add some (broken mostly) tests from DDG * Move document tests * Function arg eval, part I * Instance/factory * Builds * Test fixes * Fix static and instance call eval * More tests * More ported tests * Specialize builtin functions * Make walkers common and handle nested functions * Moar tests * Parser fixes + more tests * Handle negative numbers * Fix null ref * Basic list support * Few more list tests * Basic iterators * Support __iter__ * Iterators * Fix couple of tests * Add decorator test * Generics, part I * Generics, part 2 * Generics, part 3 * Basic TypeVar test * Typings, part 4 * Fix test * Generics, part 6 * Generics, part 7 * More tests (failing) * Forward ref fixes * Reorg * Improve symbol resolution + test fixes * Test fixes * Dictionary, part I * Part 11 * Fix test * Tests * Tests * More dict work * List ctor * Skip some tests for now * Fix iterators * Tuple slicing * Polish type comparo in return types * Add Mapping and tests * Add Iterable * Fix typo * Add Iterator[T] + test * Simplify typing types * Class reduction * Fix tests * Test fix * Handle 'with' statement * Handle try-except * Class method inheritance + NewType * Container types * Containers test * Tests * Handle generic type alias * Named tuple * Global/non-local * Handle tuples in for Handle custom iterators * Basic generator * Any/AnyStr * Test fixes * Type/Optional/etc handling * Proper doc population * Tests + range * Argument match * Basic argset and diagnostics * Argset tests * Exclude WIP * Exclude WIP * Arg eval * Arg match, part 2 * Tests and generic arg comparisons * Function eval with arguments * Baselines * Fix test * Undo AST formatting change and update baseline * LS cleanup 1 * Fix list ctor argument unpacking * Cleanup 2 * Builds * Partial completions * Partial * Partial * Simple test * Tests * Basic startup * Clean up a bit * Remove debug code * Port formatter tests * Fix tokenizer crash * Async fixes * Hover * Basic hover * Adjust expression options * Basic signature help * Fix class/instance * Update test * Fix builtin creation exception * Fix tests * Actually provide declared module * Completion test (partial) * Undo * Fix null await Fix override completions + test * Exports filtering Prevent augmenting imported types * Filter variables & exports * Ported tests * Test fixes * More ported tests * Fix exception completions * Import completions * Scope completions * With completions * Test fixes * WIP * Test fix * Better arg match * Temp disable WIP * First cut * Fix type leak * WIP * Remove ConfigureAwait and handle canceled and failed in the analysis notifications * WIP * Generic class base * Generic forward reference resolution * Suppress completion in strings + test * Prevent recursion on generic resolution Better match arguments * Handle call expression in generics * Relax condition as it happens in tensorflow * Fix typeshed version search Make writing cached modules async Fix module doc fetching * Hover tests * Fix prom import hover * Hover tests * Synchronize test cache writing * First cut * Test * Fixes * Add tests for os.path Null ref fix * Fix cache check * Improve resolution of builtins and typing in stubs * Merge tests * Add ntst for requests * Handle typeshed better * Fix custom stub handling * Better sync * Move files * Fix parameter locations * Hover improvement * PEP hints * One more test for PEP hints * Better handle hover over import as * Text based generic constraints * Handle with better with generic stubs * Undo debug * Handle non-binary open() Temporary fix 'with' handler since we haven't specialized IO/TextIO/BinaryIO yet. * Output syntax errors * Properly clear * - Fix async issue with analysis completion - Clean up diagnostics service interface - Use real DS in tests * Use proper scope when analyzing module * Severity mapping and reporting * Add publishing test Add NSubstitute Move all services to the same namespace. * Unused var * Test forced publish on close * Fix typo * Update test framework * Import location * Remove incorrect reference * Diagnostic severity mapping test Fix post-mortem earlier PR comment * Minor fixes * Move interface to the main class part * Flicker reduction * De-duplicate completions * Fix os.path in typeshed
1 parent 037d248 commit 75e14ab

File tree

7 files changed

+34
-35
lines changed

7 files changed

+34
-35
lines changed

src/Analysis/Ast/Impl/Analyzer/Handlers/FromImportHandler.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,8 @@ public async Task<bool> HandleFromImportAsync(FromImportStatement node, Cancella
4242

4343
var imports = ModuleResolution.CurrentPathResolver.FindImports(Module.FilePath, node);
4444
switch (imports) {
45-
case ModuleImport moduleImport when moduleImport.FullName == Module.Name && Module.ModuleType == ModuleType.Stub:
46-
// If we are processing stub, ignore imports of the original module.
47-
// For example, typeshed stub for 'sys' imports sys.
48-
break;
4945
case ModuleImport moduleImport when moduleImport.FullName == Module.Name:
50-
ImportMembersFromSelf(node);
46+
await ImportMembersFromSelfAsync(node, cancellationToken);
5147
break;
5248
case ModuleImport moduleImport:
5349
await ImportMembersFromModuleAsync(node, moduleImport.FullName, cancellationToken);
@@ -65,7 +61,7 @@ public async Task<bool> HandleFromImportAsync(FromImportStatement node, Cancella
6561
return false;
6662
}
6763

68-
private void ImportMembersFromSelf(FromImportStatement node) {
64+
private async Task ImportMembersFromSelfAsync(FromImportStatement node, CancellationToken cancellationToken = default) {
6965
var names = node.Names;
7066
var asNames = node.AsNames;
7167

@@ -84,6 +80,14 @@ private void ImportMembersFromSelf(FromImportStatement node) {
8480
var memberName = memberReference.Name;
8581

8682
var member = Module.GetMember(importName);
83+
if (member == null && Eval.Module == Module) {
84+
// We are still evaluating this module so members are not complete yet.
85+
// Consider 'from . import path as path' in os.pyi in typeshed.
86+
var import = ModuleResolution.CurrentPathResolver.GetModuleImportFromModuleName($"{Module.Name}.{importName}");
87+
if (!string.IsNullOrEmpty(import?.FullName)) {
88+
member = await ModuleResolution.ImportModuleAsync(import.FullName, cancellationToken);
89+
}
90+
}
8791
Eval.DeclareVariable(memberName, member ?? Eval.UnknownType, VariableSource.Declaration, Eval.GetLoc(names[i]));
8892
}
8993
}

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,14 @@ private PathResolverSnapshot(PythonLanguageVersion pythonLanguageVersion, string
7171
public IEnumerable<string> GetAllModuleNames() => GetModuleNames(_roots.Prepend(_nonRooted).Append(_builtins));
7272
public IEnumerable<string> GetInterpreterModuleNames() => GetModuleNames(_roots.Skip(_userRootsCount).Append(_builtins));
7373

74-
private static IEnumerable<string> GetModuleNames(IEnumerable<Node> roots) => roots
75-
.SelectMany(r => r.TraverseBreadthFirst(n => n.IsModule ? Enumerable.Empty<Node>() : n.Children))
76-
.Where(n => n.IsModule)
74+
private IEnumerable<string> GetModuleNames(IEnumerable<Node> roots) {
75+
var builtins = new HashSet<Node>(_builtins.Children);
76+
return roots.SelectMany(r => r.TraverseBreadthFirst(n => n.IsModule? Enumerable.Empty<Node>() : n.Children))
77+
.Where(n => n.IsModule || builtins.Contains(n))
7778
.Select(n => n.FullModuleName);
79+
}
7880

79-
public ModuleImport GetModuleImportFromModuleName(in string fullModuleName) {
81+
public ModuleImport GetModuleImportFromModuleName(in string fullModuleName) {
8082
foreach (var root in _roots) {
8183
var node = root;
8284
var matched = true;

src/LanguageServer/Impl/Completion/CompletionSource.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,11 @@ public async Task<CompletionResult> GetCompletionsAsync(IDocumentAnalysis analys
3838
switch (expression) {
3939
case MemberExpression me when me.Target != null && me.DotIndex > me.StartIndex && context.Position > me.DotIndex:
4040
return new CompletionResult(await ExpressionCompletion.GetCompletionsFromMembersAsync(me.Target, scope, context, cancellationToken));
41-
case ConstantExpression ce when ce.Value is double || ce.Value is float:
41+
case ConstantExpression ce1 when ce1.Value is double || ce1.Value is float:
4242
// no completions on integer ., the user is typing a float
43-
return CompletionResult.Empty;
44-
case ConstantExpression ce when ce.Value is string:
43+
case ConstantExpression ce2 when ce2.Value is string:
4544
// no completions in strings
46-
return CompletionResult.Empty;
4745
case null when context.Ast.IsInsideComment(context.Location):
48-
return CompletionResult.Empty;
4946
case null when context.Ast.IsInsideString(context.Location):
5047
return CompletionResult.Empty;
5148
}

src/LanguageServer/Impl/Completion/ImportCompletion.cs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,8 @@ public static CompletionResult GetCompletionsInFromImport(FromImportStatement fr
116116
}
117117

118118
private static IEnumerable<CompletionItem> GetImportsFromModuleName(IEnumerable<NameExpression> nameExpressions, CompletionContext context) {
119-
IReadOnlyList<CompletionItem> items;
120119
var names = nameExpressions.TakeWhile(n => n.StartIndex <= context.Position).Select(n => n.Name).ToArray();
121-
if (names.Length <= 1) {
122-
var mres = context.Analysis.Document.Interpreter.ModuleResolution;
123-
var importable = mres.CurrentPathResolver.GetAllModuleNames();
124-
items = importable.Select(m => CompletionItemSource.CreateCompletionItem(m, CompletionItemKind.Module)).ToArray();
125-
} else {
126-
items = GetChildModules(names, context);
127-
}
128-
return items;
120+
return names.Length <= 1 ? GetAllImportableModules(context) : GetChildModules(names, context);
129121
}
130122

131123
private static IEnumerable<CompletionItem> GetModuleMembers(IEnumerable<NameExpression> nameExpressions, CompletionContext context) {
@@ -140,7 +132,7 @@ private static IEnumerable<CompletionItem> GetModuleMembers(IEnumerable<NameExpr
140132

141133
private static IEnumerable<CompletionItem> GetAllImportableModules(CompletionContext context) {
142134
var mres = context.Analysis.Document.Interpreter.ModuleResolution;
143-
var modules = mres.CurrentPathResolver.GetAllModuleNames();
135+
var modules = mres.CurrentPathResolver.GetAllModuleNames().Distinct();
144136
return modules.Select(n => CompletionItemSource.CreateCompletionItem(n, CompletionItemKind.Module));
145137
}
146138

src/LanguageServer/Impl/Implementation/Server.Editor.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,6 @@ public async Task<CompletionList> Completion(CompletionParams @params, Cancellat
4444
return res;
4545
}
4646

47-
public Task<CompletionItem> CompletionItemResolve(CompletionItem item, CancellationToken token) {
48-
// TODO: Fill out missing values in item
49-
return Task.FromResult(item);
50-
}
51-
5247
public async Task<Hover> Hover(TextDocumentPositionParams @params, CancellationToken cancellationToken) {
5348
var uri = @params.textDocument.uri;
5449
_log?.Log(TraceEventType.Verbose, $"Hover in {uri} at {@params.position}");

src/LanguageServer/Impl/LanguageServer.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,10 +238,6 @@ public async Task<CompletionList> Completion(JToken token, CancellationToken can
238238
return await _server.Completion(ToObject<CompletionParams>(token), GetToken(cancellationToken));
239239
}
240240

241-
[JsonRpcMethod("completionItem/resolve")]
242-
public Task<CompletionItem> CompletionItemResolve(JToken token, CancellationToken cancellationToken)
243-
=> _server.CompletionItemResolve(ToObject<CompletionItem>(token), GetToken(cancellationToken));
244-
245241
[JsonRpcMethod("textDocument/hover")]
246242
public async Task<Hover> Hover(JToken token, CancellationToken cancellationToken) {
247243
await _prioritizer.DefaultPriorityAsync(cancellationToken);

src/LanguageServer/Test/CompletionTests.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
using System.Linq;
1818
using System.Threading.Tasks;
1919
using FluentAssertions;
20+
using FluentAssertions.Common;
2021
using Microsoft.Python.Analysis.Types;
22+
using Microsoft.Python.Core;
2123
using Microsoft.Python.Core.Text;
2224
using Microsoft.Python.LanguageServer.Completion;
2325
using Microsoft.Python.LanguageServer.Protocol;
@@ -791,7 +793,7 @@ import os
791793
result.Should().HaveLabels("path", @"devnull", "SEEK_SET", @"curdir");
792794
}
793795

794-
[DataRow(false), Ignore("https://github.com/Microsoft/python-language-server/issues/574")]
796+
[DataRow(false)]
795797
[DataRow(true)]
796798
[DataTestMethod, Priority(0)]
797799
public async Task OsPathMembers(bool is3x) {
@@ -805,5 +807,16 @@ import os
805807
var result = await cs.GetCompletionsAsync(analysis, new SourceLocation(3, 9));
806808
result.Should().HaveLabels("split", @"getsize", @"islink", @"abspath");
807809
}
810+
811+
[TestMethod, Priority(0)]
812+
public async Task NoDuplicateMembers() {
813+
const string code = @"import sy";
814+
var analysis = await GetAnalysisAsync(code);
815+
var cs = new CompletionSource(new PlainTextDocumentationSource(), ServerSettings.completion);
816+
817+
var result = await cs.GetCompletionsAsync(analysis, new SourceLocation(1, 10));
818+
result.Completions.Count(c => c.label.EqualsOrdinal(@"sys")).Should().Be(1);
819+
result.Completions.Count(c => c.label.EqualsOrdinal(@"sysconfig")).Should().Be(1);
820+
}
808821
}
809822
}

0 commit comments

Comments
 (0)