Поделиться через


Azure Functions Python Developer Guide (Справочник по Функциям Azure для разработчика Python)

Это руководство содержит общие сведения о разработке Функции Azure с помощью Python. В статье предполагается, что вы уже ознакомились с руководством разработчиков Функции Azure.

Внимание

Эта статья поддерживает модель программирования версии 1 и версии 2 для Python в Функции Azure. Модель Python версии 1 использует файл functions.json для определения функций, а новая модель версии 2 позволяет вместо этого использовать подход на основе декоратора. Этот новый подход приводит к более простой структуре файлов, и она более ориентирована на код. Выберите селектор версии 2 в верхней части статьи, чтобы узнать об этой новой модели программирования.

Разработчик Python также может быть заинтересован в следующих разделах:

Варианты разработки

Обе модели программирования функций Python поддерживают локальную разработку в одной из следующих сред:

Модель программирования Python версии 2:

Модель программирования Python версии 1:

Вы также можете создать функции Python версии 1 в портал Azure.

Совет

Хотя вы можете разрабатывать функции Azure на основе Python локально в Windows, Python поддерживается только в плане размещения на основе Linux при работе в Azure. Дополнительные сведения см. в списке поддерживаемых сочетаний операционной системы и среды выполнения.

Модель программирования

Функция Azure должна быть реализована как метод без отслеживания состояния в сценарии Python, который обрабатывает входные данные и создает выходные данные. По умолчанию среда выполнения ожидает, что метод будет реализован в виде глобального метода, вызываемого main() в файле __init__.py . Можно также указать альтернативную точку входа.

Вы привязываете данные к функции из триггеров и привязок с помощью атрибутов метода, использующих свойство, name определенное в файле function.json . Например, следующий файл function.json описывает простую функцию, активированную HTTP-запросом req:

