} // For de-serializer from JSON /// <summary> /// Constructs class model for persistence off the class in-memory type. /// </summary> public ClassModel(IPythonClassType cls, IServiceContainer services) { var methods = new List <FunctionModel>(); var properties = new List <PropertyModel>(); var fields = new List <VariableModel>(); var innerClasses = new List <ClassModel>(); // Skip certain members in order to avoid infinite recursion. foreach (var name in cls.GetMemberNames().Except(new[] { "__base__", "__bases__", "__class__", "mro" })) { var m = cls.GetMember(name); // Only take members from this class, skip members from bases. if (m is IPythonClassMember cm && cls.QualifiedName != cm.DeclaringType?.QualifiedName) { continue; } using (_processing.Push(m, out var reentered)) { if (reentered) { continue; } switch (m) { case IPythonClassType ct when ct.Name == name: if (!ct.DeclaringModule.Equals(cls.DeclaringModule)) { continue; } innerClasses.Add(new ClassModel(ct, services)); break; case IPythonFunctionType ft when ft.IsLambda(): break; case IPythonFunctionType ft when ft.Name == name: methods.Add(new FunctionModel(ft, services)); break; case IPythonPropertyType prop when prop.Name == name: properties.Add(new PropertyModel(prop, services)); break; case IPythonInstance inst: fields.Add(VariableModel.FromInstance(name, inst, services)); break; case IPythonType t: fields.Add(VariableModel.FromType(name, t, services)); break; } } } Name = cls.TypeId == BuiltinTypeId.Ellipsis ? "ellipsis" : cls.Name; Id = Name.GetStableHash(); DeclaringModuleId = cls.DeclaringModule.GetUniqueId(services); QualifiedName = cls.QualifiedName; IndexSpan = cls.Location.IndexSpan.ToModel(); Documentation = cls.Documentation; var ntBases = cls.Bases.MaybeEnumerate().OfType <ITypingNamedTupleType>().ToArray(); NamedTupleBases = ntBases.Select(b => new NamedTupleModel(b, services)).ToArray(); Bases = cls.Bases.MaybeEnumerate().Except(ntBases).Select(t => t.GetPersistentQualifiedName(services)).ToArray(); Methods = methods.ToArray(); Properties = properties.ToArray(); Fields = fields.ToArray(); Classes = innerClasses.ToArray(); if (cls.IsGeneric) { // Only check immediate bases, i.e. when class itself has Generic[T] base. var gcp = cls.Bases.OfType <IGenericClassBase>().FirstOrDefault(); GenericBaseParameters = gcp?.TypeParameters.Select(p => p.Name).ToArray(); } // If class is generic, we must save its generic base definition // so on restore we'll be able to re-create the class as generic. GenericBaseParameters = GenericBaseParameters ?? Array.Empty <string>(); GenericParameterValues = cls.GenericParameters .Select(p => new GenericParameterValueModel { Name = p.Key, Type = p.Value.GetPersistentQualifiedName(services) }) .ToArray(); }
public static ModuleModel FromAnalysis(IDocumentAnalysis analysis, IServiceContainer services, AnalysisCachingLevel options) { var uniqueId = analysis.Document.GetUniqueId(services, options); if (uniqueId == null) { // Caching level setting does not permit this module to be persisted. return(null); } var variables = new Dictionary <string, VariableModel>(); var functions = new Dictionary <string, FunctionModel>(); var classes = new Dictionary <string, ClassModel>(); var typeVars = new Dictionary <string, TypeVarModel>(); var namedTuples = new Dictionary <string, NamedTupleModel>(); // Go directly through variables which names are listed in GetMemberNames // as well as variables that are declarations. var exportedNames = new HashSet <string>(analysis.Document.GetMemberNames()); foreach (var v in analysis.GlobalScope.Variables .Where(v => exportedNames.Contains(v.Name) || v.Source == VariableSource.Declaration || v.Source == VariableSource.Builtin || v.Source == VariableSource.Generic)) { if (v.Value is IGenericTypeParameter && !typeVars.ContainsKey(v.Name)) { typeVars[v.Name] = TypeVarModel.FromGeneric(v); continue; } switch (v.Value) { case ITypingNamedTupleType nt: namedTuples[nt.Name] = new NamedTupleModel(nt); continue; case IPythonFunctionType ft when ft.IsLambda(): // No need to persist lambdas. continue; case IPythonFunctionType ft when v.Name != ft.Name: // Variable assigned to type info of the function like // def func(): ... // x = type(func) break; case IPythonFunctionType ft: var fm = GetFunctionModel(analysis, v, ft); if (fm != null && !functions.ContainsKey(ft.Name)) { functions[ft.Name] = fm; continue; } break; case IPythonClassType cls when v.Name != cls.Name: // Variable assigned to type info of the class. break; case IPythonClassType cls when cls.DeclaringModule.Equals(analysis.Document) || cls.DeclaringModule.Equals(analysis.Document.Stub): if (!classes.ContainsKey(cls.Name)) { classes[cls.Name] = new ClassModel(cls); continue; } break; } // Do not re-declare classes and functions as variables in the model. if (!variables.ContainsKey(v.Name)) { variables[v.Name] = VariableModel.FromVariable(v); } } // Take dependencies from imports. If module has stub we should also take // dependencies from there since persistent state is based on types that // are combination of stub and the module. Sometimes stub may import more // and we must make sure dependencies are restored before the module. var primaryDependencyWalker = new DependencyWalker(analysis.Ast); var stubDependencyWalker = analysis.Document.Stub != null ? new DependencyWalker(analysis.Document.Stub.Analysis.Ast) : null; var stubImports = stubDependencyWalker?.Imports ?? Enumerable.Empty <ImportModel>(); var stubFromImports = stubDependencyWalker?.FromImports ?? Enumerable.Empty <FromImportModel>(); return(new ModuleModel { Id = uniqueId.GetStableHash(), UniqueId = uniqueId, Name = analysis.Document.Name, QualifiedName = analysis.Document.QualifiedName, Documentation = analysis.Document.Documentation, Functions = functions.Values.ToArray(), Variables = variables.Values.ToArray(), Classes = classes.Values.ToArray(), TypeVars = typeVars.Values.ToArray(), NamedTuples = namedTuples.Values.ToArray(), NewLines = analysis.Ast.NewLineLocations.Select(l => new NewLineModel { EndIndex = l.EndIndex, Kind = l.Kind }).ToArray(), FileSize = analysis.Ast.EndIndex, Imports = primaryDependencyWalker.Imports.ToArray(), FromImports = primaryDependencyWalker.FromImports.ToArray(), StubImports = stubImports.ToArray(), StubFromImports = stubFromImports.ToArray() }); }
/// <summary> /// Constructs module persistent model from analysis. /// </summary> public static ModuleModel FromAnalysis(IDocumentAnalysis analysis, IServiceContainer services, AnalysisCachingLevel options) { var uniqueId = analysis.Document.GetUniqueId(services, options); if (uniqueId == null) { // Caching level setting does not permit this module to be persisted. return(null); } var variables = new Dictionary <string, VariableModel>(); var functions = new Dictionary <string, FunctionModel>(); var classes = new Dictionary <string, ClassModel>(); var typeVars = new Dictionary <string, TypeVarModel>(); var namedTuples = new Dictionary <string, NamedTupleModel>(); //var subModules = new Dictionary<string, SubmoduleModel>(); foreach (var v in analysis.Document.GetMemberNames() .Select(x => analysis.GlobalScope.Variables[x]).ExcludeDefault()) { if (v.Value is IGenericTypeParameter && !typeVars.ContainsKey(v.Name)) { typeVars[v.Name] = TypeVarModel.FromGeneric(v, services); continue; } switch (v.Value) { case ITypingNamedTupleType nt: namedTuples[v.Name] = new NamedTupleModel(nt, services); continue; case IPythonFunctionType ft when ft.IsLambda(): // No need to persist lambdas. continue; case IPythonFunctionType ft when v.Name != ft.Name: // Variable assigned to type info of the function like // def func(): ... // x = type(func) break; case IPythonFunctionType ft: var fm = GetFunctionModel(analysis, v, ft, services); if (fm != null && !functions.ContainsKey(ft.Name)) { functions[ft.Name] = fm; continue; } break; case IPythonClassType cls when v.Name != cls.Name: // Variable assigned to type info of the class. break; case IPythonClassType cls when cls.DeclaringModule.Equals(analysis.Document) || cls.DeclaringModule.Equals(analysis.Document.Stub): if (!classes.ContainsKey(cls.Name)) { classes[cls.Name] = new ClassModel(cls, services); continue; } break; } // Do not re-declare classes and functions as variables in the model. if (!variables.ContainsKey(v.Name)) { variables[v.Name] = VariableModel.FromVariable(v, services); } } return(new ModuleModel { Id = uniqueId.GetStableHash(), UniqueId = uniqueId, Name = analysis.Document.Name, QualifiedName = analysis.Document.QualifiedName, FilePath = analysis.Document.FilePath, Documentation = analysis.Document.Documentation, Functions = functions.Values.ToArray(), Variables = variables.Values.ToArray(), Classes = classes.Values.ToArray(), TypeVars = typeVars.Values.ToArray(), NamedTuples = namedTuples.Values.ToArray(), //SubModules = subModules.Values.ToArray(), NewLines = analysis.Ast.NewLineLocations.Select(l => new NewLineModel { EndIndex = l.EndIndex, Kind = l.Kind }).ToArray(), FileSize = analysis.Ast.EndIndex }); }