Movatterモバイル変換


[0]ホーム

URL:


Skip to main content

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Download Microsoft EdgeMore info about Internet Explorer and Microsoft Edge
Table of contentsExit focus mode

Azure Functions Python developer guide

  • 2024-12-29
Feedback

In this article

This guide is an introduction to developing Azure Functions by using Python. The article assumes that you've already read theAzure Functions developers guide.

Important

This article supports both the v1 and v2 programming model for Python in Azure Functions.The Python v1 model uses afunctions.json file to define functions, and the new v2 model lets you instead use a decorator-based approach. This new approach results in a simpler file structure, and it's more code-centric. Choose thev2 selector at the top of the article to learn about this new programming model.

As a Python developer, you might also be interested in these topics:

  • Visual Studio Code: Create your first Python app using Visual Studio Code.
  • Terminal or command prompt: Create your first Python app from the command prompt using Azure Functions Core Tools.
  • Samples: Review some existing Python apps in the Learn samples browser.
  • Visual Studio Code: Create your first Python app using Visual Studio Code.
  • Terminal or command prompt: Create your first Python app from the command prompt using Azure Functions Core Tools.
  • Samples: Review some existing Python apps in the Learn samples browser.

Development options

Both Python Functions programming models support local development in one of the following environments:

Python v2 programming model:

Python v1 programming model:

You can also create Python functions in the Azure portal.

Tip

Although you can develop your Python-based Azure functions locally on Windows, Python is supported only on a Linux-based hosting plan when it's running in Azure. For more information, see thelist of supported operating system/runtime combinations.

Programming model

Azure Functions expects a function to be a stateless method in your Python script that processes input and produces output. By default, the runtime expects the method to be implemented as a global method calledmain() in the__init__.py file. You can alsospecify an alternative entry point.

You bind data to the function from triggers and bindings via method attributes that use thename property that's defined in thefunction.json file. For example, the followingfunction.json file describes a simple function that's triggered by an HTTP request namedreq:

{    "scriptFile": "__init__.py",    "bindings": [        {            "authLevel": "function",            "type": "httpTrigger",            "direction": "in",            "name": "req",            "methods": [                "get",                "post"            ]        },        {            "type": "http",            "direction": "out",            "name": "$return"        }    ]}

Based on this definition, the__init__.py file that contains the function code might look like the following example:

def main(req):    user = req.params.get('user')    return f'Hello, {user}!'

You can also explicitly declare the attribute types and return type in the function by using Python type annotations. Doing so helps you to use the IntelliSense and autocomplete features that are provided by many Python code editors.

import azure.functionsdef main(req: azure.functions.HttpRequest) -> str:    user = req.params.get('user')    return f'Hello, {user}!'

Use the Python annotations that are included in theazure.functions.* package to bind the input and outputs to your methods.

Azure Functions expects a function to be a stateless method in your Python script that processes input and produces output. By default, the runtime expects the method to be implemented as a global method in thefunction_app.py file.

Triggers and bindings can be declared and used in a function in a decorator based approach. They're defined in the same file,function_app.py, as the functions. As an example, the followingfunction_app.py file represents a function trigger by an HTTP request.

@app.function_name(name="HttpTrigger1")@app.route(route="req")def main(req):    user = req.params.get("user")    return f"Hello, {user}!"

You can also explicitly declare the attribute types and return type in the function by using Python type annotations. Doing so helps you use the IntelliSense and autocomplete features that are provided by many Python code editors.

import azure.functions as funcapp = func.FunctionApp()@app.function_name(name="HttpTrigger1")@app.route(route="req")def main(req: func.HttpRequest) -> str:    user = req.params.get("user")    return f"Hello, {user}!"

To learn about known limitations with the v2 model and their workarounds, seeTroubleshoot Python errors in Azure Functions.

Alternative entry point

You can change the default behavior of a function by optionally specifying thescriptFile andentryPoint properties in thefunction.json file. For example, the followingfunction.json tells the runtime to use thecustomentry() method in themain.py file as the entry point for your Azure function.

{  "scriptFile": "main.py",  "entryPoint": "customentry",  "bindings": [      ...  ]}

The entry point is only in thefunction_app.py file. However, you can reference functions within the project infunction_app.py by usingblueprints or by importing.

Folder structure

The recommended folder structure for a Python functions project looks like the following example:

 <project_root>/ | - .venv/ | - .vscode/ | - my_first_function/ | | - __init__.py | | - function.json | | - example.py | - my_second_function/ | | - __init__.py | | - function.json | - shared_code/ | | - __init__.py | | - my_first_helper_function.py | | - my_second_helper_function.py | - tests/ | | - test_my_second_function.py | - .funcignore | - host.json | - local.settings.json | - requirements.txt | - Dockerfile

The main project folder,<project_root>, can contain the following files:

  • local.settings.json: Used to store app settings and connection strings when running locally. This file doesn't get published to Azure. To learn more, seelocal.settings.file.
  • requirements.txt: Contains the list of Python packages the system installs when publishing to Azure.
  • host.json: Contains configuration options that affect all functions in a function app instance. This file does get published to Azure. Not all options are supported when running locally. To learn more, seehost.json.
  • .vscode/: (Optional) Contains the stored Visual Studio Code configuration. To learn more, seeVisual Studio Code settings.
  • .venv/: (Optional) Contains a Python virtual environment used by local development.
  • Dockerfile: (Optional) Used when publishing your project in acustom container.
  • tests/: (Optional) Contains the test cases of your function app.
  • .funcignore: (Optional) Declares files that shouldn't get published to Azure. Usually, this file contains.vscode/ to ignore your editor setting,.venv/ to ignore the local Python virtual environment,tests/ to ignore test cases, andlocal.settings.json to prevent local app settings from being published.

Each function has its own code file and binding configuration file,function.json.

