DEV Community

Javier Aguirre for Wealize

Posted on • Originally published at javaguirre.me on

Debug Python and Django easily from Visual Studio Code

Debugging code, sometimes painful, sometimes funny, but always an exciting task.

If we don’t use the right tools, It’s where the developer can waste more time. Making debugging easy for developers has been sometimes a problem for technology, but fortunately, in Python, there have been good debug options right from the start.

Visual Studio Code has a very powerful and configurable tab where you can define the desired configuration for your project. You can have all the configurations you want! (for testing, debugging, running a specific process…)

TL;DR

From VS Code, we can easily debug Python code locally but also when running inside of a Docker container using ptvsd. I’ll tell you how.

Print

We all have printed code at some point of our career, but the path to becoming a better developer goes beyond that, it’s essential to spend time researching until we find better tools for the task.

Printing has never been cool, but before learning the proper debugging tools, it has always been that quick and dirty option to check variable output.

PDB

PDB and pudb are great tools! I still use them sometimes when I want to debug something tricky, but for debugging speed purposes I find much more convenient using VS Code Debug tab, where I can see all the context on a specific line of code.

Before that, I used to have a snippet for pdb, and that would extend to import pdb; pdb.set_trace() so I could stop the execution at a specific line of code. Then with (n)ext, (c)ontinue, (q)uit… I could control the execution line by line and step into a specific function or method (more on pdb and pudb).

VS Code

After a while using VS Code I started getting deep into different user and workspace configurations on Django and Node/React, this article gives an example on how we could configure a Django project to use the VS Code debugging tab.

Starting services having installed a Django project locally is easy, we could just use runserver. We’d click the Debug tab, select Add configuration... in the selector and follow the wizard selecting Django: runserver.

The configuration would look like this:

{
    "name": "Django: Runserver",
    "type": "python",
    "request": "launch",
    "program": "${workspaceFolder}/manage.py",
    "args": [
        "runserver",
        "--noreload",
        "--nothreading"
    ],
    "django": true
}
Enter fullscreen mode Exit fullscreen mode

If you use pipenv, virtualenv or have selected the pythonPath on your workspace configuration (Command-, on Mac), VS Code knows how to run the command automatically. We could have a command for testing too, having an envvar to select another DJANGO_SETTINGS_MODULE.

{
    "name": "Django: Test",
    "type": "python",
    "request": "launch",
    "program": "${workspaceFolder}/manage.py",
    "env": {"DJANGO_SETTINGS_MODULE": "myproject.settings.test"},
    "args": [
        "test"
    ],
    "django": true
}
Enter fullscreen mode Exit fullscreen mode

We’d click play and have our tests passed. :-)

VS Code debug in Docker

Debugging inside a Docker container is a bit trickier, we need to open a socket so we can debug from VS Code, let’s see how.

Our Django Dockerfile looks something like this if we use pipenv.

FROM python:3.7

RUN mkdir /code

WORKDIR /code

RUN pip install pipenv
ADD Pipfile /code/
RUN pipenv install --dev

COPY . /code/

EXPOSE 8000
Enter fullscreen mode Exit fullscreen mode

We could have a docker-compose.yml file to manage dependencies easier, such as postgres, redis, or just the ports opened for the host.

version: '3.7'

services:
  db:
    ...

  backend:
    build: .
    image: mydjangoproject
    command: pipenv run manage.py runserver 0.0.0.0:8000
    environment:
      DJANGO_DEBUG: 1
      DJANGO_SETTINGS_MODULE: myproject.settings.local
    volumes:
      - .:/code
    ports:
      - 8000:8000 # Serving Django
      - 8888:8888 # debugging service (ptvsd)
    depends_on:
      - db

  frontend:
    ...
Enter fullscreen mode Exit fullscreen mode

In this case, we open the 8000 for Django runserver and the 8888 so VS Code can connect via the Debug tab to Django.

To be able to do this, Microsoft created a library, ptvsd the Python tools for the Visual Studio debugger. This library runs within our Python code and opens a socket we can connect to debug the application. In Django, we can put it on the wsgi.py file and It will only run if settings.DEBUG is True.

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")

if os.environ.get('DJANGO_DEBUG', False): # You can use django.conf settings.DEBUG
    import ptvsd
    ptvsd.enable_attach(address=('0.0.0.0', 8888))
    ptvsd.wait_for_attach() # We can remove this line it gives you trouble,
                             # but it's good to know if the debugger started or not
                             # blocking the execution for a while :-)

application = get_wsgi_application()
Enter fullscreen mode Exit fullscreen mode

We open the socket to the outside world 0.0.0.0 in the port 8888 so we can connect from the host, our machine.

We execute our docker-compose script, in my case docker-compose up backend.

In VS Code the configuration would be pretty straight forward, we add the port where ptvsd opened the socket, we tell VS Code, our localRoot is the current project and the remoteRoot which is my /code path, defined on my Dockerfile for this project.

{
    "name": "Remote Django App",
    "type": "python",
    "request": "attach",
    "pathMappings": [
        {
            "localRoot": "${workspaceFolder}",
            "remoteRoot": "/code"
        }
    ],
    "port": 8888,
    "host": "localhost"
}
Enter fullscreen mode Exit fullscreen mode

Now It’s when the magic happens! You should be able to do something like this. :-)

Do you know more tricks debugging on VS Code? Let me know in the comments!

Latest comments (6)

Collapse
 
bouissihamza6 profile image
hamza Bou Issa

I wrote an updated article :
dev.to/bouissihamza6/debug-a-djang...

Collapse
 
siaarzh profile image
Serzhan Akhmetov

This is a very helpful post. Thank you Javier! I'm going to expand on your post here by adding that you can debug within Docker containers easily now. Using the new Remote Development extension pack, which should come to the mainline VS Code soon.

There's no need for a dedicated port for VS Code in your Django App, although the solution is quite elegant!

Collapse
 
j_mplourde profile image
Jean-Michel Plourde

Nice article! I will try that for sure since I work with Django. I was wondering if there is any way for running unit test and functional test. I currently use Intellij Idea, while the cost is a bit high for me, it is really powerful. I'm willing to try new products.

Collapse
 
javaguirre profile image
Javier Aguirre

Thank you! There is actually! :-)

As you may know you can use
python manage.py test
to run all your tests, so from VS Code you could use it like:

{
    "name": "Django: Test",
    "type": "python",
    "request": "launch",
    "program": "${workspaceFolder}/manage.py",
    "env": {"DJANGO_SETTINGS_MODULE": "myproject.settings.test"},
    "args": [
        "test"
    ],
    "django": true
}

you can put it on your launch.json and you’re good to go!

Collapse
 
dylan profile image
Dylan

I think you might really like pysnooer:
github.com/cool-RR/PySnooper

debug with a decorator and watch line by line, set depth, etc

Collapse
 
javaguirre profile image
Javier Aguirre

I'll check it out, thank you Dylan!