Azure Functions の Python 開発者向けガイド

このガイドでは、Python を使用した Azure Functions の開発について紹介します。 この記事では、「Azure Functions の開発者向けガイド」を既に読んでいることを前提としています。

重要

この記事では、Azure Functions での Python プログラミング モデルの v1 と v2 の両方をサポートします。 Python v1 モデルでは functions.json ファイルを使用して関数を定義しますが、新しい v2 モデルでは代わりにデコレーターベースのアプローチを使用できます。 この新しいアプローチにより、ファイル構造がシンプルになり、コード中心になります。 この新しいプログラミング モデルについて学習するには、記事の上部にある v2 セレクターを選択します。

Python 開発者は、以下のトピックにも興味があるかもしれません。

開発オプション

どちらの Python Functions プログラミング モデルでも、次の環境のいずれかでローカル開発がサポートされます。

Python v2 プログラミング モデル:

Python v1 プログラミング モデル:

Azure portal で Python v1 関数を作成することもできます。

ヒント

Python ベースの Azure 関数を Windows 上のローカルで開発できますが、Python は、Azure で実行されている場合、Linux ベースのホスティング プランでのみサポートされます。 詳細については、サポートされているオペレーティング システムとランタイムの組み合わせの一覧を参照してください。

プログラミング モデル

Azure Functions では、関数は入力を処理して出力を生成する Python スクリプト内のステートレスなメソッドであることが求められます。 既定で、ランタイムでは、このメソッドは main() と呼ばれるグローバル メソッドとして _init_.py ファイル内に実装されると想定されます。 また、代替エントリ ポイントを指定することもできます。

トリガーとバインディングからのデータをメソッド属性を介して関数にバインドするには、function.json ファイル内で定義されている name プロパティを使用します。 たとえば、次の function.json ファイルには、req という名前の HTTP 要求によってトリガーされるシンプルな関数が記述されています。

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

この定義に基づき、関数コードを含む _init_.py ファイルは次の例のようになります。

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

Python の型の注釈を使用することで、関数内に属性の種類および戻り値の型を明示的に宣言することもできます。 こうすることで、多くの Python コード エディターによって提供される IntelliSense とオートコンプリート機能を使うのに役立ちます。

import azure.functions

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

azure.functions.* パッケージに含まれる Python の注釈を使用すると、入力と出力がご利用のメソッドにバインドされます。

Azure Functions では、関数は入力を処理して出力を生成する Python スクリプト内のステートレスなメソッドであることが求められます。 既定で、ランタイムでは、このメソッドはグローバル メソッドとして function_app.py ファイル内に実装されると想定されます。

デコレーター ベースのアプローチでは、トリガーとバインドは関数で宣言および使用できます。 これらは、関数と同じファイル function_app.py で定義されています。 例として、次の function_app.py ファイルは、HTTP 要求によってトリガーされる関数を表します。

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

Python の型の注釈を使用することで、関数内に属性の種類および戻り値の型を明示的に宣言することもできます。 こうすることで、多くの Python コード エディターによって提供される IntelliSense とオートコンプリート機能を使うのに役立ちます。

import azure.functions as func

app = 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}!"

v2 モデルに関する既知の制限事項とその回避策については、「Azure Functions での Python エラーのトラブルシューティング」を参照してください。

代替エントリ ポイント

scriptFile ファイル内で scriptFile プロパティと entryPoint プロパティをオプションで指定することによって、関数の既定の動作を変更できます。 たとえば、以下の function.json では、ご利用の Azure 関数のエントリ ポイントとして、main.py ファイル内の customentry() メソッドを使用するようにランタイムに指示が出されます。

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

エントリ ポイントは function_app.py ファイル内のみにあります。 ただし、プロジェクト内の関数は、ブループリントを使用するかインポートして、function_app.py で参照できます。

フォルダー構造

Python 関数プロジェクトの推奨フォルダー構造は、次の例のようになります。

 <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

メイン プロジェクト フォルダー <> には、次のファイルを含めることができます。

  • local.settings.json:ローカルで実行するときに、アプリの設定と接続文字列を格納するために使用されます。 このファイルは Azure に公開されません。 詳細については、「local.settings.file」に関するページを参照してください。
  • requirements.txt:Azure に公開するときにシステムによってインストールされる Python パッケージの一覧が含まれます。
  • host.json: 関数アプリ インスタンス内にあるすべての関数に影響する構成オプションが含まれます。 このファイルは Azure に公開されます。 ローカルで実行する場合は、すべてのオプションがサポートされるわけではありません。 詳細については、「host.json」に関するページを参照してください。
  • .vscode/: (省略可能) 格納されている Visual Studio Code 構成が含まれます。 詳細については、Visual Studio Code の設定に関するページを参照してください。
  • .venv/ :(省略可能) ローカル開発で使用される Python 仮想環境が含まれます。
  • Dockerfile:(省略可能) カスタム コンテナーでプロジェクトを発行するときに使用されます。
  • tests/ :(省略可能) 関数アプリのテスト ケースが含まれます。
  • .funcignore:(省略可能) Azure に発行しないファイルを宣言します。 通常、このファイルには、エディター設定を無視する場合は .vscode/、ローカルの Python 仮想環境を無視する場合は .venv/、テスト ケースを無視する場合は tests/、ローカル アプリの設定を発行しない場合は local.settings.json が含まれます。

各関数には、独自のコード ファイルとバインディング構成ファイル function.json があります。

Python 関数プロジェクトの推奨フォルダー構造は、次の例のようになります。

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

メイン プロジェクト フォルダー <> には、次のファイルを含めることができます。

  • .venv/: (省略可能) ローカル開発に使用される Python 仮想環境が含まれます。
  • .vscode/: (省略可能) 格納されている Visual Studio Code 構成が含まれます。 詳細については、Visual Studio Code の設定に関するページを参照してください。
  • function_app.py: すべての関数とそれに関連するトリガーとバインドの既定の場所です。
  • additional_functions.py: (省略可能) ブループリントを介して function_app.py で参照される関数 (通常は論理グループ化用) を含む他の Python ファイル。
  • tests/ :(省略可能) 関数アプリのテスト ケースが含まれます。
  • .funcignore:(省略可能) Azure に発行しないファイルを宣言します。 通常、このファイルには、エディター設定を無視する場合は .vscode/、ローカルの Python 仮想環境を無視する場合は .venv/、テスト ケースを無視する場合は tests/、ローカル アプリの設定を発行しない場合は local.settings.json が含まれます。
  • host.json: 関数アプリ インスタンス内にあるすべての関数に影響する構成オプションが含まれます。 このファイルは Azure に公開されます。 ローカルで実行する場合は、すべてのオプションがサポートされるわけではありません。 詳細については、「host.json」に関するページを参照してください。
  • local.settings.json: ローカルで実行するとき、アプリ設定と接続文字列を格納するために使用されます。 このファイルは Azure に公開されません。 詳細については、「local.settings.file」に関するページを参照してください。
  • requirements.txt: Azure に公開するときにシステムによってインストールされる Python パッケージの一覧が含まれます。
  • Dockerfile:(省略可能) カスタム コンテナーでプロジェクトを発行するときに使用されます。

