Debugpy + Nvim-DAP in a Docker container - help getting this to work?

I’ve been trying to get Debugpy working with Nvim-DAP from inside a Docker container. I think I am close, but it’s not really working yet.

Here is my setup: GitHub - gwerbin/debugpy-in-docker at 0c0db5ff05d36b94ce1fb969e6b6a1295b26292c

I perform these steps:

  1. Open the runtime/service.py file in Neovim for editing.
  2. Run docker compose up --build to:
    2.1. Mount ./runtime as a “volume” in the container
    2.2. Start Debugpy, which starts Hypercorn, which starts the web server
    2.3. Expose the ports for Debugpy (9001) and the Uvicorn web server (8001) on my system
  3. Execute :lua require('dap').continue() to start a session, and select 1 for my “Generic remote” adapter.
  4. Open the Nvim-DAP REPL with :lua require('dap').repl.open().

It appears that Neovim is successfully starting a “session” that is connected to the Debugpy server inside the container. I can set breakpoints with :lua require('dap').toggle_breakpoint() and see the “B” sign appear in the sign column.

My Python program appears to run just fine. I can make requests with curl http://localhost:8001/, getting the correct responses and seeing the expected log output.

However I can’t seem to actually drop into the debugger at all, no matter if I set a breakpoint or I manually trigger an exception. Manually inserting a breakpoint() call just triggers a BdbQuit exception as you might expect.

Is there something I’m missing in the setup here?

Version info:

  • Neovim v0.5.0-dev+61aefaf29
  • Nvim-DAP at commit 7c6d12132339d7ef4136dabdd316a20e9c7dd8cf
  • Docker 20.10.5, build 55c4c88 with Docker Desktop for Mac
  • MacOS 10.14.6

Which python version is used in the Docker image? debugpy doesn’t work with python 3.9.3, see Break points are being ignored in Python 3.9.3 · Issue #587 · microsoft/debugpy · GitHub

Many months later, this seems to be working now. One of the missing pieces was that I didn’t run the container with the --service-ports option, which meant that the DAP port wasn’t even available to connect to. Oops…

One piece that I am still missing: how do I set a breakpoint properly? When I am running the application in a container and I use toggle_breakpoint(), I get the error “Breakpoint in a file that does not exist”. Do I need some kind of hook to translate my own filesystem paths to container filesystem paths? I am using a Docker Volume for the source code, if that makes things any easier.

My current config is here: https://git.sr.ht/~wintershadows/dotfiles/tree/c73cb89e/item/.config/nvim/lua/plugin-config/nvim-dap.lua.

Haven’t tried in this context, but one general trick is to mount $HOME (-v $HOME:$HOME) into the container (won’t welp with system libraries)

You probably need to configure the pathMappings, see Debug configuration settings · microsoft/debugpy Wiki · GitHub

Thanks! Where do I adjust settings like this? Do they go on the “adapter” or the “configuration”? And what table field should they be assigned to?

They go to the configuration.

I guess you’d have to adapt

  dap.configurations.python = {
    {
      type = 'generic_remote',
      name = 'Generic remote',
      request = 'attach',
    },

To something like this:

  dap.configurations.python = {
    {
      type = 'generic_remote',
      name = 'Generic remote',
      request = 'attach',
      pathMappings = {{
        -- Update this as needed
        localRoot = vim.fn.getcwd();
        remoteRoot = "/";
      }};
    },

Thanks! The missing piece was that elements in the configuration table (except for a few specific ones?) are passed to the DAP server.

I don’t think that is explicitly mentioned in the docs anywhere, is it? And personally I find it a bit confusing; the type, name, and request keys all seem like “client-side” configuration, but the rest of that table is “server-side” configuration.

:help dap-configuration does say it - at least kinda:

In addition to having to know how to (launch) and connect to a debug-adapter,
Neovim needs to instruct the debug-adapter how to launch the debugee or how to
connect to it. The debugee is the application you want to debug.

This is configured via a `Configuration`, a `Configuration` has 3 required
fields:

>
    type: string        -- References the Adapter to use
    request: string     -- Either `attach` or `launch`, indicates if the
                        -- debug-adapter in turn should launch a debugee or if
                        -- it can attach to a debugee.
    name: string        -- A user readable name for the configuration
<

It takes any number of further options which are debug-adapter specific.

Fair enough! I didn’t understand what “options which are debug-adapter specific” meant. If I can think of a way to rephrase or clarify that statement, I’ll submit a PR.