/// <summary> /// Determines value of the variable and declares it. Value depends if source module has submodule /// that is named the same as the variable and/or it has internal variables named same as the submodule. /// </summary> /// <example>'from a.b import c' when 'c' is both submodule of 'b' and a variable declared inside 'b'.</example> /// <param name="variableModule">Source module of the variable such as 'a.b' in 'from a.b import c as d'.</param> /// <param name="memberName">Module member name such as 'c' in 'from a.b import c as d'.</param> /// <param name="imports">Import search result.</param> /// <param name="variableName">Name of the variable to declare, such as 'd' in 'from a.b import c as d'.</param> /// <param name="importPosition">Position of the import statement.</param> /// <param name="nameLocation">Location of the variable name expression.</param> private void DeclareVariable(PythonVariableModule variableModule, string memberName, IImportSearchResult imports, string variableName, int importPosition, Node nameLocation) { // First try imports since child modules should win, i.e. in 'from a.b import c' // 'c' should be a submodule if 'b' has one, even if 'b' also declares 'c = 1'. var value = GetValueFromImports(variableModule, imports as IImportChildrenSource, memberName); // First try exported or child submodules. value = value ?? variableModule.GetMember(memberName); // Value may be variable or submodule. If it is variable, we need it in order to add reference. var variable = variableModule.Analysis?.GlobalScope?.Variables[memberName]; value = variable?.Value?.Equals(value) == true ? variable : value; // If nothing is exported, variables are still accessible. value = value ?? variableModule.Analysis?.GlobalScope?.Variables[memberName]?.Value ?? Eval.UnknownType; // Do not allow imported variables to override local declarations var canOverwrite = CanOverwriteVariable(variableName, importPosition, value); // Do not declare references to '*' var locationExpression = nameLocation is NameExpression nex && nex.Name == "*" ? null : nameLocation; Eval.DeclareVariable(variableName, value, VariableSource.Import, locationExpression, canOverwrite); // Make sure module is loaded and analyzed. if (value is IPythonModule m) { ModuleResolution.GetOrLoadModule(m.Name); } }
private void HandleModuleImportStar(PythonVariableModule variableModule) { if (variableModule.Module == Module) { // from self import * won't define any new members return; } foreach (var memberName in variableModule.GetMemberNames()) { var member = variableModule.GetMember(memberName); if (member == null) { Log?.Log(TraceEventType.Verbose, $"Undefined import: {variableModule.Name}, {memberName}"); } else if (member.MemberType == PythonMemberType.Unknown) { Log?.Log(TraceEventType.Verbose, $"Unknown import: {variableModule.Name}, {memberName}"); } member = member ?? Eval.UnknownType; if (member is IPythonModule m) { ModuleResolution.GetOrLoadModule(m.Name); } Eval.DeclareVariable(memberName, member, VariableSource.Import, variableModule.Location); } }
private void HandleModuleImportStar(PythonVariableModule variableModule, bool isImplicitPackage) { if (variableModule.Module == Module) { // from self import * won't define any new members return; } // If __all__ is present, take it, otherwise declare all members from the module that do not begin with an underscore. var memberNames = isImplicitPackage ? variableModule.GetMemberNames() : variableModule.Analysis.StarImportMemberNames ?? variableModule.GetMemberNames().Where(s => !s.StartsWithOrdinal("_")); foreach (var memberName in memberNames) { var member = variableModule.GetMember(memberName); if (member == null) { Log?.Log(TraceEventType.Verbose, $"Undefined import: {variableModule.Name}, {memberName}"); } else if (member.MemberType == PythonMemberType.Unknown) { Log?.Log(TraceEventType.Verbose, $"Unknown import: {variableModule.Name}, {memberName}"); } member = member ?? Eval.UnknownType; if (member is IPythonModule m) { ModuleResolution.GetOrLoadModule(m.Name); } var variable = variableModule.Analysis?.GlobalScope?.Variables[memberName]; Eval.DeclareVariable(memberName, variable ?? member, VariableSource.Import); } }
private void HandleModuleImportStar(PythonVariableModule variableModule, IImportSearchResult imports, int importPosition, NameExpression nameExpression) { if (variableModule.Module == Module) { // from self import * won't define any new members return; } // If __all__ is present, take it, otherwise declare all members from the module that do not begin with an underscore. var memberNames = imports is ImplicitPackageImport ? variableModule.GetMemberNames() : variableModule.Analysis.StarImportMemberNames ?? variableModule.GetMemberNames().Where(s => !s.StartsWithOrdinal("_")); foreach (var memberName in memberNames) { DeclareVariable(variableModule, memberName, imports, memberName, importPosition, nameExpression); } }
/// <summary> /// Determines value of the variable and declares it. Value depends if source module has submodule /// that is named the same as the variable and/or it has internal variables named same as the submodule. /// </summary> /// <example>'from a.b import c' when 'c' is both submodule of 'b' and a variable declared inside 'b'.</example> /// <param name="variableModule">Source module of the variable such as 'a.b' in 'from a.b import c as d'. May be null if the module was not found.</param> /// <param name="memberName">Module member name such as 'c' in 'from a.b import c as d'.</param> /// <param name="imports">Import search result.</param> /// <param name="variableName">Name of the variable to declare, such as 'd' in 'from a.b import c as d'.</param> /// <param name="importPosition">Position of the import statement.</param> /// <param name="nameLocation">Location of the variable name expression.</param> private void DeclareVariable(PythonVariableModule variableModule, string memberName, IImportSearchResult imports, string variableName, int importPosition, Node nameLocation) { IMember value = Eval.UnknownType; if (variableModule != null) { // First try imports since child modules should win, i.e. in 'from a.b import c' // 'c' should be a submodule if 'b' has one, even if 'b' also declares 'c = 1'. value = GetValueFromImports(variableModule, imports as IImportChildrenSource, memberName); // First try exported or child submodules. var member = variableModule.GetMember(memberName); // Value may be variable or submodule. If it is variable, we need it in order to add reference. var variable = _importedVariableHandler.GetVariable(variableModule, memberName); if (member is PythonVariableModule vm && vm.Equals(variable?.Value)) { // If member is submodule, use actual variable so it can be linked through for goto definition. value = variable; } else if (value == null) { if (member is PythonVariableModule) { // If member is submodule, use it. value = member; } else if (variable?.Value != null) { // Otherwise use variable, if available so references can be linked. value = variable; } else if (member != null) { value = member; } else { value = Eval.UnknownType; } } }
private IMember GetValueFromImports(PythonVariableModule parentModule, IImportChildrenSource childrenSource, string memberName) { if (childrenSource == null || !childrenSource.TryGetChildImport(memberName, out var childImport)) { return(Interpreter.UnknownType); } switch (childImport) { case ModuleImport moduleImport: var module = ModuleResolution.GetOrLoadModule(moduleImport.FullName); return(module != null?GetOrCreateVariableModule(module, parentModule, moduleImport.Name) : Interpreter.UnknownType); case ImplicitPackageImport packageImport: return(GetOrCreateVariableModule(packageImport.FullName, parentModule, memberName)); default: return(Interpreter.UnknownType); } }
private void AssignVariables(FromImportStatement node, IImportSearchResult imports, PythonVariableModule variableModule) { if (variableModule == null) { return; } var names = node.Names; var asNames = node.AsNames; if (names.Count == 1 && names[0].Name == "*") { // TODO: warn this is not a good style per // TODO: https://docs.python.org/3/faq/programming.html#what-are-the-best-practices-for-using-import-in-a-module // TODO: warn this is invalid if not in the global scope. HandleModuleImportStar(variableModule, imports is ImplicitPackageImport, node.StartIndex); return; } for (var i = 0; i < names.Count; i++) { var memberName = names[i].Name; if (!string.IsNullOrEmpty(memberName)) { var nameExpression = asNames[i] ?? names[i]; var variableName = nameExpression?.Name ?? memberName; var variable = variableModule.Analysis?.GlobalScope?.Variables[memberName]; var exported = variable ?? variableModule.GetMember(memberName); var value = exported ?? GetValueFromImports(variableModule, imports as IImportChildrenSource, memberName); // Do not allow imported variables to override local declarations Eval.DeclareVariable(variableName, value, VariableSource.Import, nameExpression, CanOverwriteVariable(variableName, node.StartIndex)); } } }
private void AssignVariables(FromImportStatement node, IImportSearchResult imports, PythonVariableModule variableModule) { var names = node.Names; var asNames = node.AsNames; if (variableModule != null && names.Count == 1 && names[0].Name == "*") { // TODO: warn this is not a good style per // TODO: https://docs.python.org/3/faq/programming.html#what-are-the-best-practices-for-using-import-in-a-module // TODO: warn this is invalid if not in the global scope. HandleModuleImportStar(variableModule, imports, node.StartIndex, names[0]); return; } for (var i = 0; i < names.Count; i++) { var memberName = names[i].Name; if (string.IsNullOrEmpty(memberName)) { continue; } var nameExpression = asNames[i] ?? names[i]; var variableName = nameExpression?.Name ?? memberName; if (!string.IsNullOrEmpty(variableName)) { DeclareVariable(variableModule, memberName, imports, variableName, node.StartIndex, nameExpression); } if (imports is IImportChildrenSource cs && cs.TryGetChildImport(memberName, out var csr) && HandleImportSearchResult(csr, variableModule, null, names[i], out var childModule)) { _importedVariableHandler.EnsureModule(childModule); } } }
private void AssignVariables(FromImportStatement node, IImportSearchResult imports, PythonVariableModule variableModule) { if (variableModule == null) { return; } var names = node.Names; var asNames = node.AsNames; if (names.Count == 1 && names[0].Name == "*") { // TODO: warn this is not a good style per // TODO: https://docs.python.org/3/faq/programming.html#what-are-the-best-practices-for-using-import-in-a-module // TODO: warn this is invalid if not in the global scope. HandleModuleImportStar(variableModule, imports, node.StartIndex, names[0]); return; } for (var i = 0; i < names.Count; i++) { var memberName = names[i].Name; if (!string.IsNullOrEmpty(memberName)) { var nameExpression = asNames[i] ?? names[i]; var variableName = nameExpression?.Name ?? memberName; if (!string.IsNullOrEmpty(variableName)) { DeclareVariable(variableModule, memberName, imports, variableName, node.StartIndex, nameExpression); } } } }
private void AssignVariables(FromImportStatement node, IImportSearchResult imports, PythonVariableModule variableModule) { if (variableModule == null) { return; } var names = node.Names; var asNames = node.AsNames; if (names.Count == 1 && names[0].Name == "*") { // TODO: warn this is not a good style per // TODO: https://docs.python.org/3/faq/programming.html#what-are-the-best-practices-for-using-import-in-a-module // TODO: warn this is invalid if not in the global scope. HandleModuleImportStar(variableModule); return; } for (var i = 0; i < names.Count; i++) { var memberName = names[i].Name; if (!string.IsNullOrEmpty(memberName)) { var variableName = asNames[i]?.Name ?? memberName; var value = variableModule.GetMember(memberName) ?? GetValueFromImports(variableModule, imports as IImportChildrenSource, memberName); Eval.DeclareVariable(variableName, value, VariableSource.Import, names[i]); } } }
public IEnumerable <string> GetMemberNames(PythonVariableModule variableModule) => variableModule.Analysis.StarImportMemberNames ?? variableModule.GetMemberNames().Where(s => !s.StartsWithOrdinal("_"));