Azure の関数アプリにプロジェクトをデプロイするときは、メイン プロジェクト フォルダー <project_root> の内容全体をパッケージに含める必要がありますが、フォルダー自体は含めないでください。つまり、host.json はパッケージ ルートに存在する必要があります。 テストは、他の関数と一緒に 1 つのフォルダーに保存することをお勧めします (この例では tests/)。 詳細については、「単体テスト」を参照してください。

データベースへの接続

Azure Functions は、IoT、e コマース、ゲームなど、多くのユース ケースAzure Cosmos DB と密接に統合されています。

たとえば、イベント ソーシングの場合、2 つのサービスは、Azure Cosmos DB の変更フィード機能を使用してイベント ドリブン アーキテクチャを提供するために統合されます。 変更フィードでは、段階的かつ確実に挿入と更新を読み取る (注文イベントなど) 機能をダウンストリームのマイクロサービスに提供します。 この機能を利用すれば、状態の変化するイベントのメッセージ ブローカーとして永続的なイベント ストアを提供し、多数のマイクロサービス間で注文処理ワークフローを稼働することができます (サーバーレス Azure Functions として実装可能)。

Azure Cosmos DB 注文パイプライン リファレンス アーキテクチャ

Azure Cosmos DB に接続するには、まずアカウント、データベース、コンテナーを作成します。 その後、次ののように、トリガーとバインドを使用して、関数コードを Azure Cosmos DB に接続できます。

より複雑なアプリ ロジックを実装するには、Cosmos DB 用の Python ライブラリを使用することもできます。 非同期 I/O 実装は次のようになります。

pip install azure-cosmos
pip install aiohttp

from azure.cosmos.aio import CosmosClient
from azure.cosmos import exceptions
from azure.cosmos.partition_key import PartitionKey
import asyncio

# Replace these values with your Cosmos DB connection information
endpoint = "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 container
database_throughput = 1000

# Singleton CosmosClient instance
client = CosmosClient(endpoint, credential=key)

# Helper function to get or create database and container
async 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 items

async 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 items

async 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

Python v2 プログラミング モデルでは、ブループリント の概念が導入されています。 ブループリントは、コア関数アプリケーションの外部で関数を登録するためにインスタンス化された新しいクラスです。 ブループリント インスタンスに登録されている関数は、関数ランタイムによって直接インデックス付けされません。 これらのブループリント関数のインデックスを作成するには、関数アプリはブループリント インスタンスから関数を登録する必要があります。

ブループリントの使用には次のような利点があります。

  • 関数アプリをモジュール型コンポーネントに分割して、複数の Python ファイルで関数を定義し、ファイルごとに異なるコンポーネントに分割できます。
  • 独自の API をビルドして再利用するための、拡張可能なパブリック関数アプリ インターフェイスを提供します。

次の例は、ブループリントの使用方法を示しています。

まず、http_blueprint.py ファイルで HTTP によってトリガーされる関数が最初に定義され、ブループリント オブジェクトに追加されます。

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 
        ) 

次に、function_app.py ファイルでブループリント オブジェクトがインポートされ、その関数が関数アプリに登録されます。

import azure.functions as func 
from http_blueprint import bp

app = func.FunctionApp() 

app.register_functions(bp) 

注意

Durable Functions では、ブループリントもサポートされています。 Durable Functions アプリのブループリントを作成するには、こちらに示すように、azure-functions-durable Blueprint クラスを使用してオーケストレーション、アクティビティ、およびエンティティ トリガーとクライアント バインドを登録します。 その後、結果のブループリントを通常どおりに登録できます。 例については、サンプルをご覧ください。

インポートの動作

絶対と相対の各参照の両方を使用して、関数コードにモジュールをインポートすることができます。 次のインポートは、前述のフォルダー構造に基づいて、関数ファイル <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)

注意

shared_code/ フォルダーには、絶対インポート構文を使用するときに Python パッケージとしてマークするための __init__.py ファイルが含まれている必要があります。

次の __app__ インポートおよび最上位を超える相対インポートは、静的な型チェッカーでサポートされておらず、Python テスト フレームワークでサポートされていないため非推奨です。

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)

トリガーと入力

Azure Functions では、入力はトリガー入力とその他の入力の 2 つのカテゴリに分けられます。 function.json ファイルではこれらは同じではありませんが、Python コードでは同じように使用されます。 トリガーの接続文字列またはシークレットと入力ソースは、ローカル実行時には local.settings.json ファイル内の値にマップし、Azure での実行時にはアプリケーションの設定にマップします。

たとえば、次のコードでは 2 つの入力の違いが示されています。

// 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__.py
import azure.functions as func
import logging

def main(req: func.HttpRequest, obj: func.InputStream):
    logging.info(f'Python HTTP-triggered function processed: {obj.read()}')

この関数が呼び出されると、HTTP 要求は req として関数に渡されます。 エントリは、ルート URL 内の ID に基づいて Azure Blob Storage アカウントから取得され、関数の本体で obj として使用できるようになります。 ここで、指定されるストレージ アカウントは、CONNECTION_STRING アプリ設定で見つかる接続文字列です。

Azure Functions では、入力はトリガー入力とその他の入力の 2 つのカテゴリに分けられます。 これらは異なるデコレーターを使用して定義されていますが、Python コードでは使用方法は似ています。 トリガーの接続文字列またはシークレットと入力ソースは、ローカル実行時には local.settings.json ファイル内の値にマップし、Azure での実行時にはアプリケーションの設定にマップします。

例として、次のコードは、BLOB ストレージの入力バインドを定義する方法を示しています。

// local.settings.json
{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "python",
    "STORAGE_CONNECTION_STRING": "<AZURE_STORAGE_CONNECTION_STRING>",
    "AzureWebJobsStorage": "<azure-storage-connection-string>"
  }
}
# function_app.py
import azure.functions as func
import logging

