Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to debug Django in VSCode with autoreload turned on

I set up debugging in VSCode (Django application) and it works great with the default setup. However, when debugging it seems automatic reloading is not possible. This is stated in the VSCode docs:

Note that automatic reloading of Django apps is not possible while debugging.

I was wondering if there's some way to make debugging (breakpoints etc.) work with reload enabled in Django.

like image 930
c4urself Avatar asked Jan 25 '23 21:01

c4urself


1 Answers

It turns out you can make this work by using Microsoft's debugpy tool.

Django launches two processes when reloading is turned on (the default), one of them is the parent and the other is the subprocess which does the reloading magic.

Django differentiates these two processes by setting the environment variable RUN_MAIN to true in the subprocess (which does the reloading). Refer to: https://github.com/django/django/blob/8a902b7ee622ada258d15fb122092c1f02b82698/django/utils/autoreload.py#L241

By tweaking manage.py slightly, we can start a debug listener in the parent process and have it survive any reloads.

  1. Add debugpy to however you manage your requirements (requirements.txt etc.)

  2. Add the following function to initialize the debugger:

def initialize_debugger():
    import debugpy
    
    # optionally check to see what env you're running in, you probably only want this for 
    # local development, for example: if os.getenv("MY_ENV") == "dev":

    # RUN_MAIN envvar is set by the reloader to indicate that this is the 
    # actual thread running Django. This code is in the parent process and
    # initializes the debugger
    if not os.getenv("RUN_MAIN"):
        debugpy.listen(("0.0.0.0", 9999))
        sys.stdout.write("Start the VS Code debugger now, waiting...\n")
        debugpy.wait_for_client()
        sys.stdout.write("Debugger attached, starting server...\n")

  1. Alter the main function in manage.py as follows:
    def main()
        # <...>
        initialize_debugger()  # add this
        execute_from_command_line(sys.argv)

  1. Modify launch.json configuration in VSCode to attach to port 9999 (from above):
        {
            "name": "Python: Remote Attach (DebugPy)",
            "type": "python",
            "request": "attach",
            "port": 9999,
            "host": "localhost",
        },

TIP: you can disable "Uncaught exceptions" because the reload itself causes a SystemExit

like image 86
c4urself Avatar answered Jan 27 '23 12:01

c4urself