private bool TryAddProperty(FunctionDefinition node, IPythonType declaringType) { // We can't add a property to an unknown type. Fallback to a regular function for now. // TOOD: Decouple declaring types from the property. if (declaringType.IsUnknown()) { return(false); } var dec = node.Decorators?.Decorators; var decorators = dec != null?dec.ExcludeDefault().ToArray() : Array.Empty <Expression>(); foreach (var d in decorators.OfType <NameExpression>()) { switch (d.Name) { case @"property": AddProperty(node, declaringType, false); return(true); case @"abstractproperty": AddProperty(node, declaringType, true); return(true); } } return(false); }
private static bool IsStubBetterType(IPythonType sourceType, IPythonType stubType) { if (stubType.IsUnknown()) { // Do not use worse types than what is in the module. return(false); } if (sourceType.IsUnknown()) { return(true); // Anything is better than unknowns. } // If stub says 'Any' but we have better type, keep the current type. return(!(stubType.DeclaringModule is TypingModule) || stubType.Name != "Any"); }
private void TransferDocumentationAndLocation(IPythonType sourceType, IPythonType stubType) { if (sourceType.IsUnknown() || sourceType.DeclaringModule.ModuleType == ModuleType.Builtins || stubType.IsUnknown() || stubType.DeclaringModule.ModuleType == ModuleType.Builtins) { return; // Do not transfer location of unknowns or builtins } // Stub may be one for multiple modules - when module consists of several // submodules, there is typically only one stub for the main module. // Types from 'unittest.case' (library) are stubbed in 'unittest' stub. if (!IsFromThisModuleOrSubmodules(sourceType)) { return; // Do not change unrelated types. } // Destination must be from this module stub and not from other modules. // Consider that 'email.headregistry' stub has DataHeader declaring 'datetime' // property of type 'datetime' from 'datetime' module. We don't want to modify // datetime type and change it's location to 'email.headregistry'. if (stubType.DeclaringModule.ModuleType != ModuleType.Stub || stubType.DeclaringModule != _eval.Module.Stub) { return; } // Documentation and location are always get transferred from module type // to the stub type and never the other way around. This makes sure that // we show documentation from the original module and goto definition // navigates to the module source and not to the stub. if (sourceType != stubType && sourceType is PythonType src && stubType is PythonType dst) { // If type is a class, then doc can either come from class definition node of from __init__. // If class has doc from the class definition, don't stomp on it. if (src is PythonClassType srcClass && dst is PythonClassType dstClass) { // Higher lever source wins if (srcClass.DocumentationSource == PythonClassType.ClassDocumentationSource.Class || (srcClass.DocumentationSource == PythonClassType.ClassDocumentationSource.Init && dstClass.DocumentationSource == PythonClassType.ClassDocumentationSource.Base)) { dstClass.SetDocumentation(srcClass.Documentation); } }
private static void TransferDocumentationAndLocation(IPythonType s, IPythonType d) { if (s.IsUnknown()) { return; // Do not transfer location of unknowns } // Documentation and location are always get transferred from module type // to the stub type and never the other way around. This makes sure that // we show documentation from the original module and goto definition // navigates to the module source and not to the stub. if (s != d && s is PythonType src && d is PythonType dst) { var documentation = src.Documentation; if (!string.IsNullOrEmpty(documentation)) { dst.SetDocumentation(documentation); } dst.Location = src.Location; } }
private void HandleTypedVariable(IPythonType variableType, IMember value, Expression expr) { // Check value type for compatibility IMember instance = null; if (value != null) { var valueType = value.GetPythonType(); if (!variableType.IsUnknown() && !valueType.Equals(variableType)) { // TODO: warn incompatible value type. // TODO: verify values. Value may be list() while variable type is List[str]. // Leave it as variable type. } else { instance = value; } } var args = ArgumentSet.Empty(expr, Eval); instance = instance ?? variableType?.CreateInstance(args) ?? Eval.UnknownType.CreateInstance(ArgumentSet.WithoutContext); if (expr is NameExpression ne) { Eval.DeclareVariable(ne.Name, instance, VariableSource.Declaration, ne); return; } if (expr is MemberExpression m) { // self.x : int = 42 var self = Eval.LookupNameInScopes("self", out var scope); var argType = self?.GetPythonType(); if (argType is PythonClassType cls && scope != null) { cls.AddMember(m.Name, instance, true); } } }