> AI agents: For documentation discovery and navigation, see [llms.txt](/llms.txt).

# Debug Python within a container

When adding Docker files to a Python project, tasks and launch configurations are added to enable debugging the application within a container. To accommodate the various scenarios of Python projects, some apps may require additional configuration.

## Configuring the container entry point

You can configure the entry point of the container by setting properties in `tasks.json`. VS Code automatically configures the container entry point when you first use the **Containers: Add Docker Files to Workspace...** command.

### Example: Configuring the entry point for a Python module

```json
{
  "tasks": [
    {
      "type": "docker-run",
      "label": "docker-run: debug",
      "dependsOn": [
        "docker-build"
      ],
      "python": {
        "module": "myapp"
      }
    }
  ]
}
```

### Example: Configuring the entry point for a Python file

```json
{
  "tasks": [
    {
      "type": "docker-run",
      "label": "docker-run: debug",
      "dependsOn": [
        "docker-build"
      ],
      "python": {
        "args": [
          "runserver",
          "0.0.0.0:8000",
          "--nothreading",
          "--noreload"
        ],
        "file": "manage.py"
      }
    }
  ]
}
```

## Automatically launching the browser to the entry page of the application

You can select the **Containers: Python - Django** or **Containers: Python - Flask** launch configurations to automatically launch the browser to the main page of the app. This feature is enabled by default, but you can configure this behavior explicitly by setting the `dockerServerReadyAction` object in `launch.json`.

This feature depends on several aspects of the application:

- The application **must output to the debug console or Docker logs**.
- The application must log a "server ready" message.
- The application must serve a browsable page.

Here is an example of using `dockerServerReadyAction` to launch the browser to open the `about.html` page based on a specific server message pattern:

```json
{
  "configurations": [
    {
      "name": "Containers: Python - Django",
      "type": "docker",
      "request": "launch",
      "preLaunchTask": "docker-run: debug",
      "python": {
        "pathMappings": [
          {
            "localRoot": "${workspaceFolder}",
            "remoteRoot": "/app"
          }
        ],
        "projectType": "django"
      },
      "dockerServerReadyAction": {
        "action": "openExternally",
        "pattern": "Starting development server at (https?://\\S+|[0-9]+)",
        "uriFormat": "%s://localhost:%s/about.html"
      }
    }
  ]
}
```

  > **Note**: The regex found in the `pattern` attribute simply attempts to capture a logged message similar to "Starting development server at `http://localhost:8000`". It accommodates variations in the url for http or https, any host name, and any port.

### Important dockerServerReadyAction object properties

- `action`: The action to take when the pattern is found. Can be `debugWithChrome` or `openExternally`.

