public async Task Mro()
        {
            using (var s = await CreateServicesAsync(null, null, null)) {
                var interpreter = s.GetService <IPythonInterpreter>();
                var o           = interpreter.GetBuiltinType(BuiltinTypeId.Object);
                var m           = new SentinelModule("test", s);

                var location = new Location(m);
                var O        = new PythonClassType("O", location);
                var A        = new PythonClassType("A", location);
                var B        = new PythonClassType("B", location);
                var C        = new PythonClassType("C", location);
                var D        = new PythonClassType("D", location);
                var E        = new PythonClassType("E", location);
                var F        = new PythonClassType("F", location);

                O.SetBases(new[] { o });
                F.SetBases(new[] { O });
                E.SetBases(new[] { O });
                D.SetBases(new[] { O });
                C.SetBases(new[] { D, F });
                B.SetBases(new[] { D, E });
                A.SetBases(new[] { B, C });

                var mroA = PythonClassType.CalculateMro(A).Select(p => p.Name);
                mroA.Should().Equal("A", "B", "C", "D", "E", "F", "O", "object");

                var mroB = PythonClassType.CalculateMro(B).Select(p => p.Name);
                mroB.Should().Equal("B", "D", "E", "O", "object");

                var mroC = PythonClassType.CalculateMro(C).Select(p => p.Name);
                mroC.Should().Equal("C", "D", "F", "O", "object");
            }
        }
Beispiel #2
0
        private IPythonModule GetModule()
        {
            var mod = Volatile.Read(ref _module);

            if (mod != null)
            {
                return(mod);
            }

            foreach (var n in _importNames)
            {
                mod = _interpreter.ImportModule(n);
                if (mod != null)
                {
                    Debug.Assert(!(mod is AstNestedPythonModule), "ImportModule should not return nested module");
                    break;
                }
            }
            if (mod == null)
            {
                mod = new SentinelModule(_importNames.FirstOrDefault() ?? "<unknown>", false);
            }

            return(Interlocked.CompareExchange(ref _module, mod, null) ?? mod);
        }
        private IPythonModule GetModule()
        {
            var module = Volatile.Read(ref _module);

            if (module != null)
            {
                return(module);
            }

            module = _interpreter.ImportModule(Name);
            if (module != null)
            {
                Debug.Assert(!(module is AstNestedPythonModule), "ImportModule should not return nested module");
            }

            if (module == null)
            {
                module = new SentinelModule(Name, false);
            }

            return(Interlocked.CompareExchange(ref _module, module, null) ?? module);
        }
Beispiel #4
0
 public void AddUnimportableModule(string moduleName)
 {
     _modules[moduleName] = new SentinelModule(moduleName, false);
 }
