Skip to content

Commit ad249aa

Browse files
committed
- Address CR comments
- Fixed namespace package resolution in completions (microsoft#12) - Fixed support for sys.modules (microsoft#363) - Added several tests (microsoft#365) - Fixed support for implicit relative module names (microsoft#366) - Added support for multiple matching rules in PathResolver (microsoft#367) Not yet implemented: - Fix imports of binary modules (microsoft#362) - Fix stubs handling - AstAnalysisWalker - More tests - Code cleanup
1 parent fa5479f commit ad249aa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1645
-1343
lines changed

src/Analysis/Engine/Impl/Analyzer/DDG.cs

Lines changed: 104 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -334,46 +334,38 @@ private void SetVariableForImportedMember(IModule module, NameExpression importN
334334
}
335335

336336
public override bool Walk(FromImportStatement node) {
337-
var rootNames = node.Root.Names.Select(n => n.Name);
338-
var availableImports = node.Root is RelativeModuleName relativeName
339-
? _pathResolver.GetAvailableImportsFromRelativePath(_filePath, relativeName.DotCount, rootNames)
340-
: _pathResolver.GetAvailableImportsFromAbsolutePath(_filePath, rootNames);
341-
342-
switch (availableImports) {
343-
case AvailableModuleImports moduleImports:
344-
ImportMembersFromModule(node, moduleImports);
337+
var importSearchResult = _pathResolver.FindImports(_filePath, node);
338+
339+
switch (importSearchResult) {
340+
case ModuleImport moduleImports when TryGetModule(node.Root, moduleImports, out var module):
341+
case PossibleModuleImport possibleModuleImport when TryGetModule(node.Root, possibleModuleImport, out module):
342+
ImportMembersFromModule(node, module);
345343
return false;
346-
case AvailablePackageImports packageImports:
344+
case PackageImport packageImports:
347345
ImportModulesFromPackage(node, packageImports);
348346
return false;
347+
case ImportNotFound notFound:
348+
MakeUnresolvedImport(notFound.FullName, node.Root);
349+
return false;
349350
default:
350-
_unit.DeclaringModule.AddUnresolvedModule(node.Root.MakeString(), node.ForceAbsolute);
351351
return false;
352352
}
353353
}
354354

355-
private void ImportMembersFromModule(FromImportStatement node, AvailableModuleImports moduleImports) {
356-
if (!ProjectState.Modules.TryImport(moduleImports.FullName, out var moduleReference)) {
357-
return;
358-
}
359-
360-
_unit.DeclaringModule.AddModuleReference(moduleImports.FullName, moduleReference);
361-
var module = moduleReference.Module;
362-
module.Imported(_unit);
363-
364-
if (node.Names.Count == 1 && node.Names[0].Name == "*") {
355+
private void ImportMembersFromModule(FromImportStatement node, IModule module) {
356+
var names = node.Names;
357+
if (names.Count == 1 && names[0].Name == "*") {
365358
// import all module public members
366-
var publicMembers = moduleReference.Module
359+
var publicMembers = module
367360
.GetModuleMemberNames(GlobalScope.InterpreterContext)
368361
.Where(n => !n.StartsWithOrdinal("_"));
369362
foreach (var member in publicMembers) {
370363
// Don't add references to "*" node
371-
SetVariableForImportedMember(module, node.Names[0], member, null, member, false);
364+
SetVariableForImportedMember(module, names[0], member, null, member, false);
372365
}
373366
return;
374367
}
375368

376-
var names = node.Names;
377369
var asNames = node.AsNames;
378370

379371
var len = Math.Min(names.Count, asNames.Count);
@@ -390,23 +382,26 @@ private void ImportMembersFromModule(FromImportStatement node, AvailableModuleIm
390382
}
391383
}
392384

393-
private void ImportModulesFromPackage(FromImportStatement node, AvailablePackageImports packageImports) {
385+
private void ImportModulesFromPackage(FromImportStatement node, PackageImport packageImport) {
394386
var names = node.Names;
395387
var asNames = node.AsNames;
396388

397389
var importNames = names.Select(n => n.Name).ToArray();
398390
if (importNames.Length == 1 && importNames[0] == "*") {
399391
// TODO: Need tracking of previous imports to determine possible imports for namespace package
392+
MakeUnresolvedImport(packageImport.Name, node.Root);
400393
return;
401394
}
402395

403-
foreach (var module in packageImports.Modules) {
396+
foreach (var module in packageImport.Modules) {
404397
var index = importNames.IndexOf(module.Name, StringExtensions.EqualsOrdinal);
405398
if (index == -1) {
399+
MakeUnresolvedImport(module.FullName, node.Root);
406400
continue;
407401
}
408402

409403
if (!ProjectState.Modules.TryImport(module.FullName, out var moduleReference)) {
404+
MakeUnresolvedImport(module.FullName, node.Root);
410405
continue;
411406
}
412407

@@ -498,48 +493,108 @@ public override bool Walk(IfStatement node) {
498493
public override bool Walk(ImportStatement node) {
499494
var len = Math.Min(node.Names.Count, node.AsNames.Count);
500495
for (var i = 0; i < len; i++) {
501-
var curName = node.Names[i];
502-
var asName = node.AsNames[i];
503-
504-
var imports = _pathResolver.GetAvailableImportsFromAbsolutePath(_filePath, curName.Names.Select(n => n.Name));
505-
if (!(imports is AvailableModuleImports moduleImports)) {
506-
continue;
496+
var moduleImportExpression = node.Names[i];
497+
var asNameExpression = node.AsNames[i];
498+
499+
var imports = _pathResolver.GetImportsFromAbsoluteName(_filePath, moduleImportExpression.Names.Select(n => n.Name), node.ForceAbsolute);
500+
switch (imports) {
501+
case ModuleImport moduleImports when TryGetModule(moduleImportExpression, moduleImports, out var module):
502+
case PossibleModuleImport possibleModuleImport when TryGetModule(moduleImportExpression, possibleModuleImport, out module):
503+
ImportModule(node, module, moduleImportExpression, asNameExpression);
504+
break;
505+
default:
506+
MakeUnresolvedImport(moduleImportExpression.MakeString(), moduleImportExpression);
507+
break;
507508
}
508-
509-
ImportModule(node, moduleImports, curName, asName);
510509
}
511510
return true;
512511
}
513512

514-
private void ImportModule(ImportStatement node, AvailableModuleImports moduleImports, DottedName moduleImportExpression, NameExpression asNameExpression) {
515-
if (!ProjectState.Modules.TryImport(moduleImports.FullName, out var moduleReference)) {
516-
return;
517-
}
518-
519-
_unit.DeclaringModule.AddModuleReference(moduleImports.FullName, moduleReference);
520-
var module = moduleReference.Module;
521-
module.Imported(_unit);
513+
private void MakeUnresolvedImport(string name, Node spanNode) {
514+
_unit.DeclaringModule.AddUnresolvedModule(name);
515+
ProjectState.AddDiagnostic(spanNode, _unit, ErrorMessages.UnresolvedImport(name), DiagnosticSeverity.Warning, ErrorMessages.UnresolvedImportCode);
516+
}
522517

518+
private void ImportModule(in ImportStatement node, in IModule module, in DottedName moduleImportExpression, in NameExpression asNameExpression) {
523519
// "import fob.oar as baz" is handled as
524520
// baz = import_module('fob.oar')
525521
if (asNameExpression != null) {
526-
AssignImportedModuleOrMember(asNameExpression.Name, moduleReference.AnalysisModule, true, node.Names.LastOrDefault(), asNameExpression);
522+
AssignImportedModuleOrMember(asNameExpression.Name, module, true, node.Names.LastOrDefault(), asNameExpression);
527523
return;
528524
}
529525

530526
// "import fob.oar" is handled as
531527
// import_module('fob.oar')
532528
// fob = import_module('fob')
533-
var firstImportNameExpression = moduleImportExpression.Names[0];
529+
var importNames = moduleImportExpression.Names;
530+
531+
var existingDepth = 0;
532+
PythonPackage pythonPackage = null;
533+
if (Scope.TryGetVariable(importNames[0].Name, out var importVariable)) {
534+
var childPackage = importVariable.Types.OfType<PythonPackage>().FirstOrDefault();
535+
while (childPackage != null && existingDepth < importNames.Count - 1) {
536+
existingDepth++;
537+
pythonPackage = childPackage;
538+
childPackage = pythonPackage.GetChildPackage(null, importNames[existingDepth].Name) as PythonPackage;
539+
}
540+
}
534541

535-
// Should be able to just get the module, as we only just imported it
536-
if (!ProjectState.Modules.TryGetImportedModule(firstImportNameExpression.Name, out moduleReference)) {
537-
Debug.Fail($"Failed to get module {firstImportNameExpression.Name} we just imported");
538-
Scope.CreateEphemeralVariable(firstImportNameExpression, _unit, firstImportNameExpression.Name, true);
539-
return;
542+
var child = module;
543+
for (var i = importNames.Count - 2; i >= existingDepth; i--) {
544+
var childName = importNames[i + 1].Name;
545+
var parentName = importNames[i].Name;
546+
var parent = new PythonPackage(parentName, ProjectState);
547+
parent.AddChildModule(childName, child);
548+
child = parent;
540549
}
541550

542-
AssignImportedModuleOrMember(firstImportNameExpression.Name, moduleReference.AnalysisModule, true, firstImportNameExpression, null);
551+
if (pythonPackage == null) {
552+
AssignImportedModuleOrMember(importNames[0].Name, child, true, importNames[0], null);
553+
} else {
554+
pythonPackage.AddChildModule(importNames[existingDepth].Name, child);
555+
}
556+
}
557+
558+
private bool TryGetModule(Node importNode, ModuleImport moduleImport, out IModule module) {
559+
var fullName = moduleImport.FullName;
560+
if (!ProjectState.Modules.TryImport(fullName, out var moduleReference)) {
561+
MakeUnresolvedImport(fullName, importNode);
562+
module = default;
563+
return false;
564+
}
565+
566+
_unit.DeclaringModule.AddModuleReference(fullName, moduleReference);
567+
module = moduleReference.Module;
568+
module.Imported(_unit);
569+
return true;
570+
}
571+
572+
private bool TryGetModule(Node importNode, PossibleModuleImport possibleModuleImport, out IModule module) {
573+
var fullName = possibleModuleImport.PrecedingModuleFullName;
574+
if (!ProjectState.Modules.TryImport(fullName, out var moduleReference)) {
575+
MakeUnresolvedImport(fullName, importNode);
576+
module = default;
577+
return false;
578+
}
579+
580+
_unit.DeclaringModule.AddModuleReference(fullName, moduleReference);
581+
module = moduleReference.Module;
582+
module.Imported(_unit);
583+
584+
var nameParts = possibleModuleImport.RemainingNameParts;
585+
for (var i = 0; i < nameParts.Count; i++) {
586+
var namePart = nameParts[i];
587+
if (!module.Scope.TryGetVariable(namePart, out var variable) || !variable.Types.OfType<IModule>().Any()) {
588+
var unresolvedModuleName = string.Join(".", nameParts.Take(i + 1).Prepend(fullName));
589+
MakeUnresolvedImport(unresolvedModuleName, importNode);
590+
return false;
591+
}
592+
593+
module = variable.Types.OfType<IModule>().First();
594+
module.Imported(_unit);
595+
}
596+
597+
return true;
543598
}
544599

545600
public override bool Walk(ReturnStatement node) {

src/Analysis/Engine/Impl/Analyzer/ImportStatementWalker.cs

Lines changed: 0 additions & 112 deletions
This file was deleted.

src/Analysis/Engine/Impl/Analyzer/ModuleScope.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
namespace Microsoft.PythonTools.Analysis.Analyzer {
2020
sealed class ModuleScope : InterpreterScope, IModuleScope {
21-
2221
public ModuleScope(ModuleInfo moduleInfo)
2322
: base(moduleInfo, null) {
2423
}

src/Analysis/Engine/Impl/Definitions/IPythonAnalyzer.cs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -67,25 +67,6 @@ public interface IPythonAnalyzer: IGroupableAnalysisProject {
6767

6868
AnalysisValue GetAnalysisValueFromObjects(object attr);
6969

70-
/// <summary>
71-
/// Returns true if a module has been imported.
72-
/// </summary>
73-
/// <param name="importFrom">
74-
/// The entry of the module doing the import. If null, the module name
75-
/// is resolved as an absolute name.
76-
/// </param>
77-
/// <param name="relativeModuleName">
78-
/// The absolute or relative name of the module. If a relative name is
79-
/// passed here, <paramref name="importFrom"/> must be provided.
80-
/// </param>
81-
/// <param name="absoluteImports">
82-
/// True if Python 2.6/3.x style imports should be used.
83-
/// </param>
84-
/// <returns>
85-
/// True if the module was imported during analysis; otherwise, false.
86-
/// </returns>
87-
bool IsModuleResolved(IPythonProjectEntry importFrom, string relativeModuleName, bool absoluteImports);
88-
8970
/// <summary>
9071
/// Gets a top-level list of all the available modules as a list of MemberResults.
9172
/// </summary>

src/Analysis/Engine/Impl/Analyzer/ImportSource.cs renamed to src/Analysis/Engine/Impl/DependencyResolution/AstUtilities.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@
1414
// See the Apache Version 2.0 License for specific language governing
1515
// permissions and limitations under the License.
1616

17-
using System;
17+
using System.Linq;
1818
using Microsoft.PythonTools.Parsing.Ast;
1919

20-
namespace Microsoft.PythonTools.Analysis.Analyzer {
21-
public interface IImportSource {
22-
bool IsResolved { get; }
23-
}
24-
25-
public interface IImportDefinition {
26-
IImportSource Source { get; }
27-
IProjectEntry ProjectEntry { get; }
20+
namespace Microsoft.PythonTools.Analysis.DependencyResolution {
21+
internal static class AstUtilities {
22+
public static IImportSearchResult FindImports(this PathResolverSnapshot pathResolver, string modulePath, FromImportStatement fromImportStatement) {
23+
var rootNames = fromImportStatement.Root.Names.Select(n => n.Name);
24+
return fromImportStatement.Root is RelativeModuleName relativeName
25+
? pathResolver.GetImportsFromRelativePath(modulePath, relativeName.DotCount, rootNames)
26+
: pathResolver.GetImportsFromAbsoluteName(modulePath, rootNames, fromImportStatement.ForceAbsolute);
27+
}
2828
}
2929
}

0 commit comments

Comments
 (0)