- `pattern`: If the application logs a different message than shown above, set the `pattern` property of the [dockerServerReadyAction](/docs/containers/debug-common.md#dockerserverreadyaction-object-properties) object to a [JavaScript regular expression](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Regular_Expressions) that matches that message. The regular expression should include a capture group that corresponds to the port on which the application is listening.
- `uriFormat`: By default, the Container Tools extension will open the main page of the browser (however that is determined by the application). If you want the browser to open a specific page like the example above, the `uriFormat` property of the [dockerServerReadyAction](/docs/containers/debug-common.md#dockerserverreadyaction-object-properties) object should be set to a format string with two string tokens to indicate the protocol and port substitution.

## How to enable hot reloading in Django or Flask apps

When you select **Containers: Add Docker Files to Workspace** for Django or Flask, we provide you a Dockerfile and `tasks.json` configured for static deployment. Each time you make changes to your app code, you need to rebuild and re-run your container. Hot reloading allows you to visualize changes in your app code as your container continues to run. Enable hot reloading with these steps:

### For Django Apps

1. In the Dockerfile, comment out the line that adds app code to the container.

    ```docker
    #ADD . /app
    ```

1. Within the `docker-run` task in the `tasks.json` file, create a new `dockerRun` attribute with a `volumes` property. This setting creates a mapping from the current workspace folder (app code) to the `/app` folder in the container.

    ``` json
    {
      "type": "docker-run",
      "label": "docker-run: debug",
      "dependsOn": [
        "docker-build"
      ],
      "dockerRun": {
        "volumes": [
          {
            "containerPath": "/app", "localPath": "${workspaceFolder}"
          }
        ]
      },
      ...
    }
    ```

1. Edit the python attribute by **removing** `--noreload` and `--nothreading`.

    ``` json
    {
      ...
      "dockerRun": {
        "volumes": [
          {
            "containerPath": "/app", "localPath": "${workspaceFolder}"
          }
        ]
      },
      "python": {
        "args": [
          "runserver",
          "0.0.0.0:8000",
        ],
        "file": "manage.py"
      }
    }
    ```

1. Select the **Containers: Python – Django** launch configuration and hit `kb(workbench.action.debug.start)` to build and run your container.
1. Modify and save any file.
1. Refresh the browser and validate changes have been made.

### For Flask Apps

1. In the Dockerfile, comment out the line that adds app code to the container.

    ```docker
    #ADD . /app
    ```

1. Within the `docker-run` task in the `tasks.json` file, edit the existing dockerRun attribute by adding a `FLASK_ENV` in the `env` property as well as a `volumes` property. This setting creates a mapping from the current workspace folder (app code) to the `/app` folder in the container.

    ``` json
    {
      "type": "docker-run",
      "label": "docker-run: debug",
      "dependsOn": [
        "docker-build"
      ],
      "dockerRun": {
        "env": {
          "FLASK_APP": "path_to/flask_entry_point.py",
          "FLASK_ENV": "development"
        },
        "volumes": [
          {
            "containerPath": "/app", "localPath": "${workspaceFolder}"
          }
        ]
      },
      ...
    }
    ```

1. Edit the python attribute by **removing** `--no-reload` and `--no-debugger`.

    ``` json
    {
      ...
      "dockerRun": {
        "env": {
          "FLASK_APP": "path_to/flask_entry_point.py",
          "FLASK_ENV": "development"
        },
        "volumes": [
          {
            "containerPath": "/app", "localPath": "${workspaceFolder}"
          }
        ]
      },
      "python": {
        "args": [
          "run",
          "--host", "0.0.0.0",
          "--port", "5000"
        ],
        "module": "flask"
      }
    }
    ```

1. Select the **Containers: Python – Flask** launch configuration and hit `kb(workbench.action.debug.start)` to build and run your container.
1. Modify and save any file.
1. Refresh the browser and validate changes have been made.

## How to build and run a container together

1. In the previously mentioned `tasks.json` file, there is a dependency on the `docker-build` task. The task is part of the `tasks` array in `tasks.json`. For example:

```json
"tasks":
[
  {
    ...
  },
  {
    "label": "docker-build",
    "type": "docker-build",
    "dockerBuild": {
        "context": "${workspaceFolder}",
        "dockerfile": "${workspaceFolder}/Dockerfile",
        "tag": "YOUR_IMAGE_NAME:YOUR_IMAGE_TAG"
    }
  }
]
```

**Tip:** As the dependency clearly states `docker-build` as its dependency, the name has to match this task. You can change the name, if desired.

1. The `dockerBuild` object in the JSON allows for the following parameters:

    - context: The build context, from which your Dockerfile is called
    - dockerfile: The path to the Dockerfile to execute
    - tag: The name of the image to be built, with its version tag

1. Overall, a VS Code setup for building and debugging your Flask application can be:

    - `launch.json`

      ```json
      {
          "version": "0.2.0",
          "configurations": [
            {
              "name": "Debug Flask App",
              "type": "docker",
              "request": "launch",

              "preLaunchTask": "docker-run: debug",
              "python": {
                "pathMappings": [
                  {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "/app"
                  }
                ],
                "projectType": "flask"
              },
              "dockerServerReadyAction": {
                "action": "openExternally",
                "pattern": "Running on (http?://\\S+|[0-9]+)",
                "uriFormat": "%s://localhost:%s/"
              }
            }
          ]
      }
      ```

    - `tasks.json`

      ```json
      {
        "version": "2.0.0",
        "tasks": [
          {
            "type": "docker-run",
            "label": "docker-run: debug",
            "dependsOn": [
                "docker-build"
            ],
            "dockerRun": {
                "containerName": "YOUR_IMAGE_NAME",
                "image": "YOUR_IMAGE_NAME:YOUR_IMAGE_TAG",
                "env": {
                    "FLASK_APP": "path_to/flask_entry_point.py",
                    "FLASK_ENV": "development"
                },
                "volumes": [
                    {
                        "containerPath": "/app",
                        "localPath": "${workspaceFolder}"
                    }
                ],
                "ports": [
                    {
                        "containerPort": 5000,
                        "hostPort": 5000
                    }
                ]
            },
            "python": {
                "args": [
                    "run",
                    "--host",
                    "0.0.0.0",
                    "--port",
                    "5000"
                ],
                "module": "flask"
            }
        },
        {
            "label": "docker-build",
            "type": "docker-build",
            "dockerBuild": {
                "context": "${workspaceFolder}",
                "dockerfile": "${workspaceFolder}/Dockerfile",
                "tag": "YOUR_IMAGE_NAME:YOUR_IMAGE_TAG"
            }
          }
        ]
      }
      ```

## Next steps

Learn more about:

- [Configuring a non-root user in your container](/docs/containers/troubleshooting.md#running-as-a-non-root-user)