{
    "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. Это помогает использовать функции IntelliSense и автозавершения, предоставляемые многими редакторами кода Python.

import azure.functions

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

Используйте заметки Python, включенные в пакет azure.functions.* для привязки входных и выходных данных к методам.

Функция Azure должна быть реализована как метод без отслеживания состояния в сценарии 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. Это помогает использовать функции IntelliSense и функции автозаполнения, предоставляемые многими редакторами кода Python.

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

Сведения об известных ограничениях модели версии 2 и их обходных решениях см. в статье "Устранение ошибок Python в Функции Azure".

Альтернативная точка входа

Можно изменить поведение функции по умолчанию, при необходимости указав свойства scriptFile и entryPoint в файле function.json. Например, следующая function.json сообщает среде выполнения использовать customentry() метод в файле main.py в качестве точки входа для функции Azure.

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

Основная папка проекта, <project_root>, может содержать следующие файлы:

  • local.settings.json. Используется для хранения параметров приложения и строка подключения при локальном запуске. Этот файл не публикуется в Azure. Дополнительные сведения см. в разделе local.settings.file.
  • requirements.txt: содержит список пакетов, которые должны быть установлены при публикации в Azure.
  • host.json: содержит параметры глобальной конфигурации, влияющие на все функции в экземпляре приложения-функции. Этот файл не публикуется в Azure. При локальном запуске поддерживаются не все параметры. Дополнительные сведения см. в разделе host.json.
  • VSCODE/: (Необязательно) Содержит хранимую конфигурацию Visual Studio Code. Дополнительные сведения см. в разделе параметров Visual Studio Code.
  • .venv/: (необязательно) Содержит виртуальную среду Python, используемую локальной разработкой.
  • Dockerfile: (необязательно) используется при публикации проекта в настраиваемом контейнере.
  • tests/: (необязательно) Содержит тест-кейсы для вашего приложения-функции.
  • .funcignore: (необязательно) объявляет файлы, которые не должны публиковаться в Azure. Обычно этот файл содержит vscode/ , чтобы игнорировать параметры редактора, .venv/ , чтобы игнорировать локальную виртуальную среду Python, тесты или игнорировать тестовые случаи и 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

Основная папка проекта, <project_root>, может содержать следующие файлы:

  • .venv/: (необязательно) Содержит виртуальную среду Python, которая используется локальной разработкой.
  • VSCODE/: (Необязательно) Содержит хранимую конфигурацию Visual Studio Code. Дополнительные сведения см. в разделе параметров Visual Studio Code.
  • function_app.py. Расположение по умолчанию для всех функций и связанных с ними триггеров и привязок.
  • additional_functions.py: (необязательно) Любые другие файлы Python, содержащие функции (обычно для логической группировки), на которые ссылаются function_app.py с помощью схем.
  • tests/: (необязательно) Содержит тест-кейсы для вашего приложения-функции.
  • .funcignore: (необязательно) объявляет файлы, которые не должны публиковаться в Azure. Как правило, этот файл содержит vscode/, чтобы игнорировать параметр редактора, venv/, чтобы игнорировать локальную виртуальную среду Python, тесты или игнорировать тестовые случаи и local.settings.json, чтобы предотвратить публикацию параметров локального приложения.
  • host.json: содержит параметры глобальной конфигурации, влияющие на все функции в экземпляре приложения-функции. Этот файл не публикуется в Azure. При локальном запуске поддерживаются не все параметры. Дополнительные сведения см. в разделе host.json.
  • local.settings.json. Используется для хранения параметров приложения и строка подключения при локальном запуске. Этот файл не публикуется в Azure. Дополнительные сведения см. в разделе local.settings.file.
  • requirements.txt. Содержит список пакетов Python, которые система устанавливает при публикации в Azure.
  • Dockerfile: (необязательно) используется при публикации проекта в настраиваемом контейнере.

При развертывании проекта в приложении-функции в Azure все содержимое основной папки <проекта, project_root>, должно быть включено в пакет, но не в саму папку, что означает, что host.json должен находиться в корневом каталоге пакета. Рекомендуется поддерживать тесты в папке вместе с другими функциями (в этом примере — тесты/). Дополнительные сведения см. в разделе Модульное тестирование.

Соединение с базой данных

Функции Azure хорошо интегрируется с Azure Cosmos DB для многих вариантов использования, включая IoT, электронную коммерцию, игры и т. д.

Например, для источника событий две службы интегрированы в архитектуры, управляемые событиями, с помощью функции канала изменений Azure Cosmos DB. Канал изменений предоставляет нижестоящим микрослужбам возможность надежного и добавочного чтения вставок и обновлений (например, событий заказа). Эту функцию можно использовать для предоставления постоянного хранилища событий в качестве брокера сообщений для событий изменения состояния и рабочего процесса обработки заказа диска между многими микрослужбами (которые можно реализовать как бессерверные Функции Azure).

Эталонная архитектура конвейера заказов на основе Azure Cosmos DB

Чтобы подключиться к Azure Cosmos DB, сначала создайте учетную запись, базу данных и контейнер. Затем можно подключить код функции к Azure Cosmos DB с помощью триггеров и привязок, как показано в этом примере.

Для реализации более сложной логики приложения можно также использовать библиотеку Python для Cosmos DB. Реализация асинхронного ввода-вывода выглядит следующим образом:

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 версии 2 представляет концепцию схем. Схема — это новый класс, созданный для регистрации функций вне основного приложения-функции. Функции, зарегистрированные в экземплярах схемы, не индексируются непосредственно средой выполнения функции. Чтобы получить индексированные эти функции схемы, приложение-функция должна зарегистрировать функции из экземпляров схемы.

Использование схем обеспечивает следующие преимущества:

  • Позволяет разбить приложение-функцию на модульные компоненты, что позволяет определять функции в нескольких файлах 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) 

Примечание.

Устойчивые функции также поддерживает схемы. Чтобы создать схемы для приложений Устойчивые функции, зарегистрируйте оркестрацию, действие и триггеры сущностей и привязки клиента с помощью 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/ папка должна содержать файл __init__.py, чтобы пометить его как пакет Python.

Следующие __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 делятся на две категории: входные данные триггеров и другие входные данные. Хотя они отличаются в файле function.json, их использование идентично в коде Python. Строки подключения или секреты для источников триггеров и входных данных сопоставляются со значениями в файле local.settings.json при локальном запуске и сопоставляются с параметрами приложения при их запуске в Azure.

