sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=VULNERABILITY) (and [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=SECURITY_HOTSPOT) to review)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/100.png' alt='100.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_coverage&view=list) [100.0% Coverage](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_coverage&view=list)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='0.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=VULNERABILITY) (and [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=SECURITY_HOTSPOT) to review)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/100.png' alt='100.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_coverage&view=list) [100.0% Coverage](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_coverage&view=list)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='0.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=VULNERABILITY) (and [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=SECURITY_HOTSPOT) to review)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=103&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/100.png' alt='100.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_coverage&view=list) [100.0% Coverage](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_coverage&view=list)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='0.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=103&metric=new_duplicated_lines_density&view=list)


diff --git a/src/debugpy/adapter/clients.py b/src/debugpy/adapter/clients.py
index 9ece52da..0acc1e13 100644
--- a/src/debugpy/adapter/clients.py
+++ b/src/debugpy/adapter/clients.py
@@ -305,7 +305,9 @@ class Client(components.Component):
             raise request.cant_handle('"sudo":true is not supported on Windows.')
 
         servers.serve()
-        launchers.spawn_debuggee(self.session, request, args, console, console_title, sudo)
+        launchers.spawn_debuggee(
+            self.session, request, args, console, console_title, sudo
+        )
 
     @_start_message_handler
     def attach_request(self, request):
@@ -499,8 +501,9 @@ class Client(components.Component):
             body = dict(self.start_request.arguments)
             self._known_subprocesses.add(conn)
 
-        body.pop("processId", None)
-        body.pop("listen", None)
+        for key in "processId", "listen", "preLaunchTask", "postDebugTask":
+            body.pop(key, None)
+
         body["name"] = fmt("Subprocess {0}", conn.pid)
         body["request"] = "attach"
         body["subProcessId"] = conn.pid

multiprocessing triggers preLaunchTask and postDebugTask more than once
## Environment data

- DEBUGPY version: 1.0.0b4
- OS and version: ubuntu18.04
- Python version (& distribution if applicable, e.g. Anaconda): Python 3.6.9
- Using VS Code or Visual Studio:VS Code

## Actual behavior

When I launch a simple program that involves `multiprocessing`, upon firing of another process, the preLaunchTask runs more than one time (once per process as I understand). Same goes for the postDebugTask, which seems to run more than one time. 

## Expected  behavior

The `preLaunchTask` should run once only, as well as the `postDebugTask`.

## Steps to reproduce:
1. Get this in `launch.json` :
```
        {
            "name": "Python: mp.py",
            "type": "python",
            "request": "launch",
            "preLaunchTask": "testStartTask",
            "program": "${workspaceFolder}/testing_code/mp.py",
            "console": "integratedTerminal",
            "debugAdapterPath": "/home/omartin/proj/debugpy/src/debugpy/adapter",
            "postDebugTask": "testStopTask"
        }
```
2. Get this in `tasks.json`:
```
        {
            "label": "testStartTask",
            "type": "shell",
            "isBackground": false,
            "command":[
                "echo helloStart `date`"
            ],
            "options": {
                "shell": {
                    "executable": "/bin/bash",
                    "args": [
                        "-c"
                    ]
                }
            },
            "problemMatcher": [
                "$eslint-compact"
            ]
        },
        {
            "label": "testStopTask",
            "type": "shell",
            "isBackground": false,
            "command":[
                "echo helloStop `date`"
            ],
            "options": {
                "shell": {
                    "executable": "/bin/bash",
                    "args": [
                        "-c"
                    ]
                }
            },
            "problemMatcher": [
                "$eslint-compact"
            ]
        },
```
3. `mp.py` looks like this
```
from multiprocessing import Pool
import traceback


def f(x):
    return x * x


if __name__ == '__main__':
    # start 4 worker processes
    try:
        with Pool(processes=4) as pool:

            # print "[0, 1, 4,..., 81]"
            print(pool.map(f, range(10)))
            print("For the moment, the pool remains available for more work")

    except:
        print(traceback.print_exc())
    # exiting the 'with'-block has stopped the pool
    print("Now the pool is closed and no longer available")

```
I also needed the fix for `connection refused error` that I have in my version of `debug.py`.

