From 69f871f08950d5bf7264c92a6a2a1e8cfd053201 Mon Sep 17 00:00:00 2001 From: Ilia Zakoulov Date: Mon, 31 Aug 2026 14:36:32 +0200 Subject: [PATCH] PY-91932: do not claim a notebook when the non-modal Welcome screen is off PyCharm failed with `NoProjectStateHandler not found, but it must be registered` when a user opened an .ipynb file from Finder while the IDE was not running. Two gates disagreed. The provider claimed the file from the registry key `welcome.screen.open.files`, which defaults to true. The only registered `NoProjectStateHandler` declines when the advanced setting `welcome.screen.non.modal.enabled` is off, so the `requireNotNull` threw. PY-89419 made this reachable, because it writes that setting to false for a paying user. The provider now checks the setting too. A paying user gets the default file opening path instead of the Welcome screen project. The test module needs `intellij.platform.welcomeScreen` to instantiate the provider. This fix is for 262 only. IJPL-249071 removed the handler call on master, so master opens the Welcome screen project for every user and must not get this gate. (cherry picked from commit 8b180e632c3832fd7bdf34e26bbfdbc931e5e5ab) IJ-MR-221009 GitOrigin-RevId: 388058443109958124cd6d61297003c4ec56969a --- python/ide/impl/BUILD.bazel | 2 + ...ellij.pycharm.community.ide.impl.tests.iml | 1 + .../PyCharmWelcomeScreenProjectProvider.kt | 9 ++- ...ellij.pycharm.community.ide.impl.tests.xml | 1 + ...PyCharmWelcomeScreenProjectProviderTest.kt | 60 +++++++++++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 python/ide/impl/tests/com/intellij/python/junit5Tests/unit/PyCharmWelcomeScreenProjectProviderTest.kt diff --git a/python/ide/impl/BUILD.bazel b/python/ide/impl/BUILD.bazel index 4aadedaa1625..c68bd55f2e82 100644 --- a/python/ide/impl/BUILD.bazel +++ b/python/ide/impl/BUILD.bazel @@ -346,6 +346,8 @@ jvm_library( "//libraries/kotlinx/collections-immutable:libraries-kotlinx-collections-immutable_test_lib", "//platform/util/concurrency", "//platform/util/concurrency:concurrency_test_lib", + "//platform/welcome-screen", + "//platform/welcome-screen:welcome-screen_test_lib", ], ) ### auto-generated section `build intellij.pycharm.community.ide.impl.tests` end diff --git a/python/ide/impl/intellij.pycharm.community.ide.impl.tests.iml b/python/ide/impl/intellij.pycharm.community.ide.impl.tests.iml index 0a8f70b0cb5c..233a8312afe6 100644 --- a/python/ide/impl/intellij.pycharm.community.ide.impl.tests.iml +++ b/python/ide/impl/intellij.pycharm.community.ide.impl.tests.iml @@ -97,6 +97,7 @@ + \ No newline at end of file diff --git a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/welcomeScreen/PyCharmWelcomeScreenProjectProvider.kt b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/welcomeScreen/PyCharmWelcomeScreenProjectProvider.kt index fa3f0e082c1c..1d39a015bc86 100644 --- a/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/welcomeScreen/PyCharmWelcomeScreenProjectProvider.kt +++ b/python/ide/impl/src/com/intellij/pycharm/community/ide/impl/welcomeScreen/PyCharmWelcomeScreenProjectProvider.kt @@ -7,6 +7,7 @@ import com.intellij.openapi.project.ex.ProjectEx import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.wm.ex.WelcomeScreenProjectProvider import com.intellij.platform.PlatformProjectOpenProcessor +import com.intellij.platform.ide.nonModalWelcomeScreen.isNonModalWelcomeScreenEnabled import com.intellij.pycharm.community.ide.impl.miscProject.impl.MISC_PROJECT_WITH_WELCOME_NAME import com.intellij.pycharm.community.ide.impl.miscProject.impl.miscProjectDefaultPath import com.jetbrains.python.orLogException @@ -38,8 +39,14 @@ internal class PyCharmWelcomeScreenProjectProvider : WelcomeScreenProjectProvide // We explicitly want to open existing project if the file already belongs to it override fun shouldOpenInWelcomeScreenIfFileBelongsToProject(filePath: Path): Boolean = false + /** + * The non-modal Welcome screen must be on. The file opening path creates the Welcome screen project through + * [com.intellij.openapi.wm.ex.NoProjectStateHandler], and the only handler declines when the setting is off. + */ override fun canOpenFilesFromSystemFileManager(filePath: Path): Boolean { - return Registry.`is`("welcome.screen.open.files", false) && filePath.extension == "ipynb" + return isNonModalWelcomeScreenEnabled && + Registry.`is`("welcome.screen.open.files", false) && + filePath.extension == "ipynb" } override suspend fun doCreateOrOpenWelcomeScreenProject(path: Path): Project { diff --git a/python/ide/impl/testResources/intellij.pycharm.community.ide.impl.tests.xml b/python/ide/impl/testResources/intellij.pycharm.community.ide.impl.tests.xml index b2a1ad91dc55..c8829469e9aa 100644 --- a/python/ide/impl/testResources/intellij.pycharm.community.ide.impl.tests.xml +++ b/python/ide/impl/testResources/intellij.pycharm.community.ide.impl.tests.xml @@ -28,6 +28,7 @@ + \ No newline at end of file diff --git a/python/ide/impl/tests/com/intellij/python/junit5Tests/unit/PyCharmWelcomeScreenProjectProviderTest.kt b/python/ide/impl/tests/com/intellij/python/junit5Tests/unit/PyCharmWelcomeScreenProjectProviderTest.kt new file mode 100644 index 000000000000..b683dd0b22cc --- /dev/null +++ b/python/ide/impl/tests/com/intellij/python/junit5Tests/unit/PyCharmWelcomeScreenProjectProviderTest.kt @@ -0,0 +1,60 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.python.junit5Tests.unit + +import com.intellij.openapi.options.advanced.AdvancedSettings +import com.intellij.platform.ide.nonModalWelcomeScreen.NON_MODAL_WELCOME_SCREEN_SETTING_ID +import com.intellij.pycharm.community.ide.impl.welcomeScreen.PyCharmWelcomeScreenProjectProvider +import com.intellij.testFramework.junit5.RegistryKey +import com.intellij.testFramework.junit5.SystemProperty +import com.intellij.testFramework.junit5.TestApplication +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir +import java.nio.file.Path + +/** + * The two gates must agree. If the provider claims a file while the non-modal Welcome screen is off, + * the file opening path finds no `NoProjectStateHandler` and the IDE fails with an internal error (PY-91932). + */ +@TestApplication +@SystemProperty(propertyKey = "idea.force.disable.non.modal.welcome.screen", propertyValue = "false") +internal class PyCharmWelcomeScreenProjectProviderTest { + private val provider = PyCharmWelcomeScreenProjectProvider() + + @Test + @RegistryKey(key = "welcome.screen.open.files", value = "true") + fun `notebook is claimed when both settings are enabled`(@TempDir tempDir: Path) = withNonModalWelcomeScreen(true) { + assertTrue(provider.canOpenFilesFromSystemFileManager(tempDir.resolve("notebook.ipynb"))) + } + + @Test + @RegistryKey(key = "welcome.screen.open.files", value = "true") + fun `notebook is not claimed when the non-modal welcome screen is disabled`(@TempDir tempDir: Path) = withNonModalWelcomeScreen(false) { + assertFalse(provider.canOpenFilesFromSystemFileManager(tempDir.resolve("notebook.ipynb"))) + } + + @Test + @RegistryKey(key = "welcome.screen.open.files", value = "false") + fun `notebook is not claimed when the registry key is disabled`(@TempDir tempDir: Path) = withNonModalWelcomeScreen(true) { + assertFalse(provider.canOpenFilesFromSystemFileManager(tempDir.resolve("notebook.ipynb"))) + } + + @Test + @RegistryKey(key = "welcome.screen.open.files", value = "true") + fun `a file that is not a notebook is not claimed`(@TempDir tempDir: Path) = withNonModalWelcomeScreen(true) { + assertFalse(provider.canOpenFilesFromSystemFileManager(tempDir.resolve("script.py"))) + assertFalse(provider.canOpenFilesFromSystemFileManager(tempDir)) + } + + private fun withNonModalWelcomeScreen(value: Boolean, action: () -> Unit) { + val previousValue = AdvancedSettings.getBoolean(NON_MODAL_WELCOME_SCREEN_SETTING_ID) + try { + AdvancedSettings.setBoolean(NON_MODAL_WELCOME_SCREEN_SETTING_ID, value) + action() + } + finally { + AdvancedSettings.setBoolean(NON_MODAL_WELCOME_SCREEN_SETTING_ID, previousValue) + } + } +}