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
This commit is contained in:
Ilia Zakoulov
2026-09-01 17:55:39 +00:00
committed by intellij-monorepo-bot
parent 3b05873be2
commit 69f871f089
5 changed files with 72 additions and 1 deletions
+2
View File
@@ -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
@@ -97,6 +97,7 @@
<orderEntry type="module" module-name="intellij.libraries.kotlinx.collections.immutable" scope="TEST" />
<orderEntry type="module" module-name="intellij.platform.concurrency" scope="TEST" />
<orderEntry type="module" module-name="intellij.pycharm.community.ide.impl" scope="TEST" />
<orderEntry type="module" module-name="intellij.platform.welcomeScreen" scope="TEST" />
</component>
<component name="TestModuleProperties" production-module="intellij.pycharm.community.ide.impl" />
</module>
@@ -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 {
@@ -28,6 +28,7 @@
<module name="intellij.platform.usageView"/>
<module name="intellij.platform.usageView.impl"/>
<module name="intellij.platform.util.coroutines"/>
<module name="intellij.platform.welcomeScreen"/>
</dependencies>
<!-- endregion -->
</idea-plugin>
@@ -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)
}
}
}