app = func.FunctionApp()

@app.route(route="req")
@app.read_blob(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()}')

この関数が呼び出されると、HTTP 要求は req として関数に渡されます。 エントリは、ルート URL 内の ID に基づいて Azure Blob Storage アカウントから取得され、関数の本体で obj として使用できるようになります。 ここで、指定されるストレージ アカウントは、STORAGE_CONNECTION_STRING アプリ設定で見つかる接続文字列です。

データ集中型バインド操作の場合は、別のストレージ アカウントを使用できます。 詳しくは、「ストレージ アカウントに関するガイダンス」をご覧ください。

SDK 型バインド (プレビュー)

選択トリガーとバインドでは、基になる Azure SDK とフレームワークによって実装されたデータ型を操作できます。 これらの "SDK 型バインド" を使用すると、基になるサービス SDK を使用しているようにバインディング データとやりとりできます。

重要

SDK 型バインドのサポートには、Python v2 プログラミング モデルが必要です。

Functions では、Azure Blob Storage の Python SDK 型バインドがサポートされています。これにより、基になる BlobClient 型を使用して BLOB データを操作できます。

重要

Python に対する SDK 型バインドのサポートは現在プレビュー段階です。

  • Python v2 プログラミング モデルを使用する必要があります。
  • 現時点では、同期 SDK 型のみがサポートされています。

前提条件

Blob Storage 拡張機能の SDK 型バインドを有効にする

  1. azurefunctions-extensions-bindings-blob 拡張機能パッケージをプロジェクト内の requirements.txt ファイルに追加します。これには、少なくとも次のパッケージが含まれている必要があります。

    azure-functions
    azurefunctions-extensions-bindings-blob
    
  2. 次のコードをプロジェクト内の function_app.py ファイルに追加します。これにより、SDK 型バインドがインポートされます。

    import azurefunctions.extensions.bindings.blob as blob
    

SDK 型バインドの例

この例では、BLOB Storage トリガー (blob_trigger) と HTTP トリガーの入力バインド (blob_input) の両方から BlobClient を取得する方法を示します。

import logging

import azure.functions as func
import azurefunctions.extensions.bindings.blob as blob

app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)

@app.blob_trigger(
    arg_name="client", path="PATH/TO/BLOB", connection="AzureWebJobsStorage"
)
def blob_trigger(client: blob.BlobClient):
    logging.info(
        f"Python blob trigger function processed blob \n"
        f"Properties: {client.get_blob_properties()}\n"
        f"Blob content head: {client.download_blob().read(size=1)}"
    )


@app.route(route="file")
@app.blob_input(
    arg_name="client", path="PATH/TO/BLOB", connection="AzureWebJobsStorage"
)
def blob_input(req: func.HttpRequest, client: blob.BlobClient):
    logging.info(
        f"Python blob input function processed blob \n"
        f"Properties: {client.get_blob_properties()}\n"
        f"Blob content head: {client.download_blob().read(size=1)}"
    )
    return "ok"

Blob Storage の他の SDK 型バインドのサンプルは、Python 拡張機能リポジトリで確認できます。

HTTP ストリーム (プレビュー)

HTTP ストリームを使用すると、関数で有効になっている FastAPI 要求および応答 API を使用して、HTTP エンドポイントからのデータを受け入れて返すことができます。 これらの API を使用すると、ホストはメッセージ全体をメモリに読み込むのではなく、HTTP メッセージ内の大きなデータをチャンクとして処理できます。

この機能により、大規模なデータ ストリーム、OpenAI の統合、動的コンテンツの配信、HTTP 経由でのリアルタイムのやりとりを必要とする他のコア HTTP シナリオのサポートが可能になります。 HTTP ストリームで FastAPI 応答の種類を使用することもできます。 HTTP ストリームがない場合、HTTP 要求と応答のサイズは、メッセージ ペイロード全体をすべてメモリ内で処理するときに発生する可能性のあるメモリ制限で制限されます。

重要

HTTP ストリームのサポートには、Python v2 プログラミング モデルが必要です。

重要

Python の HTTP ストリームのサポートは現在プレビュー段階であり、Python v2 プログラミング モデルを使用する必要があります。

前提条件

HTTP ストリームを有効にする

HTTP ストリームは既定で無効になっています。 アプリケーション設定でこの機能を有効にし、FastAPI パッケージを使用するようにコードを更新する必要があります。 HTTP ストリームを有効にすると、関数アプリでは既定で HTTP ストリーミングが使用されるため、元の HTTP 機能は機能しないことに注意してください。

  1. azurefunctions-extensions-http-fastapi 拡張機能パッケージをプロジェクト内の requirements.txt ファイルに追加します。これには、少なくとも次のパッケージが含まれている必要があります。

    azure-functions
    azurefunctions-extensions-http-fastapi
    
  2. 次のコードをプロジェクト内の function_app.py ファイルに追加します。これにより、FastAPI 拡張機能がインポートされます。

    from azurefunctions.extensions.http.fastapi import Request, StreamingResponse
    
  3. Azure にデプロイするときに、関数アプリに次のアプリケーション設定を追加します。

    "PYTHON_ENABLE_INIT_INDEXING": "1"

    Linux 従量課金プランにデプロイする場合は、以下も追加します

    "PYTHON_ISOLATE_WORKER_DEPENDENCIES": "1"

    ローカルで実行する場合は、これらの同じ設定を local.settings.json プロジェクト ファイルに追加する必要もあります。

HTTP ストリームの例

HTTP ストリーミング機能を有効にすると、HTTP 経由でデータをストリーミングする関数を作成できます。

この例は、HTTP 応答データをストリーミングする HTTP でトリガーされる関数です。 これらの機能を使用して、リアルタイムの視覚化のためにパイプラインを介してイベント データを送信したり、大規模なデータ セットの異常を検出したり、インスタント通知を提供したりするなどのシナリオをサポートできます。

import time

import azure.functions as func
from azurefunctions.extensions.http.fastapi import Request, StreamingResponse

app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)


def generate_sensor_data():
    """Generate real-time sensor data."""
    for i in range(10):
        # Simulate temperature and humidity readings
        temperature = 20 + i
        humidity = 50 + i
        yield f"data: {{'temperature': {temperature}, 'humidity': {humidity}}}\n\n"
        time.sleep(1)


@app.route(route="stream", methods=[func.HttpMethod.GET])
async def stream_sensor_data(req: Request) -> StreamingResponse:
    """Endpoint to stream real-time sensor data."""
    return StreamingResponse(generate_sensor_data(), media_type="text/event-stream")

