Konubinix' opinionated web of thoughts

Debug a Python Test Using DAP and Emacs

fleeting

I need

  • a DAP implementation in python,
  • a way to run this from pytest,
  • a way to use this from emacs,

I don’t want to run the stuff from emacs, to ensure the debugger and the frontend are not dependent.

first, a DAP implementation in python

https://github.com/microsoft/debugpy

#!/usr/bin/env python
# -*- coding: utf-8 -*-

a = 1
b = 2
print(a + b)
python3 -m debugpy --listen localhost:5678 --wait-for-client test.py
kns 5678
tcp        0      0 127.0.0.1:5678          0.0.0.0:*               LISTEN      3441251/python3

That was easy.

then, connect to it using emacs dap-mode

Using the following code

(setq dap-python-debugger 'debugpy)
(setq dap-python-executable "python3")

(dap-register-debug-template "python remote debug"
			     (list :type "python"
				   :request "attach"
				   :name "python remote debug"
				   :mode "remote"
				   :host "127.0.0.1"
				   :debugPort "5678"
				   ))

I called when the point was on , AND THEN I run ,

It looks like it connected just fine.

now, running debugpy from a pytest test

I used the following code.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import debugpy

debugpy.listen(5678)
debugpy.wait_for_client()


def test_something():
    a = 1
    b = 2
    assert a + b == 4

Then, with the same method as before, I could run pytest and connect to it easily.

Actually, because it handles the breakpoint function, I call also use.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import debugpy

debugpy.listen(5678)
debugpy.wait_for_client()


def test_something():
    breakpoint()
    a = 1
    b = 2
    assert a + b == 4

Instead of calling

I tried creating a module called konix_debugpy.py and with the following content.

#!/usr/bin/env python3
# -*- coding:utf-8 -*-


def set_trace():
    import debugpy
    debugpy.listen(5678)
    debugpy.wait_for_client()

So that I expected I could simply run

env PYTHONBREAKPOINT=konix_debugpy.set_trace pytest

Without changing the code.

It works well, but because debugpy is run by the first call to breakpoint, it actually does not stop here. I need to create a first dumb breakpoint to make it work.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

breakpoint() # to trigger debugpy


def test_something():
    breakpoint()
    a = 1
    b = 2
    assert a + b == 4

debugging from vscode

As simple as starting

nix run nixpkgs#vscodium

Then, using the attach configuration after having installed support for python, a new file called launch.json appears in my project at the location ./.vscode/launch.json with the content.

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
	{
	    "name": "Python: Remote Attach",
	    "type": "python",
	    "request": "attach",
	    "connect": {
		"host": "localhost",
		"port": 5678
	    },
	    "pathMappings": [
		{
		    "localRoot": "${workspaceFolder}",
		    "remoteRoot": "."
		}
	    ],
	    "justMyCode": true
	}
    ]
}

And pressing F5 makes vscode connect to the program to debug.