The recommended folder structure for a Python functions project looks like the following example:

 <project_root>/ | - .venv/ | - .vscode/ | - function_app.py | - additional_functions.py | - tests/ | | - test_my_function.py | - .funcignore | - host.json | - local.settings.json | - requirements.txt | - Dockerfile

The main project folder,<project_root>, can contain the following files:

  • .venv/: (Optional) Contains a Python virtual environment that's used by local development.
  • .vscode/: (Optional) Contains the stored Visual Studio Code configuration. To learn more, seeVisual Studio Code settings.
  • function_app.py: The default location for all functions and their related triggers and bindings.
  • additional_functions.py: (Optional) Any other Python files that contain functions (usually for logical grouping) that are referenced infunction_app.py through blueprints.
  • tests/: (Optional) Contains the test cases of your function app.
  • .funcignore: (Optional) Declares files that shouldn't get published to Azure. Usually, this file contains.vscode/ to ignore your editor setting,.venv/ to ignore local Python virtual environment,tests/ to ignore test cases, andlocal.settings.json to prevent local app settings being published.
  • host.json: Contains configuration options that affect all functions in a function app instance. This file does get published to Azure. Not all options are supported when running locally. To learn more, seehost.json.
  • local.settings.json: Used to store app settings and connection strings when it's running locally. This file doesn't get published to Azure. To learn more, seelocal.settings.file.
  • requirements.txt: Contains the list of Python packages the system installs when it publishes to Azure.
  • Dockerfile: (Optional) Used when publishing your project in acustom container.

When you deploy your project to a function app in Azure, the entire contents of the main project folder,<project_root>, should be included in the package, but not the folder itself, which means thathost.json should be in the package root. We recommend that you maintain your tests in a folder along with other functions (in this example,tests/). For more information, seeUnit testing.

Connect to a database

Azure Functions integrates well withAzure Cosmos DB for manyuse cases, including IoT, ecommerce, gaming, etc.

For example, forevent sourcing, the two services are integrated to power event-driven architectures using Azure Cosmos DB'schange feed functionality. The change feed provides downstream microservices the ability to reliably and incrementally read inserts and updates (for example, order events). This functionality can be used to provide a persistent event store as a message broker for state-changing events and drive order processing workflow between many microservices (which can be implemented asserverless Azure Functions).

Azure Cosmos DB ordering pipeline reference architecture

To connect to Azure Cosmos DB, firstcreate an account, database, and container. Then you can connect your function code to Azure Cosmos DB usingtrigger and bindings, like thisexample.

To implement more complex app logic, you can also use the Python library for Cosmos DB. An asynchronous I/O implementation looks like this:

pip install azure-cosmospip install aiohttpfrom azure.cosmos.aio import CosmosClientfrom azure.cosmos import exceptionsfrom azure.cosmos.partition_key import PartitionKeyimport asyncio# Replace these values with your Cosmos DB connection informationendpoint = "https://azure-cosmos-nosql.documents.azure.com:443/"key = "master_key"database_id = "cosmicwerx"container_id = "cosmicontainer"partition_key = "/partition_key"# Set the total throughput (RU/s) for the database and containerdatabase_throughput = 1000# Singleton CosmosClient instanceclient = CosmosClient(endpoint, credential=key)# Helper function to get or create database and containerasync def get_or_create_container(client, database_id, container_id, partition_key):    database = await client.create_database_if_not_exists(id=database_id)    print(f'Database "{database_id}" created or retrieved successfully.')    container = await database.create_container_if_not_exists(id=container_id, partition_key=PartitionKey(path=partition_key))    print(f'Container with id "{container_id}" created')     return container async def create_products():    container = await get_or_create_container(client, database_id, container_id, partition_key)    for i in range(10):        await container.upsert_item({            'id': f'item{i}',            'productName': 'Widget',            'productModel': f'Model {i}'        }) async def get_products():    items = []    container = await get_or_create_container(client, database_id, container_id, partition_key)    async for item in container.read_all_items():        items.append(item)    return itemsasync def query_products(product_name):    container = await get_or_create_container(client, database_id, container_id, partition_key)    query = f"SELECT * FROM c WHERE c.productName = '{product_name}'"    items = []    async for item in container.query_items(query=query, enable_cross_partition_query=True):        items.append(item)    return itemsasync def main():    await create_products()    all_products = await get_products()    print('All Products:', all_products)    queried_products = await query_products('Widget')    print('Queried Products:', queried_products)if __name__ == "__main__":    asyncio.run(main())

Blueprints

The Python v2 programming model introduces the concept ofblueprints. A blueprint is a new class that's instantiated to register functions outside of the core function application. The functions registered in blueprint instances aren't indexed directly by the function runtime. To get these blueprint functions indexed, the function app needs to register the functions from blueprint instances.

Using blueprints provides the following benefits:

  • Lets you break up the function app into modular components, which enables you to define functions in multiple Python files and divide them into different components per file.
  • Provides extensible public function app interfaces to build and reuse your own APIs.

The following example shows how to use blueprints:

First, in anhttp_blueprint.py file, an HTTP-triggered function is first defined and added to a blueprint object.

import logging import azure.functions as func bp = func.Blueprint() @bp.route(route="default_template") def default_template(req: func.HttpRequest) -> func.HttpResponse:     logging.info('Python HTTP trigger function processed a request.')     name = req.params.get('name')     if not name:         try:             req_body = req.get_json()         except ValueError:             pass         else:             name = req_body.get('name')     if name:         return func.HttpResponse(             f"Hello, {name}. This HTTP-triggered function "             f"executed successfully.")     else:         return func.HttpResponse(             "This HTTP-triggered function executed successfully. "             "Pass a name in the query string or in the request body for a"             " personalized response.",             status_code=200         )

Next, in thefunction_app.py file, the blueprint object is imported and its functions are registered to the function app.

import azure.functions as func from http_blueprint import bpapp = func.FunctionApp() app.register_functions(bp)

Note

Durable Functions also supports blueprints. To create blueprints for Durable Functions apps, register your orchestration, activity, and entity triggers and client bindings using theazure-functions-durableBlueprint class, asshownhere. The resulting blueprint can then be registered as normal. See oursample for an example.