この例は、クライアントからのストリーミング データをリアルタイムで受信して処理する、HTTP によってトリガーされる関数です。 これは、継続的なデータ ストリームの処理や IoT デバイスからのイベント データの処理などのシナリオに役立つストリーミング アップロード機能を示します。

import azure.functions as func
from azurefunctions.extensions.http.fastapi import JSONResponse, Request

app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)


@app.route(route="streaming_upload", methods=[func.HttpMethod.POST])
async def streaming_upload(req: Request) -> JSONResponse:
    """Handle streaming upload requests."""
    # Process each chunk of data as it arrives
    async for chunk in req.stream():
        process_data_chunk(chunk)

    # Once all data is received, return a JSON response indicating successful processing
    return JSONResponse({"status": "Data uploaded and processed successfully"})


def process_data_chunk(chunk: bytes):
    """Process each data chunk."""
    # Add custom processing logic here
    pass

HTTP ストリームの呼び出し

関数の FastAPI エンドポイントにストリーミング呼び出しを行うには、HTTP クライアント ライブラリを使用する必要があります。 お使いのクライアント ツールまたはブラウザーが、ストリーミングをネイティブにサポートしていないか、データの最初のチャンクのみを返す場合があります。

次のようなクライアント スクリプトを使用して、ストリーミング データを HTTP エンドポイントに送信できます。

import httpx # Be sure to add 'httpx' to 'requirements.txt'
import asyncio

async def stream_generator(file_path):
    chunk_size = 2 * 1024  # Define your own chunk size
    with open(file_path, 'rb') as file:
        while chunk := file.read(chunk_size):
            yield chunk
            print(f"Sent chunk: {len(chunk)} bytes")

async def stream_to_server(url, file_path):
    timeout = httpx.Timeout(60.0, connect=60.0)
    async with httpx.AsyncClient(timeout=timeout) as client:
        response = await client.post(url, content=stream_generator(file_path))
        return response

async def stream_response(response):
    if response.status_code == 200:
        async for chunk in response.aiter_raw():
            print(f"Received chunk: {len(chunk)} bytes")
    else:
        print(f"Error: {response}")

async def main():
    print('helloworld')
    # Customize your streaming endpoint served from core tool in variable 'url' if different.
    url = 'http://localhost:7071/api/streaming_upload'
    file_path = r'<file path>'

    response = await stream_to_server(url, file_path)
    print(response)

if __name__ == "__main__":
    asyncio.run(main())

出力

出力は、戻り値および出力パラメーターの両方で表現できます。 出力が 1 つのみの場合は、戻り値の使用をお勧めします。 複数の出力の場合は、出力パラメーターを使用する必要があります。

出力バインディングの値として関数の戻り値を使用するには、バインディングの name プロパティを function.json ファイル内の $return に設定する必要があります。

複数の出力を生成するには、azure.functions.Out インターフェイスによって提供される set() メソッドを使用して、バインディングに値を割り当てます。 たとえば、次の関数を使用すると、キューにメッセージをプッシュすることに加え、HTTP 応答を返すこともできます。

{
  "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 func

def main(req: func.HttpRequest,
         msg: func.Out[func.QueueMessage]) -> str:

    message = req.params.get('body')
    msg.set(message)
    return message

出力は、戻り値および出力パラメーターの両方で表現できます。 出力が 1 つのみの場合は、戻り値の使用をお勧めします。 出力が複数の場合は、出力パラメーターを使用する必要があります。

複数の出力を生成するには、azure.functions.Out インターフェイスによって提供される set() メソッドを使用して、バインディングに値を割り当てます。 たとえば、次の関数を使用すると、キューにメッセージをプッシュすることに加え、HTTP 応答を返すこともできます。

# function_app.py
import azure.functions as func

app = 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

ログ記録

Azure Functions ランタイム ロガーへのアクセスは、ご利用の関数アプリ内のルート logging ハンドラーを介して利用できます。 このロガーは Application Insights に関連付けられているため、関数の実行中に発生する警告とエラーにフラグを設定することができます。

次の例では、HTTP トリガーを介して関数が呼び出されるときに、情報メッセージが記録されます。

import logging

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

他にも次のようなログ記録メソッドが用意されています。これにより、さまざまなトレース レベルでコンソールへの書き込みが可能になります。

方法 説明
critical(_message_) ルート ロガー上に CRITICAL レベルのメッセージを書き込みます。
error(_message_) ルート ロガー上に ERROR レベルのメッセージを書き込みます。
warning(_message_) ルート ロガー上に WARNING レベルのメッセージを書き込みます。
info(_message_) ルート ロガー上に INFO レベルのメッセージを書き込みます。
debug(_message_) ルート ロガー上に DEBUG レベルのメッセージを書き込みます。

ログ記録の詳細については、「Azure Functions を監視する」を参照してください。

作成されたスレッドからのログ

作成されたスレッドからのログを表示するには、関数のシグネチャに context 引数を含めます。 この引数には、ローカルの invocation_id を保存する属性 thread_local_storage が含まれています。 これは、コンテキストが確実に変更されるように、関数の現在の invocation_id に設定できます。

import azure.functions as func
import logging
import threading


def 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.')

カスタム テレメトリをログに記録する

既定では、Functions ランタイムには、関数によって生成されたログとその他のテレメトリ データが収集されます。 このテレメトリは、Application インサイト のトレースとして終了します。 特定の Azure サービスの要求と依存関係のテレメトリは、既定でトリガーおよびバインディングでも収集されます。

バインディングの外部でカスタム要求やカスタム依存関係テレメトリを収集するには、OpenCensus Python Extensions を使用できます。 この拡張機能は、カスタム テレメトリ データを Application Insights インスタンスに送信します。 サポートされている拡張機能の一覧は、OpenCensus リポジトリで確認できます。

Note

OpenCensus Python 拡張機能を使用するには、PYTHON_ENABLE_WORKER_EXTENSIONS1 に設定して、関数アプリの Python 拡張機能を有効にする必要があります。 また、アプリケーション設定がまだ存在しない場合は、そのAPPLICATIONINSIGHTS_CONNECTION_STRING への APPLICATIONINSIGHTS_CONNECTION_STRING 設定を追加して、Application Insights 接続文字列を使用するように切り替える必要があります。

// requirements.txt
...
opencensus-extension-azure-functions
opencensus-ext-requests
import json
import logging

import requests
from opencensus.extension.azure.functions import OpenCensusExtension
from opencensus.trace import config_integration

config_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 トリガー

HTTP トリガーは function.json ファイルで定義されています。 バインディングの name は、関数の名前付きパラメーターと一致している必要があります。 前の例では、バインド名 req が使用されています。 このパラメーターは HttpRequest オブジェクトであり、HttpResponse オブジェクトが返されます。

HttpRequest オブジェクトからは、要求ヘッダー、クエリ パラメーター、ルート パラメーター、およびメッセージ本文を取得できます。

次の例は、Python 用の HTTP トリガー テンプレートからのものです。

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
        )