It seems, by the output of this, that when my process forks, it runs the `preLaunchTask` a 2nd time, but for each process that terminates (4 in this example), it runs the `postDebugTask`.
diff --git a/tests/debug/config.py b/tests/debug/config.py
index d6203b54..c2582361 100644
--- a/tests/debug/config.py
+++ b/tests/debug/config.py
@@ -39,6 +39,8 @@ class DebugConfig(collections.MutableMapping):
         "name": (),
         "noDebug": False,
         "pathMappings": [],
+        "postDebugTask": (),
+        "preLaunchTask": (),
         "pyramid": False,
         "pythonPath": (),
         "redirectOutput": False,
diff --git a/tests/debugpy/test_multiproc.py b/tests/debugpy/test_multiproc.py
index 0a0f86bb..f8d67749 100644
--- a/tests/debugpy/test_multiproc.py
+++ b/tests/debugpy/test_multiproc.py
@@ -15,6 +15,7 @@ from tests.patterns import some
 
 
 if not tests.full:
+
     @pytest.fixture(params=[runners.launch] + runners.all_attach_socket)
     def run(request):
         return request.param
@@ -120,10 +121,7 @@ def test_multiprocessing(pyfile, target, run, start_method):
                 "name": some.str,
                 "request": "attach",
                 "subProcessId": some.int,
-                "connect": {
-                    "host": some.str,
-                    "port": some.int,
-                }
+                "connect": {"host": some.str, "port": some.int},
             }
         )
 
@@ -142,10 +140,7 @@ def test_multiprocessing(pyfile, target, run, start_method):
                     "name": some.str,
                     "request": "attach",
                     "subProcessId": some.int,
-                    "connect": {
-                        "host": some.str,
-                        "port": some.int,
-                    }
+                    "connect": {"host": some.str, "port": some.int},
                 }
             )
 
@@ -196,6 +191,9 @@ def test_subprocess(pyfile, target, run, subProcess):
 
     with debug.Session() as parent_session:
         backchannel = parent_session.open_backchannel()
+
+        parent_session.config["preLaunchTask"] = "doSomething"
+        parent_session.config["postDebugTask"] = "doSomethingElse"
         if subProcess is not None:
             parent_session.config["subProcess"] = subProcess
 
@@ -203,16 +201,14 @@ def test_subprocess(pyfile, target, run, subProcess):
             pass
 
         expected_child_config = dict(parent_session.config)
-        expected_child_config.pop("listen", None)
+        for key in "processId", "listen", "preLaunchTask", "postDebugTask":
+            expected_child_config.pop(key, None)
         expected_child_config.update(
             {
                 "name": some.str,
                 "request": "attach",
                 "subProcessId": some.int,
-                "connect": {
-                    "host": some.str,
-                    "port": some.int,
-                }
+                "connect": {"host": some.str, "port": some.int},
             }
         )
 

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio
apt-get update apt-get install -y gcc
3.8
tests/requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
asgiref==3.8.1
atomicwrites==1.4.1
attrs==25.3.0
backports.zoneinfo==0.2.1
certifi==2025.1.31
charset-normalizer==3.4.1
click==8.1.8
coverage==7.6.1
-e git+https://github.com/microsoft/debugpy.git@32c00bc85c284791e9e55b74885b6825b9ef111e#egg=debugpy
distlib==0.3.9
Django==4.2.20
exceptiongroup==1.2.2
execnet==2.1.1
filelock==3.16.1
Flask==1.0.3
gevent==24.2.1
greenlet==3.1.1
idna==3.10
iniconfig==2.1.0
itsdangerous==2.2.0
Jinja2==3.1.6
MarkupSafe==2.1.5
more-itertools==10.5.0
packaging==24.2
platformdirs==4.3.6
pluggy==1.5.0
psutil==7.0.0
py==1.11.0
pytest==8.3.5
pytest-asyncio==0.24.0
pytest-cov==5.0.0
pytest-forked==1.6.0
pytest-mock==3.14.0
pytest-timeout==1.4.2
pytest-xdist==1.34.0
requests==2.32.3
six==1.17.0
sqlparse==0.5.3
tomli==2.2.1
tox==3.28.0
typing_extensions==4.13.0
urllib3==2.2.3
virtualenv==20.29.3
wcwidth==0.2.13
Werkzeug==3.0.6
zope.event==5.0
zope.interface==7.2