Import behavior

You can import modules in your function code by using both absolute and relative references. Based on the previously described folder structure, the following imports work from within the function file<project_root>\my_first_function\__init__.py:

from shared_code import my_first_helper_function #(absolute)
import shared_code.my_second_helper_function #(absolute)
from . import example #(relative)

Note

When you're using absolute import syntax, theshared_code/ folder needs to contain an__init__.py file to mark it as a Python package.

The following __app__ import and beyond top-level relative import are deprecated, because they're not supported by the static type checker and not supported by Python test frameworks:

from __app__.shared_code import my_first_helper_function #(deprecated __app__ import)
from ..shared_code import my_first_helper_function #(deprecated beyond top-level relative import)

Triggers and inputs

Inputs are divided into two categories in Azure Functions: trigger input and other input. Although they're different in thefunction.json file, their usage is identical in Python code. Connection strings or secrets for trigger and input sources map to values in thelocal.settings.json file when they're running locally, and they map to the application settings when they're running in Azure.

For example, the following code demonstrates the difference between the two inputs:

// function.json{  "scriptFile": "__init__.py",  "bindings": [    {      "name": "req",      "direction": "in",      "type": "httpTrigger",      "authLevel": "anonymous",      "route": "items/{id}"    },    {      "name": "obj",      "direction": "in",      "type": "blob",      "path": "samples/{id}",      "connection": "STORAGE_CONNECTION_STRING"    }  ]}
// local.settings.json{  "IsEncrypted": false,  "Values": {    "FUNCTIONS_WORKER_RUNTIME": "python",    "STORAGE_CONNECTION_STRING": "<AZURE_STORAGE_CONNECTION_STRING>",    "AzureWebJobsStorage": "<azure-storage-connection-string>"  }}
# __init__.pyimport azure.functions as funcimport loggingdef main(req: func.HttpRequest, obj: func.InputStream):    logging.info(f'Python HTTP-triggered function processed: {obj.read()}')

When the function is invoked, the HTTP request is passed to the function asreq. An entry is retrieved from the Azure Blob Storage account based on theID in the route URL and made available asobj in the function body. Here, the specified storage account is the connection string that's found in the<*_CONNECTION_STRING> app setting. For more information, see For more information, seeConnections.

Inputs are divided into two categories in Azure Functions: trigger input and other input. Although they're defined using different decorators, their usage is similar in Python code. Connection strings or secrets for trigger and input sources map to values in thelocal.settings.json file when they're running locally, and they map to the application settings when they're running in Azure.

As an example, the following code demonstrates how to define a Blob Storage input binding:

// local.settings.json{  "IsEncrypted": false,  "Values": {    "FUNCTIONS_WORKER_RUNTIME": "python",    "STORAGE_CONNECTION_STRING": "<AZURE_STORAGE_CONNECTION_STRING>",    "AzureWebJobsStorage": "<azure-storage-connection-string>"  }}
# function_app.pyimport azure.functions as funcimport loggingapp = func.FunctionApp()@app.route(route="req")@app.blob_input(arg_name="obj", path="samples/{id}",                connection="STORAGE_CONNECTION_STRING")def main(req: func.HttpRequest, obj: func.InputStream):    logging.info(f'Python HTTP-triggered function processed: {obj.read()}')

When the function is invoked, the HTTP request is passed to the function asreq. An entry is retrieved from the Azure Blob Storage account based on theID in the route URL and made available asobj in the function body. Here, the specified storage account is the connection string found in the<*_CONNECTION_STRING> app setting. For more information, see For more information, seeConnections.

For data intensive binding operations, you may want to use a separate storage account. For more information, seeStorage account guidance.

SDK type bindings

For select triggers and bindings, you can work with data types implemented by the underlying Azure SDKs and frameworks. TheseSDK type bindings let you interact binding data as if you were using the underlying service SDK.

