private void Parse(bool enqueueOnly, CancellationToken cancel) { PythonAst tree; IAnalysisCookie cookie; GetTreeAndCookie(out tree, out cookie); if (tree == null) { return; } var oldParent = _myScope.ParentPackage; if (_filePath != null) { ProjectState.ModulesByFilename[_filePath] = _myScope; } if (oldParent != null) { // update us in our parent package oldParent.AddChildPackage(_myScope, _unit); } else if (_filePath != null) { // we need to check and see if our parent is a package for the case where we're adding a new // file but not re-analyzing our parent package. string parentFilename; if (ModulePath.IsInitPyFile(_filePath)) { // subpackage parentFilename = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(_filePath)), "__init__.py"); } else { // just a module parentFilename = Path.Combine(Path.GetDirectoryName(_filePath), "__init__.py"); } ModuleInfo parentPackage; if (ProjectState.ModulesByFilename.TryGetValue(parentFilename, out parentPackage)) { parentPackage.AddChildPackage(_myScope, _unit); } } _unit = new AnalysisUnit(tree, _myScope.Scope); AnalysisLog.NewUnit(_unit); foreach (var value in MyScope.Scope.AllVariables) { value.Value.EnqueueDependents(); } MyScope.Scope.Children.Clear(); MyScope.Scope.ClearNodeScopes(); MyScope.Scope.ClearNodeValues(); MyScope.ClearUnresolvedModules(); // collect top-level definitions first var walker = new OverviewWalker(this, _unit, tree); tree.Walk(walker); _myScope.Specialize(); // It may be that we have analyzed some child packages of this package already, but because it wasn't analyzed, // the children were not registered. To handle this possibility, scan analyzed packages for children of this // package (checked by module name first, then sanity-checked by path), and register any that match. if (ModulePath.IsInitPyFile(_filePath)) { string pathPrefix = Path.GetDirectoryName(_filePath) + "\\"; var children = from pair in _projectState.ModulesByFilename // Is the candidate child package in a subdirectory of our package? let fileName = pair.Key where fileName.StartsWith(pathPrefix) let moduleName = pair.Value.Name // Is the full name of the candidate child package qualified with the name of our package? let lastDot = moduleName.LastIndexOf('.') where lastDot > 0 let parentModuleName = moduleName.Substring(0, lastDot) where parentModuleName == _myScope.Name select pair.Value; foreach (var child in children) { _myScope.AddChildPackage(child, _unit); } } _unit.Enqueue(); if (!enqueueOnly) { _projectState.AnalyzeQueuedEntries(cancel); } // publish the analysis now that it's complete/running _currentAnalysis = new ModuleAnalysis( _unit, ((ModuleScope)_unit.Scope).CloneForPublish() ); }
private void Parse(bool enqueueOnly, CancellationToken cancel) { #if DEBUG Debug.Assert(Monitor.IsEntered(this)); #endif var parse = GetCurrentParse(); var tree = parse?.Tree; var cookie = parse?.Cookie; if (tree == null) { return; } var oldParent = MyScope.ParentPackage; if (FilePath != null) { ProjectState.ModulesByFilename[FilePath] = MyScope; } if (oldParent != null) { // update us in our parent package oldParent.AddChildPackage(MyScope, _unit); } else if (FilePath != null) { // we need to check and see if our parent is a package for the case where we're adding a new // file but not re-analyzing our parent package. string parentFilename; if (ModulePath.IsInitPyFile(FilePath)) { // subpackage parentFilename = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(FilePath)), "__init__.py"); } else { // just a module parentFilename = Path.Combine(Path.GetDirectoryName(FilePath), "__init__.py"); } if (ProjectState.ModulesByFilename.TryGetValue(parentFilename, out var parentPackage)) { parentPackage.AddChildPackage(MyScope, _unit); } } _unit = new AnalysisUnit(tree, MyScope.Scope); AnalysisLog.NewUnit(_unit); MyScope.Scope.Children = new List <InterpreterScope>(); MyScope.Scope.ClearNodeScopes(); MyScope.Scope.ClearNodeValues(); MyScope.Scope.ClearLinkedVariables(); MyScope.Scope.ClearVariables(); MyScope.ClearReferencedModules(); MyScope.ClearUnresolvedModules(); _unit.State.ClearDiagnostics(this); MyScope.EnsureModuleVariables(_unit.State); foreach (var value in MyScope.Scope.AllVariables) { value.Value.EnqueueDependents(); } // collect top-level definitions first var walker = new OverviewWalker(this, _unit, tree); tree.Walk(walker); MyScope.Specialize(); // It may be that we have analyzed some child packages of this package already, but because it wasn't analyzed, // the children were not registered. To handle this possibility, scan analyzed packages for children of this // package (checked by module name first, then sanity-checked by path), and register any that match. if (ModulePath.IsInitPyFile(FilePath)) { string pathPrefix = PathUtils.EnsureEndSeparator(Path.GetDirectoryName(FilePath)); var children = from pair in ProjectState.ModulesByFilename // Is the candidate child package in a subdirectory of our package? let fileName = pair.Key where fileName.StartsWithOrdinal(pathPrefix, ignoreCase: true) let moduleName = pair.Value.Name // Is the full name of the candidate child package qualified with the name of our package? let lastDot = moduleName.LastIndexOf('.') where lastDot > 0 let parentModuleName = moduleName.Substring(0, lastDot) where parentModuleName == MyScope.Name select pair.Value; foreach (var child in children) { MyScope.AddChildPackage(child, _unit); } } _unit.Enqueue(); if (!enqueueOnly) { ProjectState.AnalyzeQueuedEntries(cancel); } // publish the analysis now that it's complete/running Analysis = new ModuleAnalysis( _unit, ((ModuleScope)_unit.Scope).CloneForPublish(), DocumentUri, AnalysisVersion ); }
/// <summary> /// Returns a sequence of candidate absolute module names for the given /// modules. /// </summary> /// <param name="projectEntry"> /// The project entry that is importing the module. /// </param> /// <param name="relativeModuleName"> /// A dotted name identifying the path to the module. /// </param> /// <returns> /// A sequence of strings representing the absolute names of the module /// in order of precedence. /// </returns> internal static IEnumerable <string> ResolvePotentialModuleNames( IPythonProjectEntry projectEntry, string relativeModuleName, bool absoluteImports ) { string importingFrom = null; if (projectEntry != null) { importingFrom = projectEntry.ModuleName; if (ModulePath.IsInitPyFile(projectEntry.FilePath)) { if (string.IsNullOrEmpty(importingFrom)) { importingFrom = "__init__"; } else { importingFrom += ".__init__"; } } } if (string.IsNullOrEmpty(relativeModuleName)) { yield break; } // Handle relative module names if (relativeModuleName.FirstOrDefault() == '.') { if (string.IsNullOrEmpty(importingFrom)) { // No source to import relative to. yield break; } var prefix = importingFrom.Split('.'); if (relativeModuleName.LastOrDefault() == '.') { // Last part empty means the whole name is dots, so there's // nothing to concatenate. yield return(string.Join(".", prefix.Take(prefix.Length - relativeModuleName.Length))); } else { var suffix = relativeModuleName.Split('.'); var dotCount = suffix.TakeWhile(bit => string.IsNullOrEmpty(bit)).Count(); if (dotCount < prefix.Length) { // If we have as many dots as prefix parts, the entire // name will disappear. Despite what PEP 328 says, in // reality this means the import will fail. yield return(string.Join(".", prefix.Take(prefix.Length - dotCount).Concat(suffix.Skip(dotCount)))); } } yield break; } // The two possible names that can be imported here are: // * relativeModuleName // * importingFrom.relativeModuleName // and the order they are returned depends on whether // absolute_import is enabled or not. // With absolute_import, we treat the name as complete first. if (absoluteImports) { yield return(relativeModuleName); } if (!string.IsNullOrEmpty(importingFrom)) { var prefix = importingFrom.Split('.'); if (prefix.Length > 1) { var adjacentModuleName = string.Join(".", prefix.Take(prefix.Length - 1)) + "." + relativeModuleName; yield return(adjacentModuleName); } } // Without absolute_import, we treat the name as complete last. if (!absoluteImports) { yield return(relativeModuleName); } }
/// <summary> /// Returns a sequence of candidate absolute module names for the given /// modules. /// </summary> /// <param name="importingFromModuleName"> /// The module that is importing the module. /// </param> /// <param name="importingFromFilePath"> /// The path to the file that is importing the module. /// </param> /// <param name="relativeModuleName"> /// A dotted name identifying the path to the module. /// </param> /// <returns> /// A sequence of strings representing the absolute names of the module /// in order of precedence. /// </returns> internal static IEnumerable <string> ResolvePotentialModuleNames( string importingFromModuleName, string importingFromFilePath, string relativeModuleName, bool absoluteImports ) { string importingFrom = string.Empty; if (!string.IsNullOrEmpty(importingFromModuleName)) { importingFrom = importingFromModuleName; if (!string.IsNullOrEmpty(importingFromFilePath) && ModulePath.IsInitPyFile(importingFromFilePath)) { if (string.IsNullOrEmpty(importingFrom)) { importingFrom = "__init__"; } else { importingFrom += ".__init__"; } } } if (string.IsNullOrEmpty(relativeModuleName)) { yield break; } // Handle relative module names if (relativeModuleName.FirstOrDefault() == '.') { var fullName = GetModuleFullName(importingFrom, relativeModuleName); if (!fullName.StartsWithOrdinal(".") && !fullName.EndsWithOrdinal(".")) { yield return(fullName); } yield break; } // The two possible names that can be imported here are: // * relativeModuleName // * importingFrom.relativeModuleName // and the order they are returned depends on whether // absolute_import is enabled or not. // Assume trailing dots are not part of the import relativeModuleName = relativeModuleName.TrimEnd('.'); // With absolute_import, we treat the name as complete first. if (absoluteImports) { yield return(relativeModuleName); } if (!string.IsNullOrEmpty(importingFrom)) { var prefix = importingFrom.Split('.'); if (prefix.Length > 1) { var adjacentModuleName = string.Join(".", prefix.Take(prefix.Length - 1)) + "." + relativeModuleName; yield return(adjacentModuleName); } } // Without absolute_import, we treat the name as complete last. if (!absoluteImports) { yield return(relativeModuleName); } }