Quickstart: Writing Azure Functions in Python (v2)

Overview

In this post, we’re looking at writing Azure Functions in Python and walk through the most common usage patterns.

Over the past months, I’ve used Azure Functions in nearly every project I’ve been working on. They have come a long way in terms of feature set and language support, and overall offer a great way to run serverless applications on Azure.

In details we’ll look into:

  1. HTTP Triggers and output bindings
  2. Blob triggers and output bindings
  3. Queue triggers and output bindings
  4. CosmosDB triggers and output bindings
  5. Timer triggers

All examples are also hosted in the azure-functions-python-examples GitHub repository.

Prerequisites

Installing Azure Functions Core Tools v2

First, we need to install the Azure Functions Core Tools (v2), so that we can start developing and testing our Functions locally. Under macOS, this is very easy using brew:

brew tap azure/functions
brew install azure-functions-core-tools

Next we need to get a Python 3.6 environment running:

python3.6 -m venv .env
source .env/bin/activate

Once our env has been activated, we can create our Python-based Function App:

func init MyPythonFunctionApp --worker-runtime python
cd MyPythonFunctionApp/
code .

Backing Azure Infrastructure

Azure Functions relies mostly on Azure Blob for “keeping track of what’s going on”. Hence, we can either use Azure Blob or the Azure Storage Emulator for local testing. For sake of laziness, let’s just use Azure directly:

az group create -l westeurope -n functions-test
az storage account create -l westeurope -g functions-test -n functionstest42 --sku Standard_LRS

When developing and testing locally, our Function APp will pull the Connection Strings from local.settings.json:

Hence, we need persist our Connection Strings for local usage in this file and add it to .gitignore. We can find our Connection String inside our Storage Account in the Azure Portal under Access keys or via CLI:

Storage Connection String
Storage Connection String

Azure Functions in Python require a reference for AzureWebJobsStorage. In this Storage Account, the Function Runtime will persist their internals. In our example we’ll just use the same Storage Account for all tests.

Additional Python Packages

We’ll probably notice that we’ll need some additional Python packages when writing Azure Functions in Python. Therefore, we can add additional pip packages in requirements.txt in the format of e.g., requests==2.19.1.

Once the Function App is deployed to Azure, the platform will automatically install all packages from requirements.txt.

Triggers and Output Binding Examples

Now that we have our basic setup created, we can start creating some Functions.

1. HTTP trigger and output binding

We can create a new Function by running:

func new

In our case, we select HTTP trigger from the templates and name it HttpExample. In our code editor, we’ll see two two relevant files:

  • __init__.py – Our actual code that the Function is supposed to run
  • function.json – Our input and output bindings

In our input and output bindings, we specify the allowed methods, as well as routes. This allows us to easily implement RESTful APIs onto of Functions:

Our Functions receives:

The API definitions for the input and output bindings can be really helpful:

We can start our Function locally by running:

func host start

We can test our Function using cURL or Postman:

curl -X GET http://localhost:7071/api/HttpExample/foobar/42?name=test

Or as a POST with JSON in the body:

curl -d '{"test": "foobar"}' -X POST http://localhost:7071/api/HttpExample/foobar/42

2. Blob trigger and output binding

For testing the Blob input and output bindings, we first need to create a Blob container:

az storage container create -n myblobcontainer --account-name functionstest42

Next, we can create a Blob Storage trigger Function from the templates and name it BlobExample:

func new

First, we want to update our bindings:

We need to configure two fields:

  • Path – The location under which Blob container and path our Function is listening
  • MyStorageConnectionAppSetting – The Connection String to our Storage Account containing our Blob container

Again, we persist MyStorageConnectionAppSetting in local.settings.json:

"MyStorageConnectionAppSetting": "DefaultEndpointsProtocol=https;AccountName=functionstest42;AccountKey=xxxxx==;EndpointSuffix=core.windows.net"

Finally we can implement our Function code:

Again, the API definition can be really helpful:

Since we are using a non-HTTP-based or Timer-trigger, we need to tell our Function App to use the runtime extension bundle, which we can do by adding it to host.json:

You can find more information why this is needed here. In short, this adds triggers and output bindings for all the Azure-related services, such a Blob, Queues, etc.

Finally, let’s run our Function:

func host start

Once we drop a file into our Blob container under the subdirectory input/ we should shortly after see a new object with the same name under output/. Unfortunately, it seems like Python does not allow to output multiple Blobs by using the output binding or change the filename of the output object. In this case, we’d need to manually connect to Blob inside our Function’s code.

3. Queue trigger and output binding

One of my favorite triggers is the Queue trigger.

Firstly, let’s create two Queues for testing:

az storage queue create -n my-input-queue --account-name functionstest42
az storage queue create -n my-output-queue --account-name functionstest42

and then use func new for creating a new Queue Storage trigger.

Our input and output bindings are fairly straight forward and just reuse the same Storage Account Connection String from the previous example:

Our Function code is also straight forward by receiving a JSON-formatted message in the input queue and outputting a new JSON message to the output queue.

Again, the API definition can be really helpful:

As with the Blob output binding, it seems like that there is currently no way to output multiple queue messages by using solely the output binding. Again, in this case we would need to manually connect to our Queue Storage within our Function’s code.

4. CosmosDB trigger and output binding

Let’s first create a CosmosDB account, add a database and then provision a collection for testing:

az cosmosdb create -g functions-test -n cosmosfunctiontest
az cosmosdb database create -d cosmostest -n cosmosfunctiontest -g functions-test
az cosmosdb collection create -c mycollection -n cosmosfunctiontest -g functions-test -d cosmostest --throughput 400

Next, we can create a Cosmos DB trigger Function from the templates and name it CosmosDBExample:

func new

First, let’s have a look at our bindings:

Our function code is fairly simple. The CosmosDB trigger automatically inputs a set of Documents for easier scalability. Documents can be easily convert to JSON and then processed.

For writing a single Documents back into CosmosDB, we can use func.Document and return it:

For returning a list of Documents to CosmosDB, we can use func.DocumentList by first assembling a list of func.Document objects and then converting them:

Again, our API definitions:

5. Timer trigger

Lastly, let’s have a look at the Timer trigger.

First, we create a Timer trigger Function using func new and name it TimerExample. The Timer trigger is configured through the standard CRON schedule syntax.

In our example, we’ll execute the Function every 10 minutes:

As expected, our Function code is straightforward:

Once we start our function via func host start, we should see the function being executed at hh:00, hh:10, hh:20, and so on.

Summary

Writing Azure Functions in Python offers a great way to run Python code serverless on Azure. In this post, we’ll walked through some of the common input triggers and output bindings and showed how they can be used in Python. If you want to learn how to automatically deploy a Function App to Azure using Azure DevOps, check out this post.

Without doubt, there is small learning curve to using Azure Functions with Python, but after a few Functions, it’ll be an easy play. One room for improvement is definitely support for naming Blob outputs, as well as being able to output more than one Blob object or Queue message.

If you have any questions or want to give feedback, feel free to reach out via Twitter or just comment below.

One thought on “Quickstart: Writing Azure Functions in Python (v2)

Leave a Reply

Your email address will not be published. Required fields are marked *