Python Azure Function Debugging in Pyenv-virtualenv virtual environment

Creating virtual environment

$ mkdir python_demo
$ cd python_demo
$ pyenv local 3.9.16
$ pyenv virtualenv 3.9.16 python_demo-3.9.16

# OR pyenv-virtualenv will use local python runtime with the following command
$ pyenv virtualenv python_demo-3.9.16

setting pyenv local version to created virtual environment will allow to activate virtual environment automatically when we enter project folder, so exiting from project folder will deactivate virtual environment.

$ pyenv local python_demo-3.9.16

Activating virtual environment

$ pyenv activate python_demo-3.9.16

Creating Azure Function Project

$ func init --python -m V2
$ echo "ptvsd" >> requirements.txt
$ func new --name HttpExample --template "HTTP trigger" --authlevel "anonymous"

Opening VSCode

$ pipenv shell
$ code .

After opening VSCode, terminal will activate virtual environment as below;

If it doesn't activate it, close vscode and reopen it.

Don't forget to activate virtual environment in terminal before opening vscode, otherwise vscode debugger try to use different python runtime, in this use case, even i create virtual environment for python 3.9 with pipenv, vscode debugger try to use python 3.10 but Azure Function can run with python 3.9.

Vscode config files

We need to update two vscode config files to debug tasks.jsonsettings.json files.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Attach to Python Functions",
            "type": "python",
            "request": "attach",
            "port": 9091,
            "preLaunchTask": "func: host start"
        }
    ]
}
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "func: host start",
      "type": "shell",
      "command": "func host start --language-worker -- '-m ptvsd --host 127.0.0.1 --port 9091'",
      "problemMatcher": "$func-python-watch",
      "isBackground": true,
      "dependsOn": "pip install (functions)"
    },
    {
      "label": "pip install (functions)",
      "type": "shell",
      "osx": {
        "command": "${config:azureFunctions.pythonVenv}/bin/python -m pip install -r requirements.txt"
      },
      "windows": {
        "command": "${config:azureFunctions.pythonVenv}\\Scripts\\python -m pip install -r requirements.txt"
      },
      "linux": {
        "command": "${config:azureFunctions.pythonVenv}/bin/python -m pip install -r requirements.txt"
      },
      "problemMatcher": []
    },
    {
      "label": "Run Azurite",
      "type": "shell",
      "command": "azurite",
      "isBackground": true,
      "problemMatcher": "$tsc"
    }
  ]
}

update value of azureFunctions.pythonVenv to your environment name. Just update python_demo-3.9 to your virtual environment name.

$ pyenv prefix test39-3.9.16
{
    "azureFunctions.deploySubpath": ".",
    "azureFunctions.scmDoBuildDuringDeployment": true,
    "azureFunctions.pythonVenv": "/Users/kenanhancer/.pyenv/versions/python_demo-3.9.16",    "azureFunctions.projectLanguage": "Python",
    "azureFunctions.projectRuntime": "~4",
    "debug.internalConsoleOptions": "neverOpen",
    "azureFunctions.projectLanguageModel": 2
}
{
  "recommendations": [
    "ms-azuretools.vscode-azurefunctions",
    "ms-python.python"
  ]
}

Vscode start azurite to start Azure Function

Azurite is local emulator of Azure. Azure function needs azurite so that when we run func host start , azure function app will connect to Azurite storage acount, so click CMD+SHIFT+P in VSCode and type azurite: start and enter.

Debugging Azure Function locally

Click CMD+SHIFT+P and type Debug: Start Debugging as shown in below screenshot or just click F5 shortcut.

VSCode will ask for storage account, so select Use Local Emulator for local development.

This will update line 6 in local.settings.json

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "python",
    "AzureWebJobsFeatureFlags": "EnableWorkerIndexing",
    "AzureWebJobsStorage": "UseDevelopmentStorage=true"
  }
}

Testing Azure HTTP and Webhook Triggered Functions Locally

$ curl http://localhost:7071/api/HttpExample\?name=Azure
$ curl -X POST -H "Content-Type: application/json" -d '{ "name": "Azure" }' http://localhost:7071/api/HttpExample

Testing Azure Non-HTTP Triggered Functions Locally

$ curl --request POST -H "Content-Type: application/json" --data '{"input":"sample queue data"}' http://localhost:7071/admin/functions/QueueFunc

Deactivating virtual environment

$ cd ..