Например, следующий код демонстрирует разницу между двумя входными данными:

// 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. Запись извлекается из учетной записи Хранилище BLOB-объектов Azure на основе идентификатора в URL-адресе маршрута и предоставляется как obj в тексте функции. Здесь указанная учетная запись хранения — это строка подключения, найденный в параметре CONNECTION_STRING приложения.

Входные данные в Функциях Azure делятся на две категории: входные данные триггеров и другие входные данные. Хотя они определены с помощью разных декораторов, их использование аналогично в коде 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. Запись извлекается из учетной записи Хранилище BLOB-объектов Azure на основе идентификатора в URL-адресе маршрута и предоставляется как obj в тексте функции. Здесь указанная учетная запись хранения — это строка подключения, найденный в параметре STORAGE_CONNECTION_STRING приложения.

Для операций с интенсивной привязкой данных может потребоваться использовать отдельную учетную запись хранения. Дополнительные сведения см . в руководстве по учетной записи хранения.

Привязки типов ПАКЕТА SDK (предварительная версия)

Для выбора триггеров и привязок можно работать с типами данных, реализованными базовыми пакетами SDK и платформами Azure. Эти привязки типов SDK позволяют взаимодействовать с данными привязки , как если бы вы использовали базовый пакет SDK службы.

Внимание

Для поддержки привязок типов SDK требуется модель программирования Python версии 2.

Функции поддерживают привязки типов пакета SDK Python для хранилища BLOB-объектов Azure, что позволяет работать с данными BLOB-объектов с помощью базового BlobClient типа.

Внимание

Поддержка привязок типов ПАКЕТА SDK для Python в настоящее время доступна в предварительной версии:

  • Необходимо использовать модель программирования Python версии 2.
  • В настоящее время поддерживаются только синхронные типы sdk.

Необходимые компоненты

Включение привязок типов ПАКЕТА SDK для расширения хранилища BLOB-объектов

  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

В этом примере показано, как получить BlobClient от триггера хранилища BLOB-объектов (blob_trigger) и из входной привязки для триггера HTTP (blob_input):

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"

Вы можете просмотреть другие примеры привязок типов пакета SDK для хранилища BLOB-объектов в репозитории расширений Python:

HTTP-потоки (предварительная версия)

Потоки HTTP позволяют принимать и возвращать данные из конечных точек HTTP с помощью API запросов FastAPI и ответов, включенных в ваших функциях. Эти API позволяют узлу обрабатывать большие данные в HTTP-сообщениях как блоки вместо чтения всего сообщения в память.

Эта функция позволяет обрабатывать большой поток данных, интеграции OpenAI, предоставлять динамическое содержимое и поддерживать другие основные сценарии HTTP, требующие взаимодействия в режиме реального времени по протоколу HTTP. Можно также использовать типы ответов FastAPI с HTTP-потоками. Без потоков HTTP размер HTTP-запросов и ответов ограничен ограничениями памяти, которые могут возникнуть при обработке всех полезных данных сообщения во всей памяти.

Внимание

Для поддержки потоков HTTP требуется модель программирования Python версии 2.

Внимание

Поддержка потоков HTTP для Python в настоящее время доступна в предварительной версии и требует использования модели программирования Python версии 2.

Необходимые компоненты

Включение потоков 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, которая получает и обрабатывает потоковую передачу данных от клиента в режиме реального времени. Он демонстрирует возможности потоковой передачи, которые могут быть полезны для сценариев, таких как обработка непрерывных потоков данных и обработка данных событий с устройств Интернета вещей.

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

Выходные данные

Выходные данные можно выразить как возвращаемое значение или параметры вывода. Если используется только один вывод, мы рекомендуем использовать возвращаемое значение. Для нескольких выходных данных необходимо использовать выходные параметры.

Чтобы использовать возвращаемое значение функции в качестве значения выходной привязки, name свойство привязки должно быть задано $return в файле function.json .

Чтобы создать несколько выходных значений, используйте метод set() из интерфейса azure.functions.Out, чтобы присвоить значение привязке. Например, следующая функция может направлять сообщение в очередь и возвращает ответ 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

