Debugging with Visual Studio Code Dev Containers Extension

With the Dev Containers extension for Visual Studio Code (VS Code), you can have access to VS Code features within a container, which includes debugging tools. Here is an overview to help you get started debugging code in your Tutor dev environment.

Initial Setup

  1. Make sure you have the Dev Containers extension installed (lms-vscode-remote.remote-containers).

  2. Open the VS Code Command Palette (Ctrl+Shift+P / Cmd+Shift+P) and run Dev Containers: Attach to Running Container.

  3. Select the container (the LMS or CMS container) that you want to debug in.

  4. VS Code will open a new window connected (inside) the selected container.

  5. In the VS Code File Explorer click on “Open Folder” and select /openedx/edx-platform .

  6. Ensure the Python extension ms-python.python is installed inside the container.

  7. In the Command Palette run Python: Select Interpreter and make sure ~/venv/bin/python (more specifically /openedx/venv/bin/python ) is selected.

  8. Open the Run and Debug panel on the left hand side, and the cog icon to create or open a launch.json file (this file by default will be created in /openedx/edx-platform/.vscode).

Debugging running instances of the LMS and/or CMS

There is a solution that has been posted in the forums on this topic. This builds on that solution, but modifies it to take advantage of the Dev Containers extension.

  1. Edit the lms and cms services in "$(tutor config printroot)/env/dev/docker-compose.yml" . Change the command to be like this (use cms after manage.py for the cms service):

    command: >
      sh -xc "python -m pip install debugpy &&
             python -m debugpy --listen 0.0.0.0:5678 ./manage.py lms runserver 0.0.0.0:8000"
    

    Note***: If you would like to debug the runserver command from the beginning, add --wait-for-client to the debugpy command. If you do this, the runserver command will not execute until a debugger is attached to it. This is helpful if you want to debug setup/configuration of the service.

  2. Run tutor dev reboot lms cms -d to stop and start the development containers, while picking up the changes to docker-compose.yml .

  3. In your launch.json file add a configuration item like this:

        {
            "name": "attach",
            "type": "debugpy",
            "request": "attach",
            "connect": {
                "host": "localhost",
                "port": 5678
            },
            "justMyCode": false
        },
  1. Run the “attach” configuration. As you make HTTP requests to the LMS and CMS services, the debugger will suspend execution at any breakpoints along the execution path - allowing you to use the debugger tools in VS Code.

Debugging edx-platform tests

Add a configuration like this to your launch.json file:

        {
            "name": "pytest cms",
            "type": "debugpy",
            "request": "launch",
            "module": "pytest",
            "args": [
                "-p",
                "no:randomly",
                "--ds",
                "cms.envs.test",
                "common/djangoapps/student/tests/test_models.py"
            ],
            "justMyCode": false
        }, 

Change the --ds argument to be the Django settings path you want to use. The last argument is a specifies which test(s) to run - update this as needed. Here are some examples:

# directory: run all tests under here
"common/djangoapps/student/"

# file: run all tests in this file
"common/djangoapps/student/tests/test_admin_views.py"

# class: run all tests in this test class
"common/djangoapps/student/tests/test_admin_views.py::AdminCourseRolesPageTest"

# test function/method: run exactly this test
"common/djangoapps/student/tests/test_admin_views.py::AdminCourseRolesPageTest::test_save_without_org_and_course_data"

Debugging edx-platform management commands

Add a configuration like this to your launch.json file for the command you want to run:

        {
            "name": "lms dump_settings",
            "type": "debugpy",
            "request": "launch",
            "args": [
                "lms",
                "dump_settings"
            ],
            "env": {
                "DJANGO_SETTINGS_MODULE": "lms.envs.production",
                "LMS_CFG": "lms/envs/mock.yml"
            },
            "django": true,
            "autoStartBrowser": false,
            "program": "${workspaceFolder}/manage.py",
            "justMyCode": false
        },

Notes

  1. The changes you make in docker-compose.yml in your Tutor environment will be overwritten on a tutor config save, tutor dev launch, etc.
  2. Set "justMyCode" to false if you want to be able to step into dependency code.
6 Likes

This is amazing. Thank you for documenting this. I use PyCharm and it has support for DevContainers as well. I am going to try this out and adapt it.

1 Like

Thanks a lot @tpayne
Really appreciate you sharing this here.

1 Like

Another thing I want to mention is that rather than manually installing extensions in dev containers every time they are created, you can set certain extensions to be installed automatically in any dev container created. To do this you can add extensions to the dev.containers.defaultExtensions (dev containers specific) setting and/or the remote.defaultExtensionsIfInstalledLocally (any remote host, including dev containers) setting.

To avoid having the commands removed when the Tutor env is modified you can create a docker-compose.override.yml file by running vim "$(tutor config printroot)/env/dev/docker-compose.override.yml" and then adding the following:

services:
  lms:
    command: >
      sh -xc "python -m pip install debugpy &&
             python -m debugpy --listen 0.0.0.0:5678 ./manage.py lms runserver 0.0.0.0:8000"
  cms:
    command: >
      sh -xc "python -m pip install debugpy &&
             python -m debugpy --listen 0.0.0.0:5678 ./manage.py cms runserver 0.0.0.0:8000"
2 Likes