この関数では、name クエリ パラメーターの値は HttpRequest オブジェクトの params パラメーターから取得されます。 JSON でエンコードされたメッセージ本文は get_json メソッドを使用して読み取ります。

同様に、返される status_code オブジェクトに応答メッセージの status_code および headers を設定できます。

HTTP トリガーは、HttpRequest オブジェクトである名前付きバインディング パラメーターを受け取り、HttpResponse オブジェクトを返すメソッドであると定義されます。 function_name デコレーターをメソッドに適用して関数名を定義しますが、HTTP エンドポイントは route デコレーターを適用することで設定します。

この例は、Python v2 プログラミング モデルの HTTP トリガー テンプレートのものであり、バインディング パラメーター名は req です。 これは、Azure Functions Core Tools または 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
        )

HttpRequest オブジェクトからは、要求ヘッダー、クエリ パラメーター、ルート パラメーター、およびメッセージ本文を取得できます。 この関数では、name クエリ パラメーターの値は HttpRequest オブジェクトの params パラメーターから取得されます。 JSON でエンコードされたメッセージ本文は get_json メソッドを使用して読み取ります。

同様に、返される status_code オブジェクトに応答メッセージの status_code および headers を設定できます。

この例で名前を渡すには、関数の実行時に指定された URL を貼り付けてから、それに "?name={name}" を付加します。

Web フレームワーク

Flask や FastAPI などの Web Server Gateway Interface (WSGI) 互換および Asynchronous Server Gateway Interface (ASGI) 互換フレームワークを、HTTP によってトリガーされる Python 関数と共に使用できます。 このセクションでは、これらのフレームワークをサポートするために関数を変更する方法を示します。

まず、次の例に示すように、function.json ファイルを更新して、HTTP トリガーに route を含める必要があります。

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

次の例に示すように、host.json ファイルを更新して、HTTP routePrefix を含める必要があります。

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

フレームワークで使用されるインターフェイスに応じて、Python コード ファイル init.py を更新します。 次の例では、ASGI ハンドラー アプローチまたは Flask の WSGI ラッパー アプローチのいずれかを示します。

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)

Flask や FastAPI などの Asynchronous Server Gateway Interface (ASGI) 互換フレームワークおよび Web Server Gateway Interface (WSGI) 互換フレームワーク (Flask や FastAPI など) を、HTTP によってトリガーされる Python 関数と共に使用できます。 次の例に示すように、最初に host.json ファイルを更新して、HTTP routePrefix を含める必要があります。

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

フレームワーク コードは次の例のようになります。

AsgiFunctionApp は、ASGI HTTP 関数を構築するための最上位の関数アプリ クラスです。

# function_app.py

import 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) 

スケーリングとパフォーマンス

Python 関数アプリのスケーリングとパフォーマンスのベスト プラクティスについては、Python のスケーリングとパフォーマンスに関する記事を参照してください。

Context

実行時に関数の呼び出しコンテキストを取得するには、そのシグニチャに context 引数を含めます。

例:

import azure.functions


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

Context クラスには次の文字列属性が含まれています。

属性 説明
function_directory 関数が実行されるディレクトリです。
function_name 関数の名前です。
invocation_id 現在の関数呼び出しの ID です。
thread_local_storage 関数のスレッド ローカル ストレージ。 作成されたスレッドからのログ用のローカルの invocation_id が含まれています。
trace_context 分散トレース用のコンテキスト。 詳細については、「Trace Context」を参照してください。
retry_context 関数への再試行のコンテキスト。 詳細については、「retry-policies」を参照してください。

グローバル変数

将来の実行に対してアプリの状態が保持されることは保証されません。 ただし、Azure Functions ランタイムでは、多くの場合、同じアプリの複数の実行に対して同じプロセスが再利用されます。 高コストの計算の結果をキャッシュするには、グローバル変数として宣言します。

CACHED_DATA = None


def main(req):
    global CACHED_DATA
    if CACHED_DATA is None:
        CACHED_DATA = load_json()

    # ... use CACHED_DATA in code

環境変数

Azure Functions では、サービス接続文字列などのアプリケーション設定は、実行時に環境変数として公開されます。 コードでこれらの設定にアクセスするには、主に 2 つの方法があります。

Method 説明
os.environ["myAppSetting"] アプリケーション設定をキー名で取得しようとして失敗した場合はエラーを発生させます。
os.getenv("myAppSetting") アプリケーション設定をキー名で取得しようとして成功した場合は null を返します。

どちらの方法も、import os を宣言する必要があります。

次の設定では、os.environ["myAppSetting"] を使用して myAppSetting という名前のキーのos.environ["myAppSetting"]が取得されます。

import logging
import os

import azure.functions as func

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}')

ローカル開発の場合、アプリケーション設定は local.settings.json ファイルに保持されます

Azure Functions では、サービス接続文字列などのアプリケーション設定は、実行時に環境変数として公開されます。 コードでこれらの設定にアクセスするには、主に 2 つの方法があります。

Method 説明
os.environ["myAppSetting"] アプリケーション設定をキー名で取得しようとして失敗した場合はエラーを発生させます。
os.getenv("myAppSetting") アプリケーション設定をキー名で取得しようとして成功した場合は null を返します。

どちらの方法も、import os を宣言する必要があります。

次の設定では、os.environ["myAppSetting"] を使用して myAppSetting という名前のキーのos.environ["myAppSetting"]が取得されます。

import logging
import os

import azure.functions as func

app = 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}')

ローカル開発の場合、アプリケーション設定は local.settings.json ファイルに保持されます

Python バージョン

Azure Functions では次の Python バージョンがサポートされています。

Functions バージョン Python* バージョン
4.x 3.11
3.10
3.9
3.8
3.7
3.x 3.9
3.8
3.7

* 公式の Python ディストリビューション