Beispiel #5
0
        public async Task <TryImportModuleResult> TryImportModuleAsync(string name, PathResolverSnapshot pathResolver, IReadOnlyList <string> typeStubPaths, bool mergeTypeStubPackages, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(name))
            {
                return(TryImportModuleResult.ModuleNotFound);
            }

            Debug.Assert(!name.EndsWithOrdinal("."), $"{name} should not end with '.'");

            // Handle builtins explicitly
            if (name == BuiltinModuleName)
            {
                Debug.Fail($"Interpreters must handle import {name} explicitly");
                return(TryImportModuleResult.NotSupported);
            }

            // Return any existing module
            if (_modules.TryGetValue(name, out var module) && module != null)
            {
                if (module is SentinelModule sentinelModule)
                {
                    // If we are importing this module on another thread, allow
                    // time for it to complete. This does not block if we are
                    // importing on the current thread or the module is not
                    // really being imported.
                    try {
                        module = await sentinelModule.WaitForImportAsync(cancellationToken);
                    } catch (OperationCanceledException) {
                        _log?.Log(TraceLevel.Warning, "ImportTimeout", name);
                        return(TryImportModuleResult.Timeout);
                    }

                    if (module is SentinelModule)
                    {
                        _log?.Log(TraceLevel.Warning, "RecursiveImport", name);
                    }
                }
                return(new TryImportModuleResult(module));
            }

            // Set up a sentinel so we can detect recursive imports
            var sentinelValue = new SentinelModule(name, true);

            if (!_modules.TryAdd(name, sentinelValue))
            {
                // Try to get the new module, in case we raced with a .Clear()
                if (_modules.TryGetValue(name, out module) && !(module is SentinelModule))
                {
                    return(new TryImportModuleResult(module));
                }
                // If we reach here, the race is too complicated to recover
                // from. Signal the caller to try importing again.
                _log?.Log(TraceLevel.Warning, "RetryImport", name);
                return(TryImportModuleResult.NeedRetry);
            }

            // Do normal searches
            if (!string.IsNullOrEmpty(_configuration?.InterpreterPath))
            {
                try {
                    module = ImportFromSearchPaths(name, pathResolver);
                } catch (OperationCanceledException) {
                    _log?.Log(TraceLevel.Error, "ImportTimeout", name, "ImportFromSearchPaths");
                    return(TryImportModuleResult.Timeout);
                }
            }

            if (module == null)
            {
                module = _astModuleCache.ImportFromCache(name, _interpreter);
            }

            // Also search for type stub packages if enabled and we are not a blacklisted module
            if (module != null && typeStubPaths != null && module.Name != "typing")
            {
                var tsModule = ImportFromTypeStubs(module.Name, typeStubPaths, pathResolver);
                if (tsModule != null)
                {
                    module = mergeTypeStubPackages ? AstPythonMultipleMembers.CombineAs <IPythonModule>(module, tsModule) : tsModule;
                }
            }

            // Replace our sentinel, or if we raced, get the current
            // value and abandon the one we just created.
            if (!_modules.TryUpdate(name, module, sentinelValue))
            {
                // Try to get the new module, in case we raced
                if (_modules.TryGetValue(name, out module) && !(module is SentinelModule))
                {
                    return(new TryImportModuleResult(module));
                }
                // If we reach here, the race is too complicated to recover
                // from. Signal the caller to try importing again.
                _log?.Log(TraceLevel.Warning, "RetryImport", name);
                return(TryImportModuleResult.NeedRetry);
            }
            sentinelValue.Complete(module);

            return(new TryImportModuleResult(module));
        }
        private IPythonModule ImportModuleOrRetry(string name, out bool retry)
        {
            retry = false;
            if (string.IsNullOrEmpty(name))
            {
                return(null);
            }

            Debug.Assert(!name.EndsWith("."), $"{name} should not end with '.'");

            // Handle builtins explicitly
            if (name == BuiltinModuleName)
            {
                if (_builtinModule == null)
                {
                    _modules[BuiltinModuleName] = _builtinModule = new AstBuiltinsPythonModule(_factory.LanguageVersion);
                    _builtinModuleNames         = null;
                    _builtinModule.Imported(this);
                    var bmn = ((AstBuiltinsPythonModule)_builtinModule).GetAnyMember("__builtin_module_names") as AstPythonStringLiteral;
                    _builtinModuleNames = bmn?.Value?.Split(',') ?? Array.Empty <string>();
                }
                return(_builtinModule);
            }

            IPythonModule mod;

            // Return any existing module
            if (_modules.TryGetValue(name, out mod) && mod != null)
            {
                if (mod is SentinelModule smod)
                {
                    // If we are importing this module on another thread, allow
                    // time for it to complete. This does not block if we are
                    // importing on the current thread or the module is not
                    // really being imported.
                    var newMod = smod.WaitForImport(5000);
                    if (newMod is SentinelModule)
                    {
                        _log?.Log(TraceLevel.Warning, "RecursiveImport", name);
                        mod = newMod;
                    }
                    else if (newMod == null)
                    {
                        _log?.Log(TraceLevel.Warning, "ImportTimeout", name);
                    }
                    else
                    {
                        mod = newMod;
                    }
                }
                return(mod);
            }

            // Set up a sentinel so we can detect recursive imports
            var sentinalValue = new SentinelModule(name, true);

            if (!_modules.TryAdd(name, sentinalValue))
            {
                // Try to get the new module, in case we raced with a .Clear()
                if (_modules.TryGetValue(name, out mod) && !(mod is SentinelModule))
                {
                    return(mod);
                }
                // If we reach here, the race is too complicated to recover
                // from. Signal the caller to try importing again.
                _log?.Log(TraceLevel.Warning, "RetryImport", name);
                retry = true;
                return(null);
            }

            // Do normal searches
            mod = ImportFromBuiltins(name) ?? ImportFromSearchPaths(name);

            // Replace our sentinel, or if we raced, get the current
            // value and abandon the one we just created.
            if (!_modules.TryUpdate(name, mod, sentinalValue))
            {
                // Try to get the new module, in case we raced
                if (_modules.TryGetValue(name, out mod) && !(mod is SentinelModule))
                {
                    return(mod);
                }
                // If we reach here, the race is too complicated to recover
                // from. Signal the caller to try importing again.
                _log?.Log(TraceLevel.Warning, "RetryImport", name);
                retry = true;
                return(null);
            }

            sentinalValue.Complete(mod);
            sentinalValue.Dispose();
            return(mod);
        }