name: debugpy
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=24.2=py38h06a4308_0
  - python=3.8.20=he870216_0
  - readline=8.2=h5eee18b_0
  - setuptools=75.1.0=py38h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.44.0=py38h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - asgiref==3.8.1
      - atomicwrites==1.4.1
      - attrs==25.3.0
      - backports-zoneinfo==0.2.1
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - click==8.1.8
      - coverage==7.6.1
      - debugpy==1.0.0b5
      - distlib==0.3.9
      - django==4.2.20
      - exceptiongroup==1.2.2
      - execnet==2.1.1
      - filelock==3.16.1
      - flask==1.0.3
      - gevent==24.2.1
      - greenlet==3.1.1
      - idna==3.10
      - iniconfig==2.1.0
      - itsdangerous==2.2.0
      - jinja2==3.1.6
      - markupsafe==2.1.5
      - more-itertools==10.5.0
      - packaging==24.2
      - platformdirs==4.3.6
      - pluggy==1.5.0
      - psutil==7.0.0
      - py==1.11.0
      - pytest==8.3.5
      - pytest-asyncio==0.24.0
      - pytest-cov==5.0.0
      - pytest-forked==1.6.0
      - pytest-mock==3.14.0
      - pytest-timeout==1.4.2
      - pytest-xdist==1.34.0
      - requests==2.32.3
      - six==1.17.0
      - sqlparse==0.5.3
      - tomli==2.2.1
      - tox==3.28.0
      - typing-extensions==4.13.0
      - urllib3==2.2.3
      - virtualenv==20.29.3
      - wcwidth==0.2.13
      - werkzeug==3.0.6
      - zope-event==5.0
      - zope-interface==7.2
prefix: /opt/conda/envs/debugpy

tests/debugpy/test_multiproc.py::test_subprocess[program-launch-True] tests/debugpy/test_multiproc.py::test_subprocess[program-launch-None] tests/debugpy/test_multiproc.py::test_subprocess[program-attach_listen(cli)-None] tests/debugpy/test_multiproc.py::test_subprocess[program-attach_connect(api)-True] tests/debugpy/test_multiproc.py::test_subprocess[program-attach_listen(cli)-True] tests/debugpy/test_multiproc.py::test_subprocess[program-attach_listen(api)-True] tests/debugpy/test_multiproc.py::test_subprocess[program-attach_listen(api)-None] tests/debugpy/test_multiproc.py::test_subprocess[program-attach_connect(api)-None] tests/debugpy/test_multiproc.py::test_subprocess[program-attach_connect(cli)-True] tests/debugpy/test_multiproc.py::test_subprocess[program-attach_connect(cli)-None]
tests/debugpy/test_multiproc.py::test_subprocess[program-attach_listen(api)-False] tests/debugpy/test_multiproc.py::test_subprocess[program-attach_listen(cli)-False] tests/debugpy/test_multiproc.py::test_multiprocessing[program-attach_listen(api)-fork] tests/debugpy/test_multiproc.py::test_multiprocessing[program-attach_listen(cli)-fork] tests/debugpy/test_multiproc.py::test_multiprocessing[program-launch-fork] tests/debugpy/test_multiproc.py::test_multiprocessing[program-attach_connect(api)-fork] tests/debugpy/test_multiproc.py::test_subprocess[program-attach_connect(api)-False] tests/debugpy/test_multiproc.py::test_subprocess[program-launch-False] tests/debugpy/test_multiproc.py::test_autokill[program] tests/debugpy/test_multiproc.py::test_subprocess[program-attach_connect(cli)-False] tests/debugpy/test_multiproc.py::test_multiprocessing[program-attach_connect(cli)-fork] tests/debugpy/test_multiproc.py::test_echo_and_shell[program-attach_listen(api)] tests/debugpy/test_multiproc.py::test_echo_and_shell[program-launch] tests/debugpy/test_multiproc.py::test_argv_quoting[program-attach_listen(api)] tests/debugpy/test_multiproc.py::test_echo_and_shell[program-attach_connect(cli)] tests/debugpy/test_multiproc.py::test_echo_and_shell[program-attach_connect(api)] tests/debugpy/test_multiproc.py::test_argv_quoting[program-launch] tests/debugpy/test_multiproc.py::test_argv_quoting[program-attach_listen(cli)] tests/debugpy/test_multiproc.py::test_argv_quoting[program-attach_connect(api)] tests/debugpy/test_multiproc.py::test_argv_quoting[program-attach_connect(cli)] tests/debugpy/test_multiproc.py::test_echo_and_shell[program-attach_listen(cli)]
src/debugpy/adapter/clients.py
src/debugpy/adapter/clients.py