Azure で関数アプリを作成するときに特定の Python バージョンを要求するには、az functionapp create コマンドの --runtime-version オプションを使用します。 Functions ランタイム バージョンは --functions-version オプションによって設定されます。 Python バージョンは、関数アプリの作成時に設定され、従量課金プランで実行されているアプリでは変更できません。

ローカル環境で実行するときは、ランタイムは使用可能な Python のバージョンを使用します。

Python バージョンの変更

Python 関数アプリを特定の言語バージョンに設定するには、サイトの構成の LinuxFxVersion フィールドで言語と言語のバージョンを指定する必要があります。 たとえば、Python 3.8 を使用するように Python アプリを変更するには、linuxFxVersionpython|3.8 に設定します。

linuxFxVersion サイト設定を表示および変更する方法については、「Azure Functions のランタイム バージョンを対象とする方法」を参照してください。

一般的な情報については、Azure Functions のランタイム サポート ポリシーに関するページおよび「Azure Functions でサポートされている言語」を参照してください。

パッケージの管理

Core Tools または Visual Studio Code を使用してローカルで開発を行う場合は、必要なパッケージの名前とバージョンを requirements.txt ファイルに追加し、pip を使用してそれらをインストールしてください。

たとえば、次の requirements.txt ファイルと pip コマンドを使用すれば、PyPI から requests パッケージをインストールすることができます。

requests==2.19.1
pip install -r requirements.txt

App Service プランで関数を実行する場合、requirements.txt で定義した依存関係は、logging などの組み込みの Python モジュールよりも優先されます。 組み込みモジュールがコード内のディレクトリと同じ名前である場合、この優先順位によって競合が生じる可能性があります。 従量課金プランまたは Elastic Premium プランで実行している場合、既定では依存関係に優先順位が設定されていないため、競合が生じる可能性は低くなります。

App Service プランで実行される問題を防ぐには、ディレクトリに Python ネイティブ モジュールと同じ名前を付けたり、プロジェクトの requirements.txt ファイルに Python ネイティブ ライブラリを含めたりしないでください。

Azure への発行

発行する準備ができたら、一般公開されているすべての依存関係が、requirements.txt ファイルに列記されていることを確認します。 このファイルは、プロジェクト ディレクトリのルートにあります。

発行から除外されたプロジェクト ファイルとフォルダー (仮想環境フォルダーなど) は、プロジェクトのルート ディレクトリにあります。

Python プロジェクトを Azure に発行するために、リモート ビルド、ローカル ビルド、およびカスタム依存関係を使用したビルドの 3 つのビルド アクションがサポートされています。

Azure Pipelines を使用して依存関係をビルドし、継続的デリバリー (CD) を使用して発行することもできます。 詳細については、「Azure Pipelines を使用した継続的デリバリー」を参照してください。

リモート ビルド

リモート ビルドを使用する場合、サーバー上に復元された依存関係とネイティブの依存関係は運用環境と一致します。 これにより、アップロードするデプロイ パッケージが小さくなります。 Windows 上で Python アプリを開発する場合は、リモート ビルドを使用します。 プロジェクトにカスタム依存関係がある場合は、追加のインデックスの URL を使用するリモート ビルドを使用することができます。

依存関係は、requirements.txt ファイルの内容に基づいてリモートで取得されます。 リモート ビルド は推奨されるビルド方法です。 次の func azure functionapp publish コマンドを使用して Python プロジェクトを Azure に発行すると、既定では Core Tools によってリモート ビルドが要求されます。

func azure functionapp publish <APP_NAME>

<APP_NAME> を、Azure 内のご自分の関数アプリの名前に置き換えることを忘れないでください。

Visual Studio Code の Azure Functions 拡張機能も、既定ではリモート ビルドを要求します。

ローカル ビルド

依存関係は、requirements.txt ファイルの内容に基づいてローカルで取得されます。 次の func azure functionapp publish コマンドを使用してローカル ビルドとして発行することで、リモート ビルドを実行しないようにすることができます。

func azure functionapp publish <APP_NAME> --build local

<APP_NAME> を、Azure 内のご自分の関数アプリの名前に置き換えることを忘れないでください。

--build local オプションを使うと、プロジェクトの依存関係が requirements.txt ファイルから読み取られ、これらの依存パッケージがローカルにダウンロードされ、インストールされます。 プロジェクト ファイルと依存関係は、ローカル コンピューターから Azure にデプロイされます。 これにより、大きいサイズのデプロイ パッケージが Azure にアップロードされます。 何らかの理由で、コア ツールを使って requirements.txt ファイルを取得できない場合は、発行でカスタム依存関係オプションを使う必要があります。

Windows でローカルに開発する場合は、ローカル ビルドの使用をお勧めしません。

カスタムの依存関係

Python パッケージ インデックスにない依存関係がプロジェクトにある場合、2 つの方法でプロジェクトをビルドすることができます。 最初のビルド方法は、プロジェクトのビルド方法によって異なります。

追加のインデックスの URL を使用するリモート ビルド

アクセス可能なカスタム パッケージ インデックスからパッケージを取得できる場合は、リモート ビルドを使用します。 発行する前に、必ず、PIP_EXTRA_INDEX_URL という名前のアプリ設定を作成してください。 この設定の値は、カスタム パッケージ インデックスの URL です。 この設定は、リモート ビルドで --extra-index-url オプションを使用して pip install を実行することを指示するために使用します。 詳細については、Pythonpip install に関するドキュメントを参照してください。

また、基本認証の資格情報を追加のパッケージ インデックスの URL と共に使用することもできます。 詳細については、Python ドキュメントの「基本認証の資格情報」を参照してください。

ローカル パッケージをインストールする

当社のツール向けに公開されていないパッケージをプロジェクトに使用している場合は、それを __app__/.python_packages ディレクトリに配置することで、アプリで使用可能にすることができます。 発行する前に次のコマンドを実行して、依存関係をローカルでインストールします。

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

カスタムの依存関係を使用する場合は、既に依存関係がプロジェクト フォルダーにインストールされているため、--no-build 発行オプションを使用する必要があります。

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

<APP_NAME> を、Azure 内のご自分の関数アプリの名前に置き換えることを忘れないでください。

単体テスト

Python で記述された関数は、標準的なテスト フレームワークを使用して、他の Python コードのようにテストできます。 ほとんどのバインドでは、azure.functions パッケージから適切なクラスのインスタンスを作成することにより、モック入力オブジェクトを作成できます。 azure.functions パッケージはすぐには利用できないため、前の「パッケージの管理」セクションで説明されているように、requirements.txt ファイルを使用してインストールしてください。