Beispiel #7
0
        public TryImportModuleResult TryImportModule(
            string name,
            out IPythonModule module,
            TryImportModuleContext context
            )
        {
            module = null;
            if (string.IsNullOrEmpty(name))
            {
                return(TryImportModuleResult.ModuleNotFound);
            }

            Debug.Assert(!name.EndsWithOrdinal("."), $"{name} should not end with '.'");

            // Handle builtins explicitly
            if (name == BuiltinModuleName)
            {
                Debug.Fail($"Interpreters must handle import {name} explicitly");
                return(TryImportModuleResult.NotSupported);
            }

            var            modules       = context?.ModuleCache;
            int            importTimeout = context?.Timeout ?? 5000;
            SentinelModule sentinalValue = null;

            if (modules != null)
            {
                // Return any existing module
                if (modules.TryGetValue(name, out module) && module != null)
                {
                    if (module is SentinelModule smod)
                    {
                        // If we are importing this module on another thread, allow
                        // time for it to complete. This does not block if we are
                        // importing on the current thread or the module is not
                        // really being imported.
                        var newMod = smod.WaitForImport(importTimeout);
                        if (newMod is SentinelModule)
                        {
                            _log?.Log(TraceLevel.Warning, "RecursiveImport", name);
                            module = newMod;
                        }
                        else if (newMod == null)
                        {
                            _log?.Log(TraceLevel.Warning, "ImportTimeout", name);
                            module = null;
                            return(TryImportModuleResult.Timeout);
                        }
                        else
                        {
                            module = newMod;
                        }
                    }
                    return(TryImportModuleResult.Success);
                }

                // Set up a sentinel so we can detect recursive imports
                sentinalValue = new SentinelModule(name, true);
                if (!modules.TryAdd(name, sentinalValue))
                {
                    // Try to get the new module, in case we raced with a .Clear()
                    if (modules.TryGetValue(name, out module) && !(module is SentinelModule))
                    {
                        return(module == null ? TryImportModuleResult.ModuleNotFound : TryImportModuleResult.Success);
                    }
                    // If we reach here, the race is too complicated to recover
                    // from. Signal the caller to try importing again.
                    _log?.Log(TraceLevel.Warning, "RetryImport", name);
                    return(TryImportModuleResult.NeedRetry);
                }
            }

            // Do normal searches
            if (!string.IsNullOrEmpty(Configuration?.InterpreterPath))
            {
                var importTask = ImportFromSearchPathsAsync(name, context);
                if (importTask.Wait(importTimeout))
                {
                    module = importTask.Result;
                }
                else
                {
                    _log?.Log(TraceLevel.Error, "ImportTimeout", name, "ImportFromSearchPaths");
                    module = null;
                }
                module = module ?? ImportFromBuiltins(name, context.BuiltinModule as AstBuiltinsPythonModule);
            }
            if (module == null)
            {
                module = ImportFromCache(name);
            }

            if (modules != null)
            {
                // Replace our sentinel, or if we raced, get the current
                // value and abandon the one we just created.
                if (!modules.TryUpdate(name, module, sentinalValue))
                {
                    // Try to get the new module, in case we raced
                    if (modules.TryGetValue(name, out module) && !(module is SentinelModule))
                    {
                        return(module == null ? TryImportModuleResult.ModuleNotFound : TryImportModuleResult.Success);
                    }
                    // If we reach here, the race is too complicated to recover
                    // from. Signal the caller to try importing again.
                    _log?.Log(TraceLevel.Warning, "RetryImport", name);
                    return(TryImportModuleResult.NeedRetry);
                }
                sentinalValue.Complete(module);
                sentinalValue.Dispose();
            }

            return(TryImportModuleResult.Success);
        }
        public TryImportModuleResult TryImportModule(
            string name,
            out IPythonModule module,
            TryImportModuleContext context
            )
        {
            module = null;
            if (string.IsNullOrEmpty(name))
            {
                return(TryImportModuleResult.ModuleNotFound);
            }

            Debug.Assert(!name.EndsWithOrdinal("."), $"{name} should not end with '.'");

            // Handle builtins explicitly
            if (name == BuiltinModuleName)
            {
                Debug.Fail($"Interpreters must handle import {name} explicitly");
                return(TryImportModuleResult.NotSupported);
            }

            var            modules       = context?.ModuleCache;
            int            importTimeout = context?.Timeout ?? 5000;
            SentinelModule sentinalValue = null;

            if (modules != null)
            {
                // Return any existing module
                if (modules.TryGetValue(name, out module) && module != null)
                {
                    if (module is SentinelModule smod)
                    {
                        // If we are importing this module on another thread, allow
                        // time for it to complete. This does not block if we are
                        // importing on the current thread or the module is not
                        // really being imported.
                        var newMod = smod.WaitForImport(importTimeout);
                        if (newMod is SentinelModule)
                        {
                            _log?.Log(TraceLevel.Warning, "RecursiveImport", name);
                            module = newMod;
                        }
                        else if (newMod == null)
                        {
                            _log?.Log(TraceLevel.Warning, "ImportTimeout", name);
                            module = null;
                            return(TryImportModuleResult.Timeout);
                        }
                        else
                        {
                            module = newMod;
                        }
                    }
                    return(TryImportModuleResult.Success);
                }

                // Set up a sentinel so we can detect recursive imports
                sentinalValue = new SentinelModule(name, true);
                if (!modules.TryAdd(name, sentinalValue))
                {
                    // Try to get the new module, in case we raced with a .Clear()
                    if (modules.TryGetValue(name, out module) && !(module is SentinelModule))
                    {
                        return(module == null ? TryImportModuleResult.ModuleNotFound : TryImportModuleResult.Success);
                    }
                    // If we reach here, the race is too complicated to recover
                    // from. Signal the caller to try importing again.
                    _log?.Log(TraceLevel.Warning, "RetryImport", name);
                    return(TryImportModuleResult.NeedRetry);
                }
            }

            // Do normal searches
            if (!string.IsNullOrEmpty(Configuration?.InterpreterPath))
            {
                var importTask = ImportFromSearchPathsAsync(name, context);
                if (importTask.Wait(importTimeout))
                {
                    module = importTask.Result;
                }
                else
                {
                    _log?.Log(TraceLevel.Error, "ImportTimeout", name, "ImportFromSearchPaths");
                    module = null;
                }
                module = module ?? ImportFromBuiltins(name, context.BuiltinModule as AstBuiltinsPythonModule);
            }
            if (module == null)
            {
                module = ImportFromCache(name);
            }

            if (modules != null)
            {
                // Replace our sentinel, or if we raced, get the current
                // value and abandon the one we just created.
                if (!modules.TryUpdate(name, module, sentinalValue))
                {
                    // Try to get the new module, in case we raced
                    if (modules.TryGetValue(name, out module) && !(module is SentinelModule))
                    {
                        return(module == null ? TryImportModuleResult.ModuleNotFound : TryImportModuleResult.Success);
                    }
                    // If we reach here, the race is too complicated to recover
                    // from. Signal the caller to try importing again.
                    _log?.Log(TraceLevel.Warning, "RetryImport", name);
                    return(TryImportModuleResult.NeedRetry);
                }
                sentinalValue.Complete(module);
                sentinalValue.Dispose();
            }

            // Also search for type stub packages if enabled and we are not a blacklisted module
            if (module != null && module.Name != "typing")
            {
                // Note that this currently only looks in the typeshed package, as type stub
                // packages are not yet standardised so we don't know where to look.
                // The details will be in PEP 561.
                if (context.TypeStubPaths?.Any() == true)
                {
                    var mtsp = FindModuleInSearchPath(context.TypeStubPaths, null, module.Name);
                    if (mtsp.HasValue)
                    {
                        var mp = mtsp.Value;
                        if (mp.IsCompiled)
                        {
                            Debug.Fail("Unsupported native module in typeshed");
                        }
                        else
                        {
                            _log?.Log(TraceLevel.Verbose, "ImportTypeShed", mp.FullName, FastRelativePath(mp.SourceFile));
                            var tsModule = PythonModuleLoader.FromFile(context.Interpreter, mp.SourceFile, LanguageVersion, mp.FullName);

                            if (tsModule != null)
                            {
                                if (context.MergeTypeStubPackages)
                                {
                                    module = AstPythonMultipleModules.Combine(module, tsModule);
                                }
                                else
                                {
                                    module = tsModule;
                                }
                            }
                        }
                    }
                }
            }

            return(module == null ? TryImportModuleResult.ModuleNotFound : TryImportModuleResult.Success);
        }