private IEnumerable <PythonInterpreterInformation> FindWorkspaceInterpreters(IPythonWorkspaceContext workspace)
        {
            var found = new List <PythonInterpreterInformation>();

            if (workspace != null)
            {
                // First look in workspace subfolders
                found.AddRange(FindInterpretersInSubFolders(workspace.Location).Where(p => p != null));

                // Then look at the currently set interpreter path,
                // because it may point to a folder outside of the workspace,
                // or in a deep subfolder that we don't look into.
                var interpreter = workspace.ReadInterpreterSetting();
                if (PathUtils.IsValidPath(interpreter) && !Path.IsPathRooted(interpreter))
                {
                    interpreter = workspace.MakeRooted(interpreter);
                }

                // Make sure it wasn't already discovered
                if (File.Exists(interpreter) && !found.Any(p => PathUtils.IsSamePath(p.Configuration.InterpreterPath, interpreter)))
                {
                    var info = CreateEnvironmentInfo(interpreter);
                    if (info != null)
                    {
                        found.Add(info);
                    }
                }
            }

            return(found);
        }
        private void InitializeWorkspace(IPythonWorkspaceContext workspace)
        {
            lock (_factories) {
                // Cleanup state associated with the previous workspace, if any
                if (_workspace != null)
                {
                    _workspace.InterpreterSettingChanged -= OnInterpreterSettingChanged;
                    _workspace = null;
                }

                _folderWatcher?.Dispose();
                _folderWatcher = null;
                _folderWatcherTimer?.Dispose();
                _folderWatcherTimer = null;

                // Setup new workspace
                _workspace = workspace;
                if (_workspace != null)
                {
                    _workspace.InterpreterSettingChanged += OnInterpreterSettingChanged;
                    try {
                        _folderWatcher                       = new FileSystemWatcher(_workspace.Location, "*.*");
                        _folderWatcher.Created              += OnFileCreatedDeletedRenamed;
                        _folderWatcher.Deleted              += OnFileCreatedDeletedRenamed;
                        _folderWatcher.Renamed              += OnFileCreatedDeletedRenamed;
                        _folderWatcher.EnableRaisingEvents   = true;
                        _folderWatcher.IncludeSubdirectories = true;
                    } catch (ArgumentException) {
                    } catch (IOException) {
                    }
                    _folderWatcherTimer = new Timer(OnFileChangesTimerElapsed);
                }
            }
        }