Выходные данные можно выразить как возвращаемое значение или параметры вывода. Если используется только один вывод, мы рекомендуем использовать возвращаемое значение. Для нескольких выводов нужно использовать параметры вывода.

Чтобы создать несколько выходных значений, используйте метод set() из интерфейса azure.functions.Out, чтобы присвоить значение привязке. Например, следующая функция может направлять сообщение в очередь и возвращает ответ 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 предоставляется через корневой обработчик logging в приложении-функции. Это средство ведения журнала привязано к Application Insights и позволяет отмечать предупреждения и ошибки, которые возникают во время выполнения функции.

Следующий пример сохраняет в журнал информационное сообщение, когда функция вызывается с помощью триггера HTTP.

import logging

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

Доступны дополнительные методы ведения журнала, которые позволяют выводить сообщения в консоль на разных уровнях трассировки.

Метод Description
critical(_message_) Записывает сообщение с уровнем CRITICAL в корневое средство ведения журнала.
error(_message_) Записывает сообщение с уровнем ERROR в корневое средство ведения журнала.
warning(_message_) Записывает сообщение с уровнем WARNING в корневое средство ведения журнала.
info(_message_) Записывает сообщение с уровнем INFO в корневое средство ведения журнала.
debug(_message_) Записывает сообщение с уровнем DEBUG в корневое средство ведения журнала.

Дополнительные сведения о ведении журналов см. в статье Мониторинг Функций Azure.

Ведение журнала из созданных потоков

Чтобы просмотреть журналы, поступающие из созданных потоков, добавьте context аргумент в подпись функции. Этот аргумент содержит атрибут thread_local_storage , который хранит локальный invocation_id. Это можно задать для текущей 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.')

Ведение журнала пользовательской телеметрии

По умолчанию среда выполнения Функций собирает журналы и другие данные телеметрии, созданные вашими функциями. Эти данные телеметрии завершаются как трассировки в Application Insights. Данные телеметрии запросов и зависимостей для определенных служб Azure также собираются по умолчанию с помощью триггеров и привязок.

Чтобы получить данные телеметрии пользовательских запросов и зависимостей (не через привязки), можно использовать расширения Python OpenCensus. Это расширение отправляет пользовательские данные телеметрии в ваш экземпляр Application Insights. Список поддерживаемых расширений можно найти в репозитории OpenCensus.

Примечание.

Чтобы использовать расширения Python OpenCensus, необходимо включить расширения рабочих ролей Python в приложении-функции, сменив в настройках PYTHON_ENABLE_WORKER_EXTENSIONS на 1. Кроме того, необходимо переключиться на использование строки подключения Application Insights, добавив APPLICATIONINSIGHTS_CONNECTION_STRING параметр в параметры приложения, если он еще не задан.

// 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 можно получить заголовки запроса, параметры запроса, параметры маршрута и текст сообщения.

Следующий пример относится к шаблону триггера HTTP для 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
        )

В этой функции вы получаете значение name параметра запроса из params параметра объекта HttpRequest . Текст сообщения в кодировке JSON с помощью get_json метода.

Аналогичным образом можно задать status_code и headers для ответного сообщения в возвращенном объекте HttpResponse.

Триггер HTTP определяется как метод, который принимает именованный параметр привязки, который является объектом HttpRequest и возвращает объект HttpResponse . Примените function_name декоратор к методу для определения имени функции, а конечная точка HTTP устанавливается путем применения route декоратора.

В этом примере используется шаблон триггера HTTP для модели программирования Python версии 2, где имя параметра привязки — req. Это пример кода, который предоставляется при создании функции с помощью Функции Azure 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 параметра запроса из params параметра объекта HttpRequest . Текст сообщения в кодировке JSON с помощью get_json метода.

Аналогичным образом можно задать status_code и headers для ответного сообщения в возвращенном объекте HttpResponse.

Чтобы передать имя в этом примере, вставьте URL-адрес, предоставленный при запуске функции, а затем добавьте его."?name={name}"

Веб-платформы

Интерфейс шлюза веб-сервера (WSGI)совместимый и асинхронный интерфейс шлюза сервера (ASGI), совместимые с платформами, такими как Flask и FastAPI, с функциями Python с триггером HTTP. В этом разделе показано, как изменить функции для поддержки этих платформ.