my_second_function を例にとると、次に示すのは、HTTP によってトリガーされる関数のモック テストです。

最初に、<project_root>/my_second_function/function.json ファイルを作成し、この関数を HTTP トリガーとして定義します。

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

次に、my_second_functionshared_code.my_second_helper_function を実装できます。

# <project_root>/my_second_function/__init__.py
import azure.functions as func
import logging

# Use absolute import to resolve shared_code modules
from 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 HttpResponse
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.py

def double(value: int) -> int:
  return value * 2

HTTP トリガーのテスト ケースの記述を開始できます。

# <project_root>/tests/test_my_second_function.py
import unittest

import azure.functions as func
from my_second_function import main

class 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',)

.venv の Python 仮想環境フォルダー内で、任意の Python テスト フレームワーク (pip install pytest など) をインストールします。 続いて pytest tests を実行して、テスト結果を確認します。

まず、<project_root>/function_app.py ファイルを作成し、my_second_function 関数 HTTP トリガーおよび shared_code.my_second_helper_function として実装します。

# <project_root>/function_app.py
import azure.functions as func
import logging

# Use absolute import to resolve shared_code modules
from shared_code import my_second_helper_function

app = 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.py

def double(value: int) -> int:
  return value * 2

HTTP トリガーのテスト ケースの記述を開始できます。

# <project_root>/tests/test_my_second_function.py
import unittest
import azure.functions as func

from function_app import main

class 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',
    )

.venv の Python 仮想環境フォルダー内で、任意の Python テスト フレームワーク (pip install pytest など) をインストールします。 続いて pytest tests を実行して、テスト結果を確認します。

一時ファイル

tempfile.gettempdir() メソッドは一時フォルダーを返します。Linux では /tmp です。 関数が実行されているときに生成および使用する一時ファイルを格納するために、アプリケーションでこのディレクトリを使用できます。

重要

一時ディレクトリに書き込まれるファイルは、呼び出しをまたいで保持されることは保証されません。 スケールアウトの間、一時ファイルはインスタンス間で共有されません。

次の例では、名前付きの一時ファイルを一時ディレクトリ (/tmp) に作成します。

import logging
import azure.functions as func
import tempfile

from os import listdir

#---
   tempFilePath = tempfile.gettempdir()
   fp = tempfile.NamedTemporaryFile()
   fp.write(b'Hello world!')
   filesDirListInTemp = listdir(tempFilePath)

テストは、プロジェクト フォルダーとは別のフォルダーに保存することをお勧めします。 このアクションにより、アプリでテスト コードをデプロイすることを防ぐことができます。

プレインストール済みライブラリ

Python Functions ランタイムには、いくつかのライブラリが付属しています。

Python 標準ライブラリ

Python 標準ライブラリには、各 Python ディストリビューションに同梱されている組み込み Python モジュールの一覧が含まれています。 これらのライブラリのほとんどは、ファイル入出力 (I/O) などのシステム機能へのアクセスに役立ちます。 Windows システムでは、これらのライブラリは Python と共にインストールされます。 Unix ベースのシステムでは、これらはパッケージ コレクションによって提供されます。

Python バージョンのライブラリを表示するには、次の手順を実行します。

Azure Functions Python worker の依存関係

Azure Functions Python worker は、特定のライブラリ セットを必要とします。 これらのライブラリは、関数内で使用することもできますが、Python 標準の一部ではありません。 対象の関数がこれらのライブラリのいずれかに依存している場合、Azure Functions の外部で実行したときにコードでそれらのライブラリを使用できない場合があります。

Note

関数アプリの requirements.txtazure-functions-worker エントリが含まれている場合は、それを削除します。 Functions worker は Azure Functions プラットフォームによって自動的に管理され、新しい機能とバグの修正のための更新が定期的に行われます。 古いバージョンの worker を requirements.txt に手動で組み込むと、予期しない問題が発生する可能性があります。

Note

worker の依存関係と競合する可能性がある特定のライブラリ (protobuf、tensorflow、grpcio など) がパッケージに含まれている場合は、アプリの設定で PYTHON_ISOLATE_WORKER_DEPENDENCIES1 に設定して、アプリケーションで worker の依存関係を参照しないようにしてください。

Azure Functions Python ライブラリ

すべての Python worker の更新プログラムには、新しいバージョンの Azure Functions Python ライブラリ (azure.functions) が含まれています。 各更新プログラムには下位互換性があるため、これで簡単に Python 関数アプリを継続的に更新できるようになります。 このライブラリのリリースの一覧は、azure-functions PyPi で確認できます。

ランタイム ライブラリのバージョンは Azure によって修正され、requirements.txt で上書きすることはできません。 requirements.txtazure-functions エントリは、リンティングと顧客意識のためだけに用意されています。

対象のランタイムの Python Functions ライブラリの実際のバージョンを追跡するには、次のコードを使用します。

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

ランタイム システム ライブラリ

Python worker の Docker イメージにプレインストールされているシステム ライブラリの一覧については、以下を参照してください。

Functions ランタイム Debian のバージョン Python のバージョン
バージョン 3.x Buster Python 3.7
Python 3.8
Python 3.9

Python worker 拡張機能

Azure Functions で実行される Python worker プロセスを使用すると、サードパーティ製ライブラリを関数アプリに統合できます。 これらの拡張ライブラリは、関数の実行のライフサイクル中に特定の操作を挿入できるミドルウェアとして機能します。

これらの拡張機能は、標準の Python ライブラリ モジュールと同様に関数コードにインポートされます。 拡張機能は、次のスコープに基づいて実行されます。

Scope 説明
アプリケーション レベル 関数トリガーにインポートされると、拡張機能はアプリ内のすべての関数実行に適用されます。
関数レベル インポート先の特定の関数トリガーにのみ実行が制限されます。

各拡張機能に関する情報を参照して、拡張機能が実行されるスコープの詳細を確認してください。

拡張機能で、Python worker 拡張機能インターフェイスが実装されます。 このアクションにより、Python worker プロセスは関数実行ライフサイクルの間に拡張機能のコードを呼び出すことができます。 詳細については、「拡張機能の作成」を参照してください。

拡張機能の使用

お使いの Python 関数で Python worker 拡張機能ライブラリを使用するには、次の手順を実行します。

  1. 拡張機能パッケージをプロジェクトの requirements.txt ファイルに追加します。
  2. ライブラリをアプリにインストールします。
  3. 次のアプリケーション設定を追加します。
  4. 関数トリガーに拡張機能モジュールをインポートします。
  5. 必要に応じて、拡張機能インスタンスを構成します。 構成要件は、拡張機能のドキュメントに明記されているはずです。

