[debugger] PY-87450 add debugpy justMyCode checkbox for python configurations, where it is supported

Merge-request: IJ-MR-190905
Merged-by: Maxim Popov <maxim.popov@jetbrains.com>

GitOrigin-RevId: b34a0edf0c89ffd1967516810e0160c5f0cb0fce
This commit is contained in:
Maxim Popov
2026-02-10 21:12:30 +00:00
committed by intellij-monorepo-bot
parent b71085c21e
commit a45f149b8a
10 changed files with 106 additions and 1 deletions
@@ -1,6 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.pycharm.community.ide.impl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
@@ -15,6 +16,7 @@ import com.intellij.ui.CollectionComboBoxModel;
import com.intellij.util.PathMappingSettings;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.jetbrains.python.run.AbstractPyCommonOptionsForm;
import com.jetbrains.python.run.PyCommonOptionsFormData;
import com.jetbrains.python.sdk.PySdkListCellRenderer;
@@ -46,6 +48,7 @@ public class PyIdeCommonOptionsForm implements AbstractPyCommonOptionsForm {
private final List<Consumer<Boolean>> myRemoteInterpreterModeListeners = new ArrayList<>();
private static final Logger LOG = Logger.getInstance(PyIdeCommonOptionsForm.class);
public PyIdeCommonOptionsForm(PyCommonOptionsFormData data) {
myProject = data.getProject();
@@ -269,6 +272,16 @@ public class PyIdeCommonOptionsForm implements AbstractPyCommonOptionsForm {
content.addSourceRootsCheckbox.setSelected(flag);
}
@Override
public boolean shouldDebugJustMyCode() {
return false;
}
@Override
public void setDebugJustMyCode(boolean flag) {
LOG.warn("Tried to set debugJustMyCode flag for common options form, which is an unsupported operation");
}
private void setRemoteInterpreterMode(boolean isInterpreterRemote) {
myInterpreterRemote = isInterpreterRemote;
}
@@ -1,6 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.python.community.plugin.impl.run;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
@@ -40,6 +41,8 @@ public class PyPluginCommonOptionsForm implements AbstractPyCommonOptionsForm {
private final List<Consumer<Boolean>> myRemoteInterpreterModeListeners = new ArrayList<>();
private static final Logger LOG = Logger.getInstance(PyPluginCommonOptionsForm.class);
public PyPluginCommonOptionsForm(PyCommonOptionsFormData data) {
// setting modules
myProject = data.getProject();
@@ -278,6 +281,16 @@ public class PyPluginCommonOptionsForm implements AbstractPyCommonOptionsForm {
content.addSourceRootsCheckbox.setSelected(flag);
}
@Override
public void setDebugJustMyCode(boolean flag) {
LOG.warn("Tried to set debugJustMyCode flag for common options form, which is an unsupported operation");
}
@Override
public boolean shouldDebugJustMyCode() {
return false;
}
@Override
public @NotNull List<String> getEnvFilePaths() {
return myEnvPaths;
@@ -1251,6 +1251,8 @@ python.debugger.settings.waiting.for.connection=Waiting for connection\u2026
python.debugger.settings.connecting.to.debugger=Connecting to debugger
python.debugger.attaching.to.process.with.pid=Attaching to a process with PID={0}
python.debugger.attaching=Attaching Debugger
python.debugger.configuration.group=Debug
python.debugger.configuration.justMyCode.label=Debug just my code
python.rename.processor.override.message=Method {0} of class {1}\noverrides method of class {2}.\nDo you want to rename the base method?
python.rename.processor.property=Do you want to rename the property ''{0}'' instead of its accessor function ''{1}''?
python.configuration.choose.target.to.run=Choose the target to run
@@ -22,6 +22,7 @@ import com.jetbrains.python.console.actions.CommandQueueForPythonConsoleService;
import com.jetbrains.python.run.AbstractPyCommonOptionsForm;
import com.jetbrains.python.run.AbstractPythonRunConfigurationParams;
import com.jetbrains.python.run.PythonRunParams;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -144,6 +145,7 @@ public class PyConsoleOptions implements PersistentStateComponent<PyConsoleOptio
public boolean myAddSourceRoots = true;
private @NotNull PathMappingSettings myMappings = new PathMappingSettings();
private boolean myUseSoftWraps = false;
private boolean myDebugJustMyCode = false;
public PyConsoleSettings() {
}
@@ -350,6 +352,18 @@ public class PyConsoleOptions implements PersistentStateComponent<PyConsoleOptio
myAddSourceRoots = addSourceRoots;
}
@Override
@ApiStatus.Internal
public boolean shouldDebugJustMyCode() {
return myDebugJustMyCode;
}
@Override
@ApiStatus.Internal
public void setDebugJustMyCode(boolean debugJustMyCode) {
myDebugJustMyCode = debugJustMyCode;
}
public void setMappings(@Nullable PathMappingSettings mappings) {
myMappings = mappings != null ? mappings : new PathMappingSettings();
}
@@ -1329,6 +1329,16 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner {
throw new UnsupportedOperationException();
}
@Override
public boolean shouldDebugJustMyCode() {
return myConsoleSettings.shouldDebugJustMyCode();
}
@Override
public void setDebugJustMyCode(boolean flag) {
LOG.warn("Tried to set debugJustMyCode flag for PythonConsoleRunParams, which is an unsupported operation");
}
@Override
public @NotNull List<String> getEnvFilePaths() {
return myEnvFiles;
@@ -64,6 +64,7 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractPythonRun
private boolean myUseModuleSdk;
private boolean myAddContentRoots = true;
private boolean myAddSourceRoots = true;
private boolean myDebugJustMyCode = false;
protected PathMappingSettings myMappingSettings;
/**
@@ -286,6 +287,9 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractPythonRun
myAddContentRoots = addContentRoots == null || Boolean.parseBoolean(addContentRoots);
final String addSourceRoots = JDOMExternalizerUtil.readField(element, "ADD_SOURCE_ROOTS");
myAddSourceRoots = addSourceRoots == null || Boolean.parseBoolean(addSourceRoots);
final String debugJustMyCode = JDOMExternalizerUtil.readField(element, "DEBUG_JUST_MY_CODE");
myDebugJustMyCode = debugJustMyCode == null || Boolean.parseBoolean(debugJustMyCode);
if (!mySkipModuleSerialization) {
getConfigurationModule().readExternal(element);
}
@@ -319,6 +323,7 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractPythonRun
JDOMExternalizerUtil.writeField(element, "IS_MODULE_SDK", Boolean.toString(myUseModuleSdk));
JDOMExternalizerUtil.writeField(element, "ADD_CONTENT_ROOTS", Boolean.toString(myAddContentRoots));
JDOMExternalizerUtil.writeField(element, "ADD_SOURCE_ROOTS", Boolean.toString(myAddSourceRoots));
JDOMExternalizerUtil.writeField(element, "DEBUG_JUST_MY_CODE", Boolean.toString(myDebugJustMyCode));
if (!mySkipModuleSerialization) {
getConfigurationModule().writeExternal(element);
}
@@ -416,6 +421,7 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractPythonRun
target.setAddContentRoots(source.shouldAddContentRoots());
target.setAddSourceRoots(source.shouldAddSourceRoots());
target.setUseRunTool(source.getUseRunTool());
target.setDebugJustMyCode(source.shouldDebugJustMyCode());
}
/**
@@ -520,6 +526,19 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractPythonRun
return false;
}
@Override
@ApiStatus.Internal
public boolean shouldDebugJustMyCode() {
return myDebugJustMyCode;
}
@Override
@ApiStatus.Internal
public void setDebugJustMyCode(boolean debugJustMyCode) {
myDebugJustMyCode = debugJustMyCode;
}
/**
* Adds test specs (like method, class, script, etc) to list of runner parameters.
* <p>
@@ -5,6 +5,7 @@ import com.intellij.execution.EnvFilesOptions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.util.PathMappingSettings;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
@@ -69,4 +70,10 @@ public interface PythonRunParams extends EnvFilesOptions {
void setAddContentRoots(boolean flag);
void setAddSourceRoots(boolean flag);
@ApiStatus.Internal
void setDebugJustMyCode(boolean flag);
@ApiStatus.Internal
boolean shouldDebugJustMyCode();
}
@@ -38,6 +38,8 @@ abstract class AbstractPythonConfigurationFragmentedEditor<T : AbstractPythonRun
addInterpreterOptions(fragments)
addContentSourceRoots(fragments)
addDebuggerOptions(fragments)
runConfiguration.sdk?.takeIf { enableRunTool }
?.let { createRunToolTag(it) }
?.let { fragments.add(it) }
@@ -85,6 +87,18 @@ abstract class AbstractPythonConfigurationFragmentedEditor<T : AbstractPythonRun
fragments.add(interpreterOptionsFragment)
}
private fun <T : AbstractPythonRunConfiguration<*>> addDebuggerOptions(fragments: MutableList<SettingsEditorFragment<T, *>>) {
val justMyCodeElement = SettingsEditorFragment.createTag<T>(
"justMyCode",
PyBundle.message("python.debugger.configuration.justMyCode.label"),
PyBundle.message("python.debugger.configuration.group"),
{ runConfiguration.shouldDebugJustMyCode() },
{ config, value -> config.setDebugJustMyCode(value) }
)
justMyCodeElement.isSelected = runConfiguration.shouldDebugJustMyCode()
fragments.add(justMyCodeElement)
}
private fun <T : AbstractPythonRunConfiguration<*>> addContentSourceRoots(fragments: MutableList<SettingsEditorFragment<T, *>>) {
val addContentRoots = SettingsEditorFragment.createTag<T>(
"py.add.content.roots",
@@ -38,7 +38,8 @@ data class UvRunConfigurationOptions(
var env: Map<String, String> = mapOf(),
var checkSync: Boolean = true,
var uvSdkKey: String? = null,
var uvArgs: List<String> = listOf()
var uvArgs: List<String> = listOf(),
var debugJustMyCode: Boolean = false
) {
val uvSdk: Sdk?
get() = uvSdkKey?.let { PythonSdkUtil.findSdkByKey(it)}
@@ -82,6 +83,10 @@ class UvRunConfiguration(
override fun getSdk(): Sdk? {
return options.uvSdk
}
override fun shouldDebugJustMyCode(): Boolean {
return options.debugJustMyCode
}
}
@ApiStatus.Internal
@@ -46,6 +46,8 @@ internal class UvRunSettingsEditor() : SettingsEditor<UvRunConfiguration>() {
private lateinit var uvSdkField: ComboBox<Sdk?>
private val uvArgsField: RawCommandLineEditor = RawCommandLineEditor().withMonospaced(true)
private lateinit var debugJustMyCodeCheckbox: JBCheckBox
private val propertyGraph = PropertyGraph()
private val isScript = propertyGraph.property(true)
private val isModule = propertyGraph.property(false)
@@ -127,6 +129,10 @@ internal class UvRunSettingsEditor() : SettingsEditor<UvRunConfiguration>() {
cell(uvArgsField)
.align(AlignX.FILL)
}
row {
debugJustMyCodeCheckbox = checkBox(PyBundle.message("python.debugger.configuration.justMyCode.label"))
.component
}
}
}
@@ -138,6 +144,7 @@ internal class UvRunSettingsEditor() : SettingsEditor<UvRunConfiguration>() {
scriptCheckSyncField.isSelected = uvRunConfiguration.options.checkSync
uvSdkField.selectedItem = uvRunConfiguration.options.uvSdk
uvArgsField.text = uvRunConfiguration.options.uvArgs.joinToString(" ")
debugJustMyCodeCheckbox.isSelected = uvRunConfiguration.options.debugJustMyCode
}
override fun applyEditorTo(uvRunConfiguration: UvRunConfiguration) {
@@ -153,6 +160,7 @@ internal class UvRunSettingsEditor() : SettingsEditor<UvRunConfiguration>() {
uvRunConfiguration.options.checkSync = scriptCheckSyncField.isSelected
uvRunConfiguration.options.uvSdkKey = uvSdkField.selectedItem.let {it as? Sdk}?.name
uvRunConfiguration.options.uvArgs = uvArgsField.text.splitParams()
uvRunConfiguration.options.debugJustMyCode = debugJustMyCodeCheckbox.isSelected
}
override fun createEditor(): JComponent = panel