示例#3
0
        private static IEnumerable <InterpreterConfiguration> TestTriggerDiscovery(
            IPythonWorkspaceContext workspaceContext,
            Action triggerDiscovery,
            IPythonWorkspaceContextProvider workspaceContextProvider = null,
            bool useDiscoveryStartedEvent = false
            )
        {
            workspaceContextProvider = workspaceContextProvider
                                       ?? new WorkspaceTestHelper.MockWorkspaceContextProvider(workspaceContext);

            using (var provider = new WorkspaceInterpreterFactoryProvider(workspaceContextProvider))
                using (var evt = new AutoResetEvent(false)) {
                    // This initializes the provider, discovers the initial set
                    // of factories and starts watching the filesystem.
                    provider.GetInterpreterFactories();

                    if (useDiscoveryStartedEvent)
                    {
                        provider.DiscoveryStarted += (sender, e) => {
                            evt.Set();
                        };
                    }
                    else
                    {
                        provider.InterpreterFactoriesChanged += (sender, e) => {
                            evt.Set();
                        };
                    }

                    triggerDiscovery();
                    Assert.IsTrue(evt.WaitOne(5000), "Failed to trigger discovery.");
                    return(provider.GetInterpreterConfigurations());
                }
        }
        private async Task InitializeCurrentContext()
        {
            var workspace = _workspaceService.CurrentWorkspace;

            if (workspace != null)
            {
                var context = new PythonWorkspaceContext(workspace, await workspace.GetPropertyEvaluatorServiceAsync(), _optionsService.Value, _registryService.Value);

                // Workspace interpreter factory provider will rescan the
                // workspace folder for factories.
                WorkspaceOpening?.Invoke(this, new PythonWorkspaceContextEventArgs(context));

                lock (_currentContextLock) {
                    _currentContext = context;
                }

                // Workspace sets its interpreter factory instance
                // This can trigger WorkspaceInterpreterFactoryProvider discovery
                // which needs to look at this object's _currentContext, which is why we
                // set that before calling initialize.
                context.Initialize();

                // Let users know this workspace context is all initialized
                WorkspaceInitialized?.Invoke(this, new PythonWorkspaceContextEventArgs(context));
            }
        }
        private void SetupWorkspace(IPythonWorkspaceContext workspace)
        {
            if (workspace == null)
            {
                return;
            }

            TestFrameworkType testFrameworkType = GetTestFramework(workspace);

            if (testFrameworkType != TestFrameworkType.None)
            {
                var projInfo = new ProjectInfo(workspace);
                _projectMap[projInfo.ProjectHome] = projInfo;

                var oldWatcher = _testFilesUpdateWatcher;
                _testFilesUpdateWatcher = new TestFilesUpdateWatcher();
                _testFilesUpdateWatcher.FileChangedEvent += OnWorkspaceFileChanged;
                _testFilesUpdateWatcher.AddDirectoryWatch(workspace.Location);
                oldWatcher?.Dispose();

                Regex testFileFilterRegex         = new Regex(@".*\.(py|txt)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                Predicate <string> testFileFilter = (x) => testFileFilterRegex.IsMatch(x);
                foreach (var file in _workspaceContextProvider.Workspace.EnumerateUserFiles(testFileFilter))
                {
                    projInfo.AddTestContainer(this, file);
                }

                workspace.ActiveInterpreterChanged -= OnActiveInterpreterChanged;
                workspace.ActiveInterpreterChanged += OnActiveInterpreterChanged;
                _packageManagerEventSink.WatchPackageManagers(workspace.CurrentFactory);
            }
        }
 public EnvironmentSwitcherWorkspaceContext(IServiceProvider serviceProvider, IPythonWorkspaceContext pythonWorkspace)
 {
     _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
     _pythonWorkspace = pythonWorkspace ?? throw new ArgumentNullException(nameof(pythonWorkspace));
     _registryService = serviceProvider.GetComponentModel().GetService <IInterpreterRegistryService>();
     _pythonWorkspace.ActiveInterpreterChanged += OnActiveInterpreterChanged;
 }
示例#7
0
        protected virtual void Dispose(bool disposing)
        {
            if (_isDisposed)
            {
                return;
            }
            _isDisposed = true;

            if (_projectWithHookedEvents != null)
            {
                _projectWithHookedEvents.ActiveInterpreterChanged -= Project_ConfigurationChanged;
                _projectWithHookedEvents._searchPaths.Changed     -= Project_ConfigurationChanged;
                _projectWithHookedEvents = null;
            }

            if (_workspaceWithHookedEvents != null)
            {
                _workspaceWithHookedEvents.ActiveInterpreterChanged  -= Workspace_ConfigurationChanged;
                _workspaceWithHookedEvents.SearchPathsSettingChanged -= Workspace_ConfigurationChanged;
                _workspaceWithHookedEvents = null;
            }

            if (disposing)
            {
                _analyzer?.Dispose();
            }
        }
        private void SetupWorkspace(IPythonWorkspaceContext workspace)
        {
            if (workspace == null ||
                GetTestFramework(workspace) == TestFrameworkType.None)
            {
                return;
            }

            try {
                Predicate <string> testFileFilter = (x) => PythonConstants.TestFileExtensionRegex.IsMatch(PathUtils.GetFileOrDirectoryName(x));

                var projInfo = new ProjectInfo(workspace);
                foreach (var file in _workspaceContextProvider.Workspace.EnumerateUserFiles(testFileFilter))
                {
                    projInfo.AddTestContainer(this, file);
                }

                _projectMap[projInfo.ProjectHome] = projInfo;
            } catch (Exception ex) when(!ex.IsCriticalException())
            {
                Trace.WriteLine("Exception : " + ex.Message);
            }

            // Register listeners
            var oldWatcher = _testFilesUpdateWatcher;

            _testFilesUpdateWatcher = new TestFilesUpdateWatcher();
            _testFilesUpdateWatcher.FileChangedEvent += OnWorkspaceFileChanged;
            _testFilesUpdateWatcher.AddDirectoryWatch(workspace.Location);
            oldWatcher?.Dispose();

            workspace.ActiveInterpreterChanged -= OnActiveInterpreterChanged;
            workspace.ActiveInterpreterChanged += OnActiveInterpreterChanged;
            _packageManagerEventSink.WatchPackageManagers(workspace.CurrentFactory);
        }
示例#9
0
 public ProjectInfo(PythonProject project)
 {
     _pythonProject   = project;
     _pythonWorkspace = null;
     _projectHome     = _pythonProject.ProjectHome;
     _projectName     = _pythonProject.ProjectName;
     _containers      = new ConcurrentDictionary <string, TestContainer>(StringComparer.OrdinalIgnoreCase);
 }
示例#10
0
 public ProjectInfo(IPythonWorkspaceContext workspace)
 {
     _pythonProject   = null;
     _pythonWorkspace = workspace;
     _projectHome     = workspace.Location;
     _projectName     = workspace.WorkspaceName;
     _containers      = new ConcurrentDictionary <string, TestContainer>(StringComparer.OrdinalIgnoreCase);
 }
示例#11
0
 public void SimulateChangeWorkspace(IPythonWorkspaceContext context)
 {
     WorkspaceClosing?.Invoke(this, new PythonWorkspaceContextEventArgs(Workspace));
     WorkspaceClosed?.Invoke(this, new PythonWorkspaceContextEventArgs(Workspace));
     Workspace = context;
     WorkspaceOpening?.Invoke(this, new PythonWorkspaceContextEventArgs(Workspace));
     WorkspaceInitialized?.Invoke(this, new PythonWorkspaceContextEventArgs(Workspace));
 }
 internal static string GetEvaluatorId(IPythonWorkspaceContext workspace)
 {
     return("{0};workspace;{1};{2}".FormatInvariant(
                _prefix,
                workspace.WorkspaceName,
                workspace.Location
                ));
 }
        private void OnWorkspaceFileChanged(object sender, TestFileChangedEventArgs e)
        {
            if (String.IsNullOrEmpty(e.File))
            {
                return;
            }

            if (IsSettingsFile(e.File))
            {
                NotifyContainerChanged();
                _isRefresh = true;
                return;
            }

            if (!IsTestFile(e.File))
            {
                return;
            }

            IPythonWorkspaceContext workspace = _workspaceContextProvider.Workspace;

            if (workspace == null)
            {
                return;
            }

            var projInfo = GetProjectInfo(workspace.Location);

            if (projInfo == null || IsFileExcluded(projInfo, e.File))
            {
                return;
            }

            switch (e.ChangedReason)
            {
            case TestFileChangedReason.Added:
                projInfo.AddTestContainer(this, e.File);
                break;

            case TestFileChangedReason.Changed:
                projInfo.AddTestContainer(this, e.File);
                break;

            case TestFileChangedReason.Removed:
                projInfo.RemoveTestContainer(e.File);
                break;

            case TestFileChangedReason.Renamed:
                projInfo.RemoveTestContainer(e.OldFile);
                projInfo.AddTestContainer(this, e.File);
                break;

            default:
                break;
            }
            NotifyContainerChanged();
        }
示例#14
0
        private void CloseAnalyzer(IPythonWorkspaceContext workspace)
        {
            _site.MustBeCalledFromUIThread();

            if (_analyzers.TryGetValue(workspace, out WorkspaceAnalyzer analyzer))
            {
                _analyzers.Remove(workspace);
                analyzer.Dispose();
            }
        }
        private void ForceDiscoverInterpreterFactories()
        {
            DiscoveryStarted?.Invoke(this, EventArgs.Empty);

            // Discover the available interpreters...
            bool anyChanged = false;

            IPythonWorkspaceContext workspace = null;

            lock (_factories) {
                workspace = _workspace;
            }

            List <PythonInterpreterInformation> found;

            try {
                found = FindWorkspaceInterpreters(workspace)
                        .Where(i => !ExcludedVersions.Contains(i.Configuration.Version))
                        .ToList();
            } catch (ObjectDisposedException) {
                // We are aborting, so silently return with no results.
                return;
            }

            var uniqueIds = new HashSet <string>(found.Select(i => i.Configuration.Id));

            // Then update our cached state with the lock held.
            lock (_factories) {
                foreach (var info in found)
                {
                    PythonInterpreterInformation existingInfo;
                    if (!_factories.TryGetValue(info.Configuration.Id, out existingInfo) ||
                        info.Configuration != existingInfo.Configuration)
                    {
                        _factories[info.Configuration.Id] = info;
                        anyChanged = true;
                    }
                }

                // Remove any factories we had before and no longer see...
                foreach (var unregistered in _factories.Keys.Except(uniqueIds).ToArray())
                {
                    _factories.Remove(unregistered);
                    anyChanged = true;
                }
            }

            if (anyChanged)
            {
                OnInterpreterFactoriesChanged();
            }
        }
 private void CloseCurrentContext()
 {
     lock (_currentContextLock) {
         var current = _currentContext;
         if (current != null)
         {
             WorkspaceClosing?.Invoke(this, new PythonWorkspaceContextEventArgs(current));
             current.Dispose();
             WorkspaceClosed?.Invoke(this, new PythonWorkspaceContextEventArgs(current));
         }
         _currentContext = null;
     }
 }
        public PythonLanguageClientContextWorkspace(IPythonWorkspaceContext pythonWorkspace)
        {
            _pythonWorkspace = pythonWorkspace ?? throw new ArgumentNullException(nameof(pythonWorkspace));
            _disposables     = new DisposableBag(GetType().Name);

            _pythonWorkspace.ActiveInterpreterChanged  += OnInterpreterChanged;
            _pythonWorkspace.SearchPathsSettingChanged += OnSearchPathsChanged;
            _disposables.Add(() => {
                _pythonWorkspace.ActiveInterpreterChanged  -= OnInterpreterChanged;
                _pythonWorkspace.SearchPathsSettingChanged -= OnSearchPathsChanged;
            });

            _pythonWorkspace.AddActionOnClose(this, (obj) => Closed?.Invoke(this, EventArgs.Empty));
        }
        private static TestFrameworkType GetTestFramework(IPythonWorkspaceContext workspace)
        {
            var testFrameworkType = TestFrameworkType.None;

            try {
                string testFrameworkStr = workspace.GetStringProperty(PythonConstants.TestFrameworkSetting);
                if (Enum.TryParse <TestFrameworkType>(testFrameworkStr, ignoreCase: true, out TestFrameworkType parsedFramework))
                {
                    testFrameworkType = parsedFramework;
                }
            } catch (Exception ex) when(!ex.IsCriticalException())
            {
                Trace.WriteLine("Exception : " + ex.Message);
            }

            return(testFrameworkType);
        }
示例#19
0
 public ProjectView(IPythonWorkspaceContext workspace)
 {
     Workspace  = workspace ?? throw new ArgumentNullException(nameof(workspace));
     Name       = workspace.WorkspaceName;
     HomeFolder = workspace.Location;
     if (workspace.CurrentFactory != null)
     {
         var id = workspace.CurrentFactory.Configuration.Id;
         InterpreterIds      = new string[] { id };
         ActiveInterpreterId = id;
     }
     else
     {
         InterpreterIds      = new string[0];
         ActiveInterpreterId = string.Empty;
     }
     RequirementsTxtPath = workspace.GetRequirementsTxtPath();
     EnvironmentYmlPath  = workspace.GetEnvironmentYmlPath();
 }
示例#20
0
 public static async Task ShowAddVirtualEnvironmentDialogAsync(
     IServiceProvider site,
     PythonProjectNode project,
     IPythonWorkspaceContext workspace,
     string existingCondaEnvName,
     string environmentYmlPath,
     string requirementsTxtPath,
     CancellationToken ct = default(CancellationToken)
     )
 {
     await ShowDialogAsync(
         PageKind.VirtualEnvironment,
         site,
         project,
         workspace,
         existingCondaEnvName,
         environmentYmlPath,
         requirementsTxtPath,
         ct
         );
 }
示例#21
0
        public WorkspaceAnalyzer(
            IPythonWorkspaceContext pythonWorkspace,
            IInterpreterOptionsService optionsService,
            IServiceProvider site
            )
        {
            _pythonWorkspace = pythonWorkspace ?? throw new ArgumentNullException(nameof(pythonWorkspace));
            _optionsService  = optionsService ?? throw new ArgumentNullException(nameof(optionsService));
            _site            = site ?? throw new ArgumentNullException(nameof(site));

            _logger         = (IPythonToolsLogger)_site.GetService(typeof(IPythonToolsLogger));
            _pendingChanges = new HashSet <AnalysisEntry>();
            _pendingDeletes = new HashSet <AnalysisEntry>();

            _recreatingAnalyzer = new SemaphoreSlim(1);
            _deferredWorkspaceFileChangeNotification = new Timer(OnDeferredWorkspaceFileChanged);
            _deferredModulesChangeNotification       = new Timer(OnDeferredModulesChanged);

            _pythonWorkspace.ActiveInterpreterChanged  += OnActiveInterpreterChanged;
            _pythonWorkspace.SearchPathsSettingChanged += OnSearchPathsChanged;
        }
        public AddCondaEnvironmentOperation(
            IServiceProvider site,
            ICondaEnvironmentManager condaMgr,
            PythonProjectNode project,
            IPythonWorkspaceContext workspace,
            string envNameOrPath,
            string envFilePath,
            List <PackageSpec> packages,
            bool setAsCurrent,
            bool setAsDefault,
            bool viewInEnvWindow
            )
        {
            _site            = site ?? throw new ArgumentNullException(nameof(site));
            _condaMgr        = condaMgr ?? throw new ArgumentNullException(nameof(condaMgr));
            _project         = project;
            _workspace       = workspace;
            _envNameOrPath   = envNameOrPath ?? throw new ArgumentNullException(nameof(envNameOrPath));
            _envFilePath     = envFilePath;
            _packages        = packages ?? throw new ArgumentNullException(nameof(packages));
            _setAsCurrent    = setAsCurrent;
            _setAsDefault    = setAsDefault;
            _viewInEnvWindow = viewInEnvWindow;

            // If passed a path, the actual name reported by conda will the last part
            _actualName = PathUtils.GetFileOrDirectoryName(_envNameOrPath);
            if (_actualName.Length == 0)
            {
                _actualName = _envNameOrPath;
            }

            _outputWindow = OutputWindowRedirector.GetGeneral(_site);
            _statusBar    = _site.GetService(typeof(SVsStatusbar)) as IVsStatusbar;
            _showAndActiveOutputWindow = _site.GetPythonToolsService().GeneralOptions.ShowOutputWindowForVirtualEnvCreate;
            _statusCenter    = _site.GetService(typeof(SVsTaskStatusCenterService)) as IVsTaskStatusCenterService;
            _registry        = _site.GetComponentModel().GetService <IInterpreterRegistryService>();
            _options         = _site.GetComponentModel().GetService <IInterpreterOptionsService>();
            _logger          = _site.GetService(typeof(IPythonToolsLogger)) as IPythonToolsLogger;
            _factoryProvider = _site.GetComponentModel().GetService <CondaEnvironmentFactoryProvider>();
        }
示例#23
0
        public static string GetStringSetting(
            string settingName,
            string filePath,
            IServiceProvider site,
            IPythonWorkspaceContext workspace,
            out ValueSource source)
        {
            source = ValueSource.Global;
            string value = null;

            if (workspace != null)
            {
                // Try workspace file
                value = workspace.GetStringProperty(settingName);
                if (value != null)
                {
                    source = ValueSource.Workspace;
                }
            }
            else
            {
                // Try project
                if (filePath != null)
                {
                    var project = site.GetProjectContainingFile(filePath);
                    if (project != null)
                    {
                        value = project.GetProjectProperty(settingName);
                        if (value != null)
                        {
                            source = ValueSource.Project;
                        }
                    }
                }
            }

            return(value);
        }
示例#24
0
 public AddVirtualEnvironmentOperation(
     IServiceProvider site,
     PythonProjectNode project,
     IPythonWorkspaceContext workspace,
     string virtualEnvPath,
     string baseInterpreterId,
     bool useVEnv,
     bool installRequirements,
     string requirementsPath,
     bool registerAsCustomEnv,
     string customEnvName,
     bool setAsCurrent,
     bool setAsDefault,
     bool viewInEnvWindow,
     Redirector output = null
     )
 {
     _site                = site ?? throw new ArgumentNullException(nameof(site));
     _project             = project;
     _workspace           = workspace;
     _virtualEnvPath      = virtualEnvPath ?? throw new ArgumentNullException(nameof(virtualEnvPath));
     _baseInterpreter     = baseInterpreterId ?? throw new ArgumentNullException(nameof(baseInterpreterId));
     _useVEnv             = useVEnv;
     _installReqs         = installRequirements;
     _reqsPath            = requirementsPath;
     _registerAsCustomEnv = registerAsCustomEnv;
     _customEnvName       = customEnvName;
     _setAsCurrent        = setAsCurrent;
     _setAsDefault        = setAsDefault;
     _viewInEnvWindow     = viewInEnvWindow;
     _output              = output;
     _statusCenter        = _site.GetService(typeof(SVsTaskStatusCenterService)) as IVsTaskStatusCenterService;
     _registry            = _site.GetComponentModel().GetService <IInterpreterRegistryService>();
     _options             = _site.GetComponentModel().GetService <IInterpreterOptionsService>();
     _logger              = _site.GetService(typeof(IPythonToolsLogger)) as IPythonToolsLogger;
 }
示例#25
0
        private void InitializeCurrentContext()
        {
            var workspace = _workspaceService.CurrentWorkspace;

            if (workspace != null)
            {
                var context = new PythonWorkspaceContext(workspace, _optionsService.Value, _registryService.Value);

                // Workspace interpreter factory provider will rescan the
                // workspace folder for factories.
                WorkspaceOpening?.Invoke(this, new PythonWorkspaceContextEventArgs(context));

                // Workspace sets its interpreter factory instance,
                // now that they've been discovered by the factory provider.
                context.Initialize();

                lock (_currentContextLock) {
                    _currentContext = context;
                }

                // Let users know this workspace context is all initialized
                WorkspaceInitialized?.Invoke(this, new PythonWorkspaceContextEventArgs(context));
            }
        }
示例#26
0
 public TestFrameworkWorkspaceInfoBar(IServiceProvider site, IPythonWorkspaceContext pythonWorkspaceContext) : base(site)
 {
     WorkspaceContext = pythonWorkspaceContext ?? throw new ArgumentNullException(nameof(pythonWorkspaceContext));
 }
示例#27
0
 internal static IVsInteractiveWindow /*!*/ EnsureReplWindow(IServiceProvider serviceProvider, VsProjectAnalyzer analyzer, PythonProjectNode project, IPythonWorkspaceContext workspace)
 {
     return(EnsureReplWindow(serviceProvider, analyzer.InterpreterFactory.Configuration, project, workspace));
 }
示例#28
0
 public VirtualEnvCreateWorkspaceInfoBar(IServiceProvider site, IPythonWorkspaceContext workspace)
     : base(site)
 {
     Workspace = workspace ?? throw new ArgumentNullException(nameof(workspace));
 }
示例#29
0
 public MockWorkspaceContextProvider(IPythonWorkspaceContext workspaceContext)
 {
     Workspace = workspaceContext;
 }
示例#30
0
        internal static IVsInteractiveWindow /*!*/ EnsureReplWindow(IServiceProvider serviceProvider, InterpreterConfiguration config, PythonProjectNode project, IPythonWorkspaceContext workspace)
        {
            var compModel        = serviceProvider.GetComponentModel();
            var provider         = compModel.GetService <InteractiveWindowProvider>();
            var vsProjectContext = compModel.GetService <VsProjectContextProvider>();

            var projectId = project != null?PythonReplEvaluatorProvider.GetEvaluatorId(project) : null;

            var workspaceId = workspace != null?PythonReplEvaluatorProvider.GetEvaluatorId(workspace) : null;

            var configId = config != null?PythonReplEvaluatorProvider.GetEvaluatorId(config) : null;

            if (config?.IsRunnable() == false)
            {
                throw new MissingInterpreterException(
                          Strings.MissingEnvironment.FormatUI(config.Description, config.Version)
                          );
            }

            IVsInteractiveWindow window;

            // If we find an open window for the project, prefer that to a per-config one
            if (!string.IsNullOrEmpty(projectId))
            {
                window = provider.Open(
                    projectId,
                    e => ((e as SelectableReplEvaluator)?.Evaluator as PythonCommonInteractiveEvaluator)?.AssociatedProjectHasChanged != true
                    );
                if (window != null)
                {
                    return(window);
                }
            }

            // If we find an open window for the workspace, prefer that to a per config one
            if (!string.IsNullOrEmpty(workspaceId))
            {
                window = provider.Open(
                    workspaceId,
                    e => ((e as SelectableReplEvaluator)?.Evaluator as PythonCommonInteractiveEvaluator)?.AssociatedWorkspaceHasChanged != true
                    );
                if (window != null)
                {
                    return(window);
                }
            }

            // If we find an open window for the configuration, return that
            if (!string.IsNullOrEmpty(configId))
            {
                window = provider.Open(configId);
                if (window != null)
                {
                    return(window);
                }
            }

            // No window found, so let's create one
            if (!string.IsNullOrEmpty(projectId))
            {
                window = provider.Create(projectId);
                project.AddActionOnClose(window, w => InteractiveWindowProvider.CloseIfEvaluatorMatches(w, projectId));
            }
            else if (!string.IsNullOrEmpty(workspaceId))
            {
                window = provider.Create(workspaceId);
                workspace.AddActionOnClose(window, w => InteractiveWindowProvider.CloseIfEvaluatorMatches(w, workspaceId));
            }
            else if (!string.IsNullOrEmpty(configId))
            {
                window = provider.Create(configId);
            }
            else
            {
                var interpService = compModel.GetService <IInterpreterOptionsService>();
                window = provider.Create(PythonReplEvaluatorProvider.GetEvaluatorId(interpService.DefaultInterpreter.Configuration));
            }

            return(window);
        }