Сначала необходимо обновить файл function.json, чтобы включить route его в триггер HTTP, как показано в следующем примере:

{
  "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 также должен быть обновлен, чтобы включить HTTProutePrefix, как показано в следующем примере:

{
  "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 или подход с использованием WSGI-оболочки для 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)

Вы можете использовать платформы, совместимые с асинхронным интерфейсом шлюза сервера (ASGI) и интерфейсом шлюза веб-сервера (WSGI), совместимыми с Flask и FastAPI, с функциями Python, активировав HTTP. Сначала необходимо обновить файл 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 — это класс приложения-функции верхнего уровня для создания функций HTTP ASGI.

# 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 аргумент в подпись.

Например:

import azure.functions


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

Класс Context имеет следующие строковые атрибуты:

Атрибут Description
function_directory Каталог, в котором выполняется функция.
function_name Имя функции.
invocation_id Идентификатор вызова текущей функции.
thread_local_storage Локальное хранилище потока функции. Содержит локальный invocation_id объект для ведения журнала из созданных потоков.
trace_context Контекст распределенной трассировки. Дополнительные сведения см. в разделе Trace Context.
retry_context Контекст повторных попыток в функцию. Дополнительные сведения см. в разделе retry-policies.

Глобальные переменные

Не гарантируется, что состояние приложения будет сохранено для будущих выполнений. Однако среда выполнения Функций Azure часто использует один и тот же процесс для нескольких выполнений одного и того же приложения. Чтобы кэшировать результаты дорогостоящих вычислений, объявите его как глобальную переменную.

CACHED_DATA = None


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

    # ... use CACHED_DATA in code

Переменные среды

В Функции Azure параметры приложения, такие как строка подключения службы, предоставляются в виде переменных среды при выполнении. Эти параметры в вашем коде доступны двумя основными способами.

Метод Description
os.environ["myAppSetting"] Пытается получить параметр приложения по имени ключа и вызывает ошибку при неудачном выполнении.
os.getenv("myAppSetting") Пытается получить параметр приложения по имени ключа и возвращается None , когда это не удалось.

Оба этих способа должны объявляться import os.

В следующем примере используется os.environ["myAppSetting"] для получения параметра приложения по ключу с именем 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 параметры приложения, такие как строка подключения службы, предоставляются в виде переменных среды при выполнении. Эти параметры в вашем коде доступны двумя основными способами.

Метод Description
os.environ["myAppSetting"] Пытается получить параметр приложения по имени ключа и вызывает ошибку при неудачном выполнении.
os.getenv("myAppSetting") Пытается получить параметр приложения по имени ключа и возвращается None , когда это не удалось.

Оба этих способа должны объявляться import os.

В следующем примере используется os.environ["myAppSetting"] для получения параметра приложения по ключу с именем 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 version

Функции Azure поддерживают следующие версии Python:

Версия службы "Функции" Версии Python*
4.x 3.11
3,10
3,9
3,8
3,7
3.x 3,9
3,8
3,7

* Официальные дистрибутивы Python

Чтобы запросить конкретную версию Python при создании приложения-функции в Azure, используйте параметр --runtime-version команды az functionapp create. Версия среды выполнения функций задается параметром --functions-version. Версия Python устанавливается при создании приложения-функции и не может быть изменена для приложений, работающих в плане потребления.

Среда выполнения использует доступную версию Python при локальном запуске.

Изменение версии Python

Чтобы установить приложение-функцию Python для определенной версии языка, необходимо указать язык и версию языка в LinuxFxVersion поле в конфигурации сайта. Например, чтобы изменить приложение Python на использование Python 3.8, установите значение linuxFxVersion python|3.8.

Сведения о том, как просматривать и изменять параметры сайта, см. в статье "Как настроить целевые linuxFxVersion версии среды выполнения Функции Azure".

Дополнительные сведения см. в политике поддержки среды выполнения Функции Azure и поддерживаемых языках в Функции Azure.

Управление пакетами

При локальной разработке с помощью основных средств или Visual Studio Code добавьте имена и версии необходимых пакетов в файл requirements.txt , а затем установите их с помощью pip.

Например, можно использовать следующий файл requirements.txt и pip команду для установки requests пакета из PyPI.

requests==2.19.1
pip install -r requirements.txt

При выполнении функций в плане Служба приложений зависимости, определенные в requirements.txt, имеют приоритет над встроенными модулями Python, такими какlogging. Это приоритет может привести к конфликтам, если встроенные модули имеют те же имена, что и каталоги в коде. При выполнении плана потребления или плана Elastic Premium конфликты могут быть менее вероятными, так как зависимости по умолчанию не определяются приоритетами.

Чтобы предотвратить проблемы, выполняемые в плане Служба приложений, не назовите каталоги так же, как и любые собственные модули Python и не включают собственные библиотеки Python в файл requirements.txt проекта.

Публикация в Azure

Когда все будет готово к публикации, убедитесь, что все общедоступные зависимости перечислены в файле requirements.txt. Этот файл можно найти в корне каталога проекта.

Файлы и папки проекта, исключенные из публикации, включая папку виртуальной среды, можно найти в корневом каталоге проекта.

Для публикации проекта Python в Azure поддерживаются три действия сборки: удаленная сборка, локальная сборка и сборки с использованием пользовательских зависимостей.

Вы также можете использовать Azure Pipelines для создания зависимостей и публикации с помощью непрерывной поставки (CD). Дополнительные сведения см. в статье о непрерывной доставке с помощью Azure Pipelines.

Удаленная сборка

При использовании удаленной сборки зависимости, которые восстанавливаются на сервере и собственных зависимостях, соответствуют рабочей среде. Это приводит к уменьшению размера пакета развертывания. Используйте удаленную сборку при разработке приложений Python в Windows. Если в проекте есть пользовательские зависимости, можно использовать удаленную сборку с дополнительным URL-адресом индекса.

Зависимости получаются удаленно на основе содержимого файла requirements.txt. В качестве рекомендуемого метода сборки рекомендуется использовать удаленную сборку. По умолчанию Core Tools запрашивает удаленную сборку при использовании следующей func azure functionapp publish команды для публикации проекта Python в Azure.

func azure functionapp publish <APP_NAME>

Не забудьте заменить <APP_NAME> именем приложения-функции, размещенного в Azure.

Расширение Функций Azure для Visual Studio Code также запрашивает удаленную сборку по умолчанию.

Локальная сборка

Зависимости получаются локально на основе содержимого файла 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, можно создать проект двумя способами. Первый способ, метод сборки, зависит от того, как вы создаете проект.

Удаленная сборка с дополнительным URL-адресом индекса

Если пакеты доступны из доступного индекса настраиваемого пакета, используйте удаленную сборку. Перед публикацией обязательно создайте параметр приложения с именем PIP_EXTRA_INDEX_URL. Значение этого параметра — это URL-адрес пользовательского индекса пакета. При использовании этого параметра удаленная сборка будет выполняться pip install с помощью --extra-index-url параметра. Дополнительные сведения см. в документации по 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_function и shared_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',
    )

В папке виртуальной среды Python venv установите любимую платформу тестов 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.

Стандартная библиотека Python

Стандартная библиотека Python содержит список встроенных модулей Python, которые поставляются с каждым дистрибутивом Python. Большинство этих библиотек помогают получить доступ к системным функциям, таким как входные и выходные данные файлов (ввода-вывода). В системах Windows эти библиотеки устанавливаются с Python. В системах под управлением Unix они предоставляются коллекциями пакетов.

Чтобы просмотреть библиотеку для версии Python, перейдите к следующим причинам:

Зависимости рабочих ролей Python в функциях Azure

Для рабочей роли Python Функции Azure требуется определенный набор библиотек. Эти библиотеки также можно использовать в функциях, но они не являются частью стандарта Python. Если функции полагаются на любую из этих библиотек, они могут быть недоступны для кода при запуске вне Функции Azure.

Примечание.

Если файл requirements.txt приложения-функции содержит запись azure-functions-worker, удалите ее. Рабочая роль функций автоматически управляется платформой Функции Azure, и мы регулярно обновляем ее с помощью новых функций и исправлений ошибок. Установка старой версии рабочей роли в файле requirements.txt может привести к непредвиденным проблемам.

Примечание.

Если пакет содержит определенные библиотеки, которые могут столкнуться с зависимостями рабочей роли (например, protobuf, tensorflow или grpcio), настройте их PYTHON_ISOLATE_WORKER_DEPENDENCIES 1 в параметрах приложения, чтобы предотвратить обращение приложения к зависимостям рабочей роли.

Библиотека Python Функции Azure

Каждое обновление рабочей роли Python включает новую версию библиотеки Python Функции Azure (azure.functions). Такой подход упрощает непрерывное обновление приложений-функций Python, так как каждое обновление имеет обратную совместимость. Список выпусков этой библиотеки см. в azure-functions PyPi.

Версия библиотеки среды выполнения исправлена Azure, и ее нельзя переопределить requirements.txt. Запись azure-functions в файле requirements.txt относится только к анализу кода и предоставлена к сведению клиентов.

Используйте следующий код для отслеживания фактической версии библиотеки функций Python в среде выполнения:

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

Системные библиотеки среды выполнения

Список предварительно установленных системных библиотек в образах Docker рабочей роли Python см. в следующих статьях:

Functions runtime (Среда выполнения функций) Версия Debian Версии Python
Версия 3.x Buster Python 3.7.
Python 3.8
Python 3.9

Расширения для рабочей роли Python

Процесс рабочей роли Python, который выполняется в Функциях Azure, позволяет интегрировать в приложение-функцию библиотеки сторонних поставщиков. Эти библиотеки расширений выполняют роль ПО промежуточного слоя для добавления определенных операций в жизненный цикл выполнения функции.

Расширения импортируются в коде функции примерно так же, как и стандартные модули библиотек Python. Расширения выполняются на основе следующих областей:

Scope Description
Уровень приложения Если расширение импортируется в любом триггере функции, оно применяется ко всем выполнениям этой функции в приложении.
уровень функции. Выполнение ограничивается только тем триггером функции, в котором импортируется расширение.

Просмотрите сведения о каждом расширении, чтобы узнать больше о области, в которой выполняется расширение.

Расширения реализуют интерфейс расширения рабочей роли Python. Это действие позволяет рабочему процессу Python вызывать код расширения во время жизненного цикла выполнения функции. Дополнительные сведения см. в статье "Создание расширений".

Применение расширений

Вы можете использовать библиотеку расширения рабочей роли Python в функциях Python, выполнив следующие действия:

  1. Добавьте пакет расширений в файл requirements.txt для проекта.
  2. Установите библиотеку в приложение.
  3. Добавьте следующие параметры приложения:
  4. Импортируйте модуль расширения в триггер функции.
  5. Настройте экземпляр расширения, если нужно. Заранее выясните требования к конфигурации, изучив документацию по расширению.

Внимание

Сторонние библиотеки рабочих расширений Python не поддерживаются и не гарантируются корпорацией Майкрософт. Необходимо убедиться, что все расширения, используемые в приложении-функции, являются надежными, и вы несете полный риск использования вредоносного или плохо написанного расширения.

Сторонние организации должны предоставить конкретную документацию по установке и использованию расширений в приложении-функции. Простой пример см. в разделе Использование расширения.

По этим ссылкам вы можете ознакомиться с применением расширений с разной областью действия в приложении-функции:

# <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. Разработчик расширения самостоятельно проектирует, реализует и публикует пакеты Python, которые содержат специализированную логику для работы в контексте выполнения функций. Эти расширения могут публиковаться через реестр PyPI или репозитории GitHub.

Дополнительные сведения о создании, упаковке, публикации и использовании пакетов расширений для рабочей роли Python см. в статье Разработка рабочих расширений Python для Функций Azure.

Расширения уровня приложения

Расширение, унаследованное от AppExtensionBase запусков в области приложения .

AppExtensionBase предоставляет следующие абстрактные методы класса, которые вам нужно реализовать.

Метод Description
init Вызывается после завершения импорта расширения.
configure Вызывается из кода функции, когда нужно настроить расширение.
post_function_load_app_level Вызывается сразу после загрузки функции. В расширение передаются параметры с именем функции и каталогом, где она размещается. Помните, что каталог функций доступен только для чтения, и любая попытка записи в локальный файл в этом каталоге завершается ошибкой.
pre_invocation_app_level Вызывается прямо перед активацией функции. В расширение передаются контекст функции и аргументы, указанные в вызове функции. Обычно вы также можете передавать другие атрибуты в объекте контекста, чтобы использовать их в коде функции.
post_invocation_app_level Вызывается сразу после завершения выполнения функции. В расширение передаются контекст функции, аргументы вызова функции и возвращаемый объект вызова. Эта реализация очень удобна для проверки, успешно ли применены перехватчики жизненного цикла.

Расширения уровня функции

Расширение, наследуемое от FuncExtensionBase, выполняется только в определенном триггере функции.

FuncExtensionBase предоставляет следующие абстрактные методы класса, которые вам нужно реализовать.

Метод Description
__init__ Конструктор расширения. Он вызывается при инициализации экземпляра приложения для конкретной функции. При реализации этого абстрактного метода может потребоваться принять filename параметр и передать его методу родительского объекта super().__init__(filename) для правильной регистрации расширений.
post_function_load Вызывается сразу после загрузки функции. В расширение передаются параметры с именем функции и каталогом, где она размещается. Помните, что каталог функций доступен только для чтения, и любая попытка записи в локальный файл в этом каталоге завершается ошибкой.
pre_invocation Вызывается прямо перед активацией функции. В расширение передаются контекст функции и аргументы, указанные в вызове функции. Обычно вы также можете передавать другие атрибуты в объекте контекста, чтобы использовать их в коде функции.
post_invocation Вызывается сразу после завершения выполнения функции. В расширение передаются контекст функции, аргументы вызова функции и возвращаемый объект вызова. Эта реализация очень удобна для проверки, успешно ли применены перехватчики жизненного цикла.

Предоставление общего доступа к ресурсам независимо от источника

Функции Azure поддерживают общий доступ к ресурсам независимо от источника (CORS). CORS настраивается на портале и через Azure CLI. Список разрешенных источников CORS применяется на уровне приложения-функции. При включении CORS ответы включают заголовок Access-Control-Allow-Origin. Дополнительные сведения см. в статье об общем доступе к ресурсам независимо от источника.

Общий доступ к ресурсам между источниками (CORS) полностью поддерживается для приложений-функций Python.

Асинхронная

По умолчанию экземпляр узла для Python может одновременно обрабатывать только один вызов функции. Это связано с тем, что Python является однопоточной средой выполнения. Для приложения-функции, обрабатывающего большое количество событий ввода-вывода и (или) связанных с вводом-выводом, можно повысить производительность, выполняя функции асинхронно. Подробную информацию см. в статье Повышение производительности приложений Python в Функциях Azure.

Общая память (предварительная версия)

Чтобы повысить пропускную способность, Функции Azure позволяет внепроцессной рабочей роли Python делиться памятью с узлом Функций. Когда приложение-функция достигает узких мест, вы можете включить общую память, добавив параметр приложения с именем FUNCTIONS_WORKER_SHARED_MEMORY_DATA_TRANSFER_ENABLED со значением 1. После включения общей памяти можно использовать параметр DOCKER_SHM_SIZE, чтобы задать общий объем памяти подобно 268435456, что эквивалентно 256 МБ.

Например, можно включить общую память для уменьшения узких мест при использовании привязок хранилища BLOB-объектов для передачи полезных данных размером более 1 МБ.

Эта функция доступна только для приложений-функций, работающих в планах "Премиум" и "Выделенный" (приложение Azure служба). Дополнительные сведения см. в разделе Общая память.

Известные проблемы и часто задаваемые вопросы

Ниже приведены два руководства по устранению распространенных проблем:

Ниже приведены два руководства по устранению известных проблем с моделью программирования версии 2.

Все известные проблемы и запросы функций отслеживаются в списке проблем GitHub. Если возникла проблема и не удается найти проблему в GitHub, откройте новую проблему и включите подробное описание проблемы.

Следующие шаги

Дополнительные сведения см. на следующих ресурсах:

Проблемы с использованием Python? Расскажите нам, что происходит.