`> [!IMPORTANT]

Using SDK type bindings requires thePython v2 programming model.

Important

SDK type bindings support for Python is only supported in the Python v2 programming model.

Prerequisites

SDK Types

ServiceTriggerInput bindingOutput bindingSamples
Azure BlobsGenerally availableGenerally availableSDK types not recommended.1Quickstart,
BlobClient,
ContainerClient,
StorageStreamDownloader
Azure Cosmos DBSDK types not used2PreviewSDK types not recommended.1Quickstart,
ContainerProxy,
CosmosClient,
DatabaseProxy
Azure Event HubsPreviewInput binding doesn't existSDK types not recommended.1Quickstart,
EventData
Azure Service BusPreviewInput binding doesn't existSDK types not recommended.1Quickstart,
ServiceBusReceivedMessage

1 For output scenarios in which you would use an SDK type, you should create and work with SDK clients directly instead of using an output binding.2 The Cosmos DB trigger uses theAzure Cosmos DB change feed and exposes change feed items as JSON-serializable types. The absence of SDK types is by-design for this scenario.

HTTP streams

HTTP streams lets you accept and return data from your HTTP endpoints using FastAPI request and response APIs enabled in your functions. These APIs lets the host process large data in HTTP messages as chunks instead of reading an entire message into memory.

This feature makes it possible to handle large data stream, OpenAI integrations, deliver dynamic content, and support other core HTTP scenarios requiring real-time interactions over HTTP. You can also use FastAPI response types with HTTP streams. Without HTTP streams, the size of your HTTP requests and responses are limited by memory restrictions that can be encountered when processing entire message payloads all in memory.

To learn more, including how to enable HTTP streams in your project, seeHTTP Streams.

Important

Support for HTTP streams requires thePython v2 programming model.

Important

HTTP streams support for Python is generally available and requires you to use the Python v2 programming model.

Outputs

Output can be expressed both in return value and output parameters. If there's only one output, we recommend using the return value. For multiple outputs, you must use output parameters.

To use the return value of a function as the value of an output binding, thename property of the binding should be set to$return in thefunction.json file.

To produce multiple outputs, use theset() method provided by theazure.functions.Out interface to assign a value to the binding. For example, the following function can push a message to a queue and also return an HTTP response.

{  "scriptFile": "__init__.py",  "bindings": [    {      "name": "req",      "direction": "in",      "type": "httpTrigger",      "authLevel": "anonymous"    },    {      "name": "msg",      "direction": "out",      "type": "queue",      "queueName": "outqueue",      "connection": "STORAGE_CONNECTION_STRING"    },    {      "name": "$return",      "direction": "out",      "type": "http"    }  ]}
import azure.functions as funcdef main(req: func.HttpRequest,         msg: func.Out[func.QueueMessage]) -> str:    message = req.params.get('body')    msg.set(message)    return message

Output can be expressed both in return value and output parameters. If there's only one output, we recommend using the return value. For multiple outputs, you'll have to use output parameters.

To produce multiple outputs, use theset() method provided by theazure.functions.Out interface to assign a value to the binding. For example, the following function can push a message to a queue and also return an HTTP response.

# function_app.pyimport azure.functions as funcapp = func.FunctionApp()@app.write_blob(arg_name="msg", path="output-container/{name}",                connection="CONNECTION_STRING")def test_function(req: func.HttpRequest,                  msg: func.Out[str]) -> str:    message = req.params.get('body')    msg.set(message)    return message

Logging

Access to the Azure Functions runtime logger is available via a rootlogging handler in your function app. This logger is tied to Application Insights and allows you to flag warnings and errors that occur during the function execution.

The following example logs an info message when the function is invoked via an HTTP trigger.

import loggingdef main(req):    logging.info('Python HTTP trigger function processed a request.')

More logging methods are available that let you write to the console at different trace levels:

MethodDescription
critical(_message_)Writes a message with level CRITICAL on the root logger.
error(_message_)Writes a message with level ERROR on the root logger.
warning(_message_)Writes a message with level WARNING on the root logger.
info(_message_)Writes a message with level INFO on the root logger.
debug(_message_)Writes a message with level DEBUG on the root logger.

To learn more about logging, seeMonitor Azure Functions.

Logging from created threads

To see logs coming from your created threads, include thecontext argument in the function's signature. This argument contains an attributethread_local_storage that stores a localinvocation_id. This can be set to the function's currentinvocation_id to ensure the context is changed.

import azure.functions as funcimport loggingimport threadingdef main(req, context):    logging.info('Python HTTP trigger function processed a request.')    t = threading.Thread(target=log_function, args=(context,))    t.start()def log_function(context):    context.thread_local_storage.invocation_id = context.invocation_id    logging.info('Logging from thread.')

Log custom telemetry

By default, the Functions runtime collects logs and other telemetry data that are generated by your functions. This telemetry ends up as traces in Application Insights. Request and dependency telemetry for certain Azure services are also collected by default bytriggers and bindings.

To collect custom request and custom dependency telemetry outside of bindings, you can use theOpenCensus Python Extensions. This extension sends custom telemetry data to your Application Insights instance. You can find a list of supported extensions at theOpenCensus repository.

Note

To use the OpenCensus Python extensions, you need to enablePython worker extensions in your function app by settingPYTHON_ENABLE_WORKER_EXTENSIONS to1. You also need to switch to using the Application Insights connection string by adding theAPPLICATIONINSIGHTS_CONNECTION_STRING setting to yourapplication settings, if it's not already there.

// requirements.txt...opencensus-extension-azure-functionsopencensus-ext-requests
import jsonimport loggingimport requestsfrom opencensus.extension.azure.functions import OpenCensusExtensionfrom opencensus.trace import config_integrationconfig_integration.trace_integrations(['requests'])OpenCensusExtension.configure()def main(req, context):    logging.info('Executing HttpTrigger with OpenCensus extension')    # You must use context.tracer to create spans    with context.tracer.span("parent"):        response = requests.get(url='http://example.com')    return json.dumps({        'method': req.method,        'response': response.status_code,        'ctx_func_name': context.function_name,        'ctx_func_dir': context.function_directory,        'ctx_invocation_id': context.invocation_id,        'ctx_trace_context_Traceparent': context.trace_context.Traceparent,        'ctx_trace_context_Tracestate': context.trace_context.Tracestate,        'ctx_retry_context_RetryCount': context.retry_context.retry_count,        'ctx_retry_context_MaxRetryCount': context.retry_context.max_retry_count,    })

HTTP trigger

The HTTP trigger is defined in thefunction.json file. Thename of the binding must match the named parameter in the function.In the previous examples, a binding namereq is used. This parameter is anHttpRequest object, and anHttpResponse object is returned.

From theHttpRequest object, you can get request headers, query parameters, route parameters, and the message body.

The following example is from theHTTP trigger template for Python.

def main(req: func.HttpRequest) -> func.HttpResponse:    headers = {"my-http-header": "some-value"}    name = req.params.get('name')    if not name:        try:            req_body = req.get_json()        except ValueError:            pass        else:            name = req_body.get('name')    if name:        return func.HttpResponse(f"Hello {name}!", headers=headers)    else:        return func.HttpResponse(             "Please pass a name on the query string or in the request body",             headers=headers, status_code=400        )

In this function, you obtain the value of thename query parameter from theparams parameter of theHttpRequest object. You read the JSON-encoded message body by using theget_json method.

Likewise, you can set thestatus_code andheaders for the response message in the returnedHttpResponse object.

The HTTP trigger is defined as a method that takes a named binding parameter, which is anHttpRequest object, and returns anHttpResponse object. You apply thefunction_name decorator to the method to define the function name, while the HTTP endpoint is set by applying theroute decorator.

This example is from the HTTP trigger template for the Python v2 programming model, where the binding parameter name isreq. It's the sample code that's provided when you create a function by using Azure Functions Core Tools or Visual Studio Code.

@app.function_name(name="HttpTrigger1")@app.route(route="hello")def test_function(req: func.HttpRequest) -> func.HttpResponse:     logging.info('Python HTTP trigger function processed a request.')     name = req.params.get('name')     if not name:        try:            req_body = req.get_json()        except ValueError:            pass        else:            name = req_body.get('name')     if name:        return func.HttpResponse(f"Hello, {name}. This HTTP-triggered function executed successfully.")     else:        return func.HttpResponse(             "This HTTP-triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",             status_code=200        )

From theHttpRequest object, you can get request headers, query parameters, route parameters, and the message body. In this function, you obtain the value of thename query parameter from theparams parameter of theHttpRequest object. You read the JSON-encoded message body by using theget_json method.

Likewise, you can set thestatus_code andheaders for the response message in the returnedHttpResponse object.

To pass in a name in this example, paste the URL that's provided when you're running the function, and then append it with"?name={name}".

Web frameworks

You can use Web Server Gateway Interface (WSGI)-compatible and Asynchronous Server Gateway Interface (ASGI)-compatible frameworks, such as Flask and FastAPI, with your HTTP-triggered Python functions. This section shows how to modify your functions to support these frameworks.

First, thefunction.json file must be updated to include aroute in the HTTP trigger, as shown in the following example:

{  "scriptFile": "__init__.py",  "bindings": [    {       "authLevel": "anonymous",       "type": "httpTrigger",       "direction": "in",       "name": "req",       "methods": [           "get",           "post"       ],       "route": "{*route}"    },    {       "type": "http",       "direction": "out",       "name": "$return"    }  ]}

Thehost.json file must also be updated to include an HTTProutePrefix, as shown in the following example:

{  "version": "2.0",  "logging":   {    "applicationInsights":     {      "samplingSettings":       {        "isEnabled": true,        "excludedTypes": "Request"      }    }  },  "extensionBundle":   {    "id": "Microsoft.Azure.Functions.ExtensionBundle",    "version": "[4.*, 5.0.0)"  },  "extensions":   {    "http":     {        "routePrefix": ""    }  }}

Update the Python code fileinit.py, depending on the interface that's used by your framework. The following example shows either an ASGI handler approach or a WSGI wrapper approach for Flask:

app = fastapi.FastAPI()@app.get("hello/{name}")async def get_name(name: str):  return {"name": name}def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:    return func.AsgiMiddleware(app).handle(req, context)

You can use Asynchronous Server Gateway Interface (ASGI)-compatible and Web Server Gateway Interface (WSGI)-compatible frameworks, such as Flask and FastAPI, with your HTTP-triggered Python functions. You must first update thehost.json file to include an HTTProutePrefix, as shown in the following example:

{  "version": "2.0",  "logging":   {    "applicationInsights":     {      "samplingSettings":       {        "isEnabled": true,        "excludedTypes": "Request"      }    }  },  "extensionBundle":   {    "id": "Microsoft.Azure.Functions.ExtensionBundle",    "version": "[4.*, 5.0.0)"  },  "extensions":   {    "http":     {        "routePrefix": ""    }  }}

The framework code looks like the following example:

AsgiFunctionApp is the top-level function app class for constructing ASGI HTTP functions.

# function_app.pyimport azure.functions as func from fastapi import FastAPI, Request, Response fast_app = FastAPI() @fast_app.get("/return_http_no_body") async def return_http_no_body():     return Response(content="", media_type="text/plain") app = func.AsgiFunctionApp(app=fast_app,                            http_auth_level=func.AuthLevel.ANONYMOUS)

Scaling and performance

For scaling and performance best practices for Python function apps, see thePython scaling and performance article.

Context

To get the invocation context of a function when it's running, include thecontext argument in its signature.

For example:

import azure.functionsdef main(req: azure.functions.HttpRequest,         context: azure.functions.Context) -> str:    return f'{context.invocation_id}'

TheContext class has the following string attributes:

AttributeDescription
function_directoryThe directory in which the function is running.
function_nameThe name of the function.
invocation_idThe ID of the current function invocation.
thread_local_storageThe thread local storage of the function. Contains a localinvocation_id forlogging from created threads.
trace_contextThe context for distributed tracing. For more information, seeTrace Context.
retry_contextThe context for retries to the function. For more information, seeretry-policies.

Global variables

It isn't guaranteed that the state of your app will be preserved for future executions. However, the Azure Functions runtime often reuses the same process for multiple executions of the same app. To cache the results of an expensive computation, declare it as a global variable.

CACHED_DATA = Nonedef main(req):    global CACHED_DATA    if CACHED_DATA is None:        CACHED_DATA = load_json()    # ... use CACHED_DATA in code

Environment variables

In Azure Functions,application settings, such as service connection strings, are exposed as environment variables when they're running. There are two main ways to access these settings in your code.

MethodDescription
os.environ["myAppSetting"]Tries to get the application setting by key name, and raises an error when it's unsuccessful.
os.getenv("myAppSetting")Tries to get the application setting by key name, and returnsNone when it's unsuccessful.

Both of these ways require you to declareimport os.

The following example usesos.environ["myAppSetting"] to get theapplication setting, with the key namedmyAppSetting:

import loggingimport osimport azure.functions as funcdef main(req: func.HttpRequest) -> func.HttpResponse:  # Get the setting named 'myAppSetting'  my_app_setting_value = os.environ["myAppSetting"]  logging.info(f'My app setting value:{my_app_setting_value}')

For local development, application settings aremaintained in thelocal.settings.json file.

In Azure Functions,application settings, such as service connection strings, are exposed as environment variables when they're running. There are two main ways to access these settings in your code.

MethodDescription
os.environ["myAppSetting"]Tries to get the application setting by key name, and raises an error when it's unsuccessful.
os.getenv("myAppSetting")Tries to get the application setting by key name, and returnsNone when it's unsuccessful.

Both of these ways require you to declareimport os.

The following example usesos.environ["myAppSetting"] to get theapplication setting, with the key namedmyAppSetting:

import loggingimport osimport azure.functions as funcapp = func.FunctionApp()@app.function_name(name="HttpTrigger1")@app.route(route="req")def main(req: func.HttpRequest) -> func.HttpResponse:  # Get the setting named 'myAppSetting'  my_app_setting_value = os.environ["myAppSetting"]  logging.info(f'My app setting value:{my_app_setting_value}')

For local development, application settings aremaintained in thelocal.settings.json file.

Python version

Azure Functions supports the following Python versions:

Functions versionPython* versions
4.x3.12
3.11
3.10

* Official Python distributions

To request a specific Python version when you create your function app in Azure, use the--runtime-version option of theaz functionapp create command. The Functions runtime version is set by the--functions-version option. The Python version is set when the function app is created, and it can't be changed for apps running in a Consumption plan.

The runtime uses the available Python version when you run it locally.

Changing Python version

To set a Python function app to a specific language version, you need to specify the language and the version of the language in theLinuxFxVersion field in the site configuration. For example, to change the Python app to use Python 3.12, setlinuxFxVersion topython|3.12.

To learn how to view and change thelinuxFxVersion site setting, seeHow to target Azure Functions runtime versions.

For more general information, see theAzure Functions runtime support policy andSupported languages in Azure Functions.

Package management

When you're developing locally by using Core Tools or Visual Studio Code, add the names and versions of the required packages to therequirements.txt file, and then install them by usingpip.

For example, you can use the followingrequirements.txt file andpip command to install therequests package from PyPI.

requests==2.19.1
pip install -r requirements.txt

When running your functions in anApp Service plan, dependencies that you define in requirements.txt are given precedence over built-in Python modules, such aslogging. This precedence can cause conflicts when built-in modules have the same names as directories in your code. When running in aConsumption plan or anElastic Premium plan, conflicts are less likely because your dependencies aren't prioritized by default.

To prevent issues running in an App Service plan, don't name your directories the same as any Python native modules and don't include Python native libraries in your project's requirements.txt file.

Publishing to Azure

When you're ready to publish, make sure that all your publicly available dependencies are listed in therequirements.txt file. You can locate this file at the root of your project directory.

You can find the project files and folders that are excluded from publishing, including the virtual environment folder, in the root directory of your project.

There are three build actions supported for publishing your Python project to Azure: remote build, local build, and builds using custom dependencies.

You can also use Azure Pipelines to build your dependencies and publish by using continuous delivery (CD). To learn more, seeContinuous delivery with Azure Pipelines.

Remote build

When you use remote build, dependencies that are restored on the server and native dependencies match the production environment. This results in a smaller deployment package to upload. Use remote build when you're developing Python apps on Windows. If your project has custom dependencies, you canuse remote build with extra index URL.

Dependencies are obtained remotely based on the contents of therequirements.txt file.Remote build is the recommended build method. By default, Core Tools requests a remote build when you use the followingfunc azure functionapp publish command to publish your Python project to Azure.

func azure functionapp publish <APP_NAME>

Remember to replace<APP_NAME> with the name of your function app in Azure.

TheAzure Functions Extension for Visual Studio Code also requests a remote build by default.

Local build

Dependencies are obtained locally based on the contents of therequirements.txt file. You can prevent doing a remote build by using the followingfunc azure functionapp publish command to publish with a local build:

func azure functionapp publish <APP_NAME> --build local

Remember to replace<APP_NAME> with the name of your function app in Azure.

When you use the--build local option, project dependencies are read from therequirements.txt file, and those dependent packages are downloaded and installed locally. Project files and dependencies are deployed from your local computer to Azure. This results in a larger deployment package being uploaded to Azure. If for some reason you can't get therequirements.txt file by using Core Tools, you must use the custom dependencies option for publishing.

We don't recommend using local builds when you're developing locally on Windows.

Custom dependencies

When your project has dependencies that aren't found in thePython Package Index, there are two ways to build the project. The first way, thebuild method, depends on how you build the project.

Remote build with extra index URL

When your packages are available from an accessible custom package index, use a remote build. Before you publish, be sure tocreate an app setting namedPIP_EXTRA_INDEX_URL. The value for this setting is the URL of your custom package index. Using this setting tells the remote build to runpip install by using the--extra-index-url option. To learn more, see thePythonpip install documentation.

You can also use basic authentication credentials with your extra package index URLs. To learn more, seeBasic authentication credentials in the Python documentation.

Install local packages

If your project uses packages that aren't publicly available to our tools, you can make them available to your app by putting them in the__app__/.python_packages directory. Before you publish, run the following command to install the dependencies locally:

pip install  --target="<PROJECT_DIR>/.python_packages/lib/site-packages"  -r requirements.txt

When you're using custom dependencies, you should use the--no-build publishing option, because you've already installed the dependencies into the project folder.

func azure functionapp publish <APP_NAME> --no-build

Remember to replace<APP_NAME> with the name of your function app in Azure.

Unit testing

Unit testing through pytest

Functions that are written in Python can be tested like other Python code by using standard testing frameworks. For most bindings, it's possible to create a mock input object by creating an instance of an appropriate class from theazure.functions package. Since theazure.functions package isn't immediately available, be sure to install it via yourrequirements.txt file as described in thepackage management section above.

Withmy_second_function as an example, the following is a mock test of an HTTP-triggered function:

First, create a<project_root>/my_second_function/function.json file, and then define this function as an HTTP trigger.

{  "scriptFile": "__init__.py",  "entryPoint": "main",  "bindings": [    {      "authLevel": "function",      "type": "httpTrigger",      "direction": "in",      "name": "req",      "methods": [        "get",        "post"      ]    },    {      "type": "http",      "direction": "out",      "name": "$return"    }  ]}

Next, you can implementmy_second_function andshared_code.my_second_helper_function.

# <project_root>/my_second_function/__init__.pyimport azure.functions as funcimport logging# Use absolute import to resolve shared_code modulesfrom shared_code import my_second_helper_function# Define an HTTP trigger that accepts the ?value=<int> query parameter# Double the value and return the result in HttpResponsedef main(req: func.HttpRequest) -> func.HttpResponse:  logging.info('Executing my_second_function.')  initial_value: int = int(req.params.get('value'))  doubled_value: int = my_second_helper_function.double(initial_value)  return func.HttpResponse(    body=f"{initial_value} * 2 = {doubled_value}",    status_code=200    )
# <project_root>/shared_code/__init__.py# Empty __init__.py file marks shared_code folder as a Python package
# <project_root>/shared_code/my_second_helper_function.pydef double(value: int) -> int:  return value * 2

You can start writing test cases for your HTTP trigger.

# <project_root>/tests/test_my_second_function.pyimport unittestimport azure.functions as funcfrom my_second_function import mainclass TestFunction(unittest.TestCase):  def test_my_second_function(self):    # Construct a mock HTTP request.    req = func.HttpRequest(method='GET',                           body=None,                           url='/api/my_second_function',                           params={'value': '21'})    # Call the function.    resp = main(req)    # Check the output.    self.assertEqual(resp.get_body(), b'21 * 2 = 42',)

Inside your.venv Python virtual environment folder, install your favorite Python test framework, such aspip install pytest. Then runpytest tests to check the test result.

First, create the<project_root>/function_app.py file and implement themy_second_function function as the HTTP trigger andshared_code.my_second_helper_function.

# <project_root>/function_app.pyimport azure.functions as funcimport logging# Use absolute import to resolve shared_code modulesfrom shared_code import my_second_helper_functionapp = func.FunctionApp()# Define the HTTP trigger that accepts the ?value=<int> query parameter# Double the value and return the result in HttpResponse@app.function_name(name="my_second_function")@app.route(route="hello")def main(req: func.HttpRequest) -> func.HttpResponse:    logging.info('Executing my_second_function.')    initial_value: int = int(req.params.get('value'))    doubled_value: int = my_second_helper_function.double(initial_value)    return func.HttpResponse(        body=f"{initial_value} * 2 = {doubled_value}",        status_code=200    )
# <project_root>/shared_code/__init__.py# Empty __init__.py file marks shared_code folder as a Python package
# <project_root>/shared_code/my_second_helper_function.pydef double(value: int) -> int:  return value * 2

You can start writing test cases for your HTTP trigger.

# <project_root>/tests/test_my_second_function.pyimport unittestimport azure.functions as funcfrom function_app import mainclass TestFunction(unittest.TestCase):  def test_my_second_function(self):    # Construct a mock HTTP request.    req = func.HttpRequest(method='GET',                           body=None,                           url='/api/my_second_function',                           params={'value': '21'})    # Call the function.    func_call = main.build().get_user_function()    resp = func_call(req)    # Check the output.    self.assertEqual(        resp.get_body(),        b'21 * 2 = 42',    )

Inside your.venv Python virtual environment folder, install your favorite Python test framework, such aspip install pytest. Then runpytest tests to check the test result.

Unit testing by invoking the function directly

Withazure-functions >= 1.21.0, functions can also be called directly using the Python interpreter. This example shows how to unit test an HTTP trigger using the v2 programming model:

# <project_root>/function_app.pyimport azure.functions as funcimport loggingapp = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)@app.route(route="http_trigger")def http_trigger(req: func.HttpRequest) -> func.HttpResponse:    return "Hello, World!"print(http_trigger(None))

Note that with this approach, no additional package or setup is required. The function can be tested by callingpython function_app.py, and it results inHello, World! output in the terminal.

Note

Durable Functions require special syntax for unit testing. For more information, refer toUnit Testing Durable Functions in Python

Temporary files

Thetempfile.gettempdir() method returns a temporary folder, which on Linux is/tmp. Your application can use this directory to store temporary files that are generated and used by your functions when they're running.

Important

Files written to the temporary directory aren't guaranteed to persist across invocations. During scale out, temporary files aren't shared between instances.

The following example creates a named temporary file in the temporary directory (/tmp):

import loggingimport azure.functions as funcimport tempfilefrom os import listdir#---   tempFilePath = tempfile.gettempdir()   fp = tempfile.NamedTemporaryFile()   fp.write(b'Hello world!')   filesDirListInTemp = listdir(tempFilePath)

We recommend that you maintain your tests in a folder that's separate from the project folder. This action keeps you from deploying test code with your app.

Preinstalled libraries

A few libraries come with the Python functions runtime.

The Python standard library

The Python standard library contains a list of built-in Python modules that are shipped with each Python distribution. Most of these libraries help you access system functionality, such as file input/output (I/O). On Windows systems, these libraries are installed with Python. On Unix-based systems, they're provided by package collections.

To view the library for your Python version, go to:

Azure Functions Python worker dependencies

The Azure Functions Python worker requires a specific set of libraries. You can also use these libraries in your functions, but they aren't a part of the Python standard. If your functions rely on any of these libraries, they might be unavailable to your code when it's running outside of Azure Functions.

Note

If your function app'srequirements.txt file contains anazure-functions-worker entry, remove it. The functions worker is automatically managed by the Azure Functions platform, and we regularly update it with new features and bug fixes. Manually installing an old version of worker in therequirements.txt file might cause unexpected issues.

Note

If your package contains certain libraries that might collide with worker's dependencies (for example, protobuf, tensorflow, or grpcio), configurePYTHON_ISOLATE_WORKER_DEPENDENCIES to1 in app settings to prevent your application from referring to worker's dependencies.

The Azure Functions Python library

Every Python worker update includes a new version of theAzure Functions Python library (azure.functions). This approach makes it easier to continuously update your Python function apps, because each update is backwards-compatible. For a list of releases of this library, go toazure-functions PyPi.

The runtime library version is fixed by Azure, and it can't be overridden byrequirements.txt. Theazure-functions entry inrequirements.txt is only for linting and customer awareness.

Use the following code to track the actual version of the Python functions library in your runtime:

getattr(azure.functions, '__version__', '< 1.2.1')

Runtime system libraries

For a list of preinstalled system libraries in Python worker Docker images, see the following:

Functions runtimeDebian versionPython versions
Version 3.xBusterPython 3.7
Python 3.8
Python 3.9

Python worker extensions

The Python worker process that runs in Azure Functions lets you integrate third-party libraries into your function app. These extension libraries act as middleware that can inject specific operations during the lifecycle of your function's execution.

Extensions are imported in your function code much like a standard Python library module. Extensions are run based on the following scopes:

ScopeDescription
Application-levelWhen imported into any function trigger, the extension applies to every function execution in the app.
Function-levelExecution is limited to only the specific function trigger into which it's imported.

Review the information for each extension to learn more about the scope in which the extension runs.

Extensions implement a Python worker extension interface. This action lets the Python worker process call into the extension code during the function's execution lifecycle. To learn more, seeCreate extensions.

Using extensions

You can use a Python worker extension library in your Python functions by doing the following:

  1. Add the extension package in therequirements.txt file for your project.
  2. Install the library into your app.
  3. Add the following application settings:
  4. Import the extension module into your function trigger.
  5. Configure the extension instance, if needed. Configuration requirements should be called out in the extension's documentation.

Important

Third-party Python worker extension libraries aren't supported or warrantied by Microsoft. You must make sure that any extensions that you use in your function app is trustworthy, and you bear the full risk of using a malicious or poorly written extension.

Third-parties should provide specific documentation on how to install and consume their extensions in your function app. For a basic example of how to consume an extension, seeConsuming your extension.

Here are examples of using extensions in a function app, by scope:

# <project_root>/requirements.txtapplication-level-extension==1.0.0
# <project_root>/Trigger/__init__.pyfrom application_level_extension import AppExtensionAppExtension.configure(key=value)def main(req, context):  # Use context.app_ext_attributes here

Creating extensions

Extensions are created by third-party library developers who have created functionality that can be integrated into Azure Functions. An extension developer designs, implements, and releases Python packages that contain custom logic designed specifically to be run in the context of function execution. These extensions can be published either to the PyPI registry or to GitHub repositories.

To learn how to create, package, publish, and consume a Python worker extension package, seeDevelop Python worker extensions for Azure Functions.

Application-level extensions

An extension that's inherited fromAppExtensionBase runs in anapplication scope.

AppExtensionBase exposes the following abstract class methods for you to implement:

MethodDescription
initCalled after the extension is imported.
configureCalled from function code when it's needed to configure the extension.
post_function_load_app_levelCalled right after the function is loaded. The function name and function directory are passed to the extension. Keep in mind that the function directory is read-only, and any attempt to write to a local file in this directory fails.
pre_invocation_app_levelCalled right before the function is triggered. The function context and function invocation arguments are passed to the extension. You can usually pass other attributes in the context object for the function code to consume.
post_invocation_app_levelCalled right after the function execution finishes. The function context, function invocation arguments, and invocation return object are passed to the extension. This implementation is a good place to validate whether execution of the lifecycle hooks succeeded.

Function-level extensions

An extension that inherits fromFuncExtensionBase runs in a specific function trigger.

FuncExtensionBase exposes the following abstract class methods for implementations:

MethodDescription
__init__The constructor of the extension. It's called when an extension instance is initialized in a specific function. When you're implementing this abstract method, you might want to accept afilename parameter and pass it to the parent's methodsuper().__init__(filename) for proper extension registration.
post_function_loadCalled right after the function is loaded. The function name and function directory are passed to the extension. Keep in mind that the function directory is read-only, and any attempt to write to a local file in this directory fails.
pre_invocationCalled right before the function is triggered. The function context and function invocation arguments are passed to the extension. You can usually pass other attributes in the context object for the function code to consume.
post_invocationCalled right after the function execution finishes. The function context, function invocation arguments, and invocation return object are passed to the extension. This implementation is a good place to validate whether execution of the lifecycle hooks succeeded.

Cross-origin resource sharing

Azure Functions supports cross-origin resource sharing (CORS). CORS is configuredin the portal and through theAzure CLI. The CORS allowed origins list applies at the function app level. With CORS enabled, responses include theAccess-Control-Allow-Origin header. For more information, seeCross-origin resource sharing.

Cross-origin resource sharing (CORS) is fully supported for Python function apps.

Async

By default, a host instance for Python can process only one function invocation at a time. This is because Python is a single-threaded runtime. For a function app that processes a large number of I/O events or is being I/O bound, you can significantly improve performance by running functions asynchronously. For more information, seeImprove throughout performance of Python apps in Azure Functions.

Shared memory (preview)

To improve throughput, Azure Functions lets your out-of-process Python language worker share memory with the Functions host process. When your function app is hitting bottlenecks, you can enable shared memory by adding an application setting namedFUNCTIONS_WORKER_SHARED_MEMORY_DATA_TRANSFER_ENABLED with a value of1. With shared memory enabled, you can then use theDOCKER_SHM_SIZE setting to set the shared memory to something like268435456, which is equivalent to 256 MB.

For example, you might enable shared memory to reduce bottlenecks when you're using Blob Storage bindings to transfer payloads larger than 1 MB.

This functionality is available only for function apps that are running in Premium and Dedicated (Azure App Service) plans. To learn more, seeShared memory.

Known issues and FAQ

Here are two troubleshooting guides for common issues:

Here are two troubleshooting guides for known issues with the v2 programming model:

All known issues and feature requests are tracked in aGitHub issues list. If you run into a problem and can't find the issue in GitHub, open a new issue, and include a detailed description of the problem.

Next steps

For more information, see the following resources:

Having issues with using Python? Tell us what's going on.


Feedback

Was this page helpful?

YesNo

In this article

Was this page helpful?

YesNo