重要

サード パーティ製の Python worker 拡張機能ライブラリについては、Microsoft はサポートも保証もしていません。 関数アプリで使用する拡張機能が信頼できることを確認する必要があります。悪意のある、または適切に作成されていない拡張機能を使用するリスクはすべてお客様が負うこととなります。

サードパーティは、関数アプリに拡張機能をインストールして使用する方法に関する具体的なドキュメントを提供する必要があります。 拡張機能の使用方法の基本的な例については、拡張機能の使用に関するページを参照してください。

以下に、関数アプリで拡張機能を使用する例をスコープ別に示します。

# <project_root>/requirements.txt
application-level-extension==1.0.0
# <project_root>/Trigger/__init__.py

from application_level_extension import AppExtension
AppExtension.configure(key=value)

def main(req, context):
  # Use context.app_ext_attributes here

拡張機能の作成

拡張機能は、Azure Functions に統合可能な機能を作成したサードパーティ製ライブラリの開発者によって作成されます。 拡張機能の開発者は、関数実行のコンテキストで実行されるように特別に設計されたカスタム ロジックを含む Python パッケージを設計、実装、リリースします。 これらの拡張機能は、PyPI レジストリまたは GitHub リポジトリに発行できます。

Python worker 拡張機能パッケージを作成、パッケージ化、発行、使用する方法については、「Azure Functions 用の Python worker 拡張機能の開発」を参照してください。

アプリケーション レベルの拡張機能

AppExtensionBase から継承された拡張機能は、アプリケーション スコープで実行されます。

AppExtensionBase は、実装のための次の抽象クラス メソッドを公開します。

方法 説明
init 拡張機能がインポートされた後に呼び出されます。
configure 拡張機能を構成する必要がある場合に、関数コードから呼び出されます。
post_function_load_app_level 関数が読み込まれた直後に呼び出されます。 関数名と関数ディレクトリが拡張機能に渡されます。 関数ディレクトリは読み取り専用であり、このディレクトリ内のローカル ファイルに書き込もうとしても失敗することに注意してください。
pre_invocation_app_level 関数がトリガーされる直前に呼び出されます。 関数コンテキストと関数呼び出しの引数が、拡張機能に渡されます。 通常、他の属性をコンテキスト オブジェクトで渡して、関数コードで使用することができます。
post_invocation_app_level 関数の実行が完了した直後に呼び出されます。 関数コンテキスト、関数呼び出しの引数、呼び出しの戻りオブジェクトが拡張機能に渡されます。 これは、ライフサイクル フックの実行が成功したかどうかを検証するのに適した実装です。

関数レベルの拡張機能

FuncExtensionBase から継承された拡張機能は、特定の関数トリガーで実行されます。

FuncExtensionBase は、実装のための次の抽象クラス メソッドを公開します。

方法 説明
__init__ 拡張機能のコンストラクター。 これは、拡張機能インスタンスが特定の関数で初期化されると呼び出されます。 この抽象メソッドを実装する際、適切な拡張機能登録のために、filename パラメーターを受け入れて、親のメソッド super().__init__(filename) に渡すことが必要になる場合があります。
post_function_load 関数が読み込まれた直後に呼び出されます。 関数名と関数ディレクトリが拡張機能に渡されます。 関数ディレクトリは読み取り専用であり、このディレクトリ内のローカル ファイルに書き込もうとしても失敗することに注意してください。
pre_invocation 関数がトリガーされる直前に呼び出されます。 関数コンテキストと関数呼び出しの引数が、拡張機能に渡されます。 通常、他の属性をコンテキスト オブジェクトで渡して、関数コードで使用することができます。
post_invocation 関数の実行が完了した直後に呼び出されます。 関数コンテキスト、関数呼び出しの引数、呼び出しの戻りオブジェクトが拡張機能に渡されます。 これは、ライフサイクル フックの実行が成功したかどうかを検証するのに適した実装です。

クロス オリジン リソース共有

Azure Functions では、クロス オリジン リソース共有 (CORS) がサポートされています。 CORS はポータル内でAzure CLI によって構成されます。 CORS の許可配信元一覧は、関数アプリ レベルで適用されます。 CORS を有効にすると、応答に Access-Control-Allow-Origin ヘッダーが含まれます。 詳細については、「 クロス オリジン リソース共有」を参照してください。

クロスオリジン リソース共有 (CORS) は、Python 関数アプリで完全にサポートされています。

Async

既定では、Python のホスト インスタンスは、一度に 1 つの関数呼び出しのみを処理できます。 これは、Python がシングル スレッド ランタイムのためです。 多数の I/O イベントを処理する、または I/O バインドされている関数アプリの場合、関数を非同期的に実行することでパフォーマンスを大幅に向上させることができます。 詳細については、「Azure Functions での Python アプリのパフォーマンス向上」を参照してください。

共有メモリ プロトコル (プレビュー)

スループットを向上させるために、Azure Functions では、プロセス外の Python 言語ワーカーが Functions ホスト プロセスとメモリを共有できます。 関数アプリがボトルネックになっている場合は、 \FUNCTIONS_WORKER_SHARED_MEMORY_DATA_TRANSFER_ENABLEDという名前のアプリケーション設定を1値に追加して、共有メモリを有効にすることができます。 共有メモリを有効にすると、DOCKER_SHM_SIZE 設定を使用して、共有メモリを 268435456 のような ものに設定できます。これは 256 MB に相当します。

たとえば、Blob ストレージ バインドを使用して 1 MB を超えるペイロードを転送する際、共有メモリを有効にするとボトルネックを減らすことができます。

この機能は、プレミアムおよび専用 (Azure App Service) プランで実行されている関数アプリに対してのみ使用できます。 詳細については、「共有メモリ」を参照してください。

既知の問題とよくあるご質問

以下に一般的な問題に対する 2 つのトラブルシューティング ガイドを示します。

以下に、v2 プログラミング モデルに関する既知の問題に対する 2 つのトラブルシューティング ガイドを示します。

既知の問題と機能に関する要望はすべて、GitHub issues リストで追跡されます。 問題が発生してその問題が GitHub で見つからない場合は、新しい Issue を開き、その問題の詳細な説明を記載してお知らせください。

次のステップ

詳細については、次のリソースを参照してください。

Python の使用に問題がありますか? 何が起こっているのか教えてください。