Useful Development

Creating a Python Function App with Poetry

banner image
posted on Nov 12, 2024

This blog post guides you through setting up a Python Function App with Poetry. It also covers configuring VS Code for debugging and deploying the project with a GitHub workflow. The code to accompany this post can be found here (along with a codespace so you can fork the repo and get it up and running in no time) 🚀🐍✨

Pre-requisites

Initialize the project

Run the following commands to initialize the project:

poetry new func-py-with-poetry/
code func-py-with-poetry
git init

Clean out the poetry scaffolding folders

Remove the default folders created by Poetry that you don't need.

Create a function app

Run the following command to create a function app:

poetry run func init --python

Move the azure-functions requirement into Poetry

Run the following commands:

poetry add azure-functions
rm requirements.txt

Add debugpy as a dev dependency

Run the following command:

poetry add debugpy --group dev

Make sure the selected VSCode interpreter is Poetry

Select the Poetry virtual environment as your interpreter in VSCode.

Add a function

Run the following command to add a new HTTP Trigger function:

poetry run func new --template "Http Trigger" --name MyHttpTrigger -a ANONYMOUS

Check the function app run locally

Run the following command to start the function app locally:

poetry run func start

Add tasks.json

Create a tasks.json file in the .vscode directory with the following content:

{
"version": "2.0.0",
"tasks": [
    {
        "type": "shell",
        "label": "func: host start",
        "command": "poetry run func host start",
        "options": {
            "env": {
                "languageWorkers__python__arguments": "-m debugpy --listen 127.0.0.1:9091"
            }
        },
        "problemMatcher": "$func-python-watch",
        "isBackground": true
    },
    {
        "label": "poetry install (functions)",
        "type": "shell",
        "osx": {
            "command": "poetry install"
        },
        "windows": {
            "command": "poetry install"
        },
        "linux": {
            "command": "poetry install"
        },
        "problemMatcher": []
    }
]
}

Add launch.json

Create a launch.json file in the .vscode directory with the following content:

{
"version": "0.2.0",
"configurations": [
    {
        "name": "Attach to Python Functions",
        "type": "debugpy",
        "request": "attach",
        "connect": {
            "host": "localhost",
            "port": 9091
        },
        "preLaunchTask": "func: host start"
    }
]
}

Test out debugging the function in VSCode using F5

Press F5 in VSCode to start debugging the function.

Next steps

To do deploy the Function App the requirements will need to be exported from Poetry (see this issue for all the details)


on:
  push:
    paths:
      - '**'
      - '!**/*.md'
      - '!**/*.http'
      - '!.vscode/**'
    branches:
      - main
  workflow_dispatch:

env:
  APP_NAME: py-with-poetry
  DEPLOY_PATH: './infra'
  PYTHON_VERSION: '3.11'

name: Build and deploy
jobs:
  build:
    runs-on: ubuntu-latest
    environment: ${{ github.head_ref || github.ref_name }}
    steps:
      - name: 'Checkout GitHub Action'
        uses: actions/checkout@v3

      - name: Setup Python ${{ env.PYTHON_VERSION }} Environment
        uses: actions/setup-python@v4
        with:
          python-version: ${{ env.PYTHON_VERSION }}

      - name: 'Resolve Project Dependencies Using Pip'
        shell: bash
        run: |
          pushd '.'
          python -m pip install --upgrade pip
          pip install poetry
          poetry export --without-hashes --format=requirements.txt > requirements.txt
          pip install -r requirements.txt --target=".python_packages/lib/site-packages"
          popd

      - name: Zip artifact for deployment
        working-directory: ${{env.AZURE_FUNCTIONAPP_PACKAGE_PATH}}
        run: zip -r release.zip . -x infra/**\*

      - name: Archive Production Artifact
        uses: actions/upload-artifact@v3
        with:
          name: dist
          path: release.zip