Azure Functions Python Library

repository·dev·Indexed 41 days ago

https://github.com/azure/azure-functions-python-library

A library for building serverless applications using Python on the Azure Functions 4.0 runtime. It provides programming models, triggers, and bindings for services such as Cosmos DB, Service Bus, HTTP, Blob, and Event Grid. Supports Python versions 3.10 through 3.13 and includes specialized serialization utilities like df_dumps and df_loads for Durable Functions.

Tokens
2.3K
Snippets
4
Records
8
Agent score
2%

What's inside Azure Functions Python Library

  1. Overview of Azure Functions Python Support

    dev

    The Azure Functions Python library provides serverless hosting capabilities for Python applications on Linux. It supports the Azure Functions 4.0 runtime and provides a wide range of triggers and bindings to integrate with various Azure services.

    Supported Python Versions

    The following Python versions are supported on the Azure Functions 4.0 runtime:

    • Python 3.10
    • Python 3.11
    • Python 3.12
    • Python 3.13

    Supported Triggers and Bindings

    You can use the library to build functions that respond to or interact with:

    • Blob
    • Cosmos DB
    • Event Grid
    • Event Hub
    • HTTP
    • Kafka
    • MySQL
    • Queue
    • ServiceBus
    • SQL
    • Timer
    • Warmup
    • Custom bindings
  2. Development and Deployment Options for Azure Functions Python

    dev

    Developers can build, test, debug, and publish Azure Functions using the following tools and methods:

    • Azure Functions Core Tools (CLI): For command-line local development and publishing.
    • Visual Studio Code: Using the Azure Functions extension for an integrated development experience.
    • Custom Docker Images: You can create and run Python Functions on Linux using your own custom Docker images.
  3. Migrate from Durable SDK serialization to Functions SDK

    dev

    If you are maintaining or upgrading a project that uses both the azure-functions and azure-durable-functions libraries, follow these migration steps to ensure you are using the centralized serialization implementation:

    1. Update azure-functions: Ensure you are using the version of the library that includes df_dumps and df_loads in azure.functions._durable_functions.
    2. Update Imports: Change all imports in your code from the old utility path to the new centralized path:
      • Old path: azure.durable_functions.models.utils.df_serialization
      • New path: azure.functions._durable_functions
    3. Update Dependencies: Ensure your install_requires or environment constraints include the appropriate version of azure-functions to support the new serialization logic.
  4. Implement the to_json/from_json contract for Strict Mode

    dev

    To support Strict Mode (AZURE_FUNCTIONS_DURABLE_STRICT_TYPING=1), your custom classes must implement a symmetric to_json and from_json contract. In strict mode, to_json() must return only natively JSON-serializable types (dicts, lists, strings, numbers, bools, None), and from_json() must be able to reconstruct the object from that plain data.

    Implementation Example

    class Order:
        @staticmethod
        def to_json(obj):
            # Explicitly call to_json on nested custom objects
            return {
                "item": obj.item,
                "hat": Hat.to_json(obj.hat), 
            }
    
        @staticmethod
        def from_json(data):
            # Reconstruct nested objects from plain dicts
            return Order(
                item=data["item"],
                hat=Hat.from_json(data["hat"]),
            )

    Handling Legacy Payloads

    If your application needs to support both legacy (loose-encoded) and strict-mode payloads during a transition, your from_json method should check the type of nested data:

        @staticmethod
        def from_json(data):
            hat_data = data["hat"]
            # If object_hook already fired (loose mode), hat_data is an instance
            if isinstance(hat_data, Hat):
                hat = hat_data
            # If strict mode, hat_data is a plain dict
            else:
                hat = Hat.from_json(hat_data)
            return Order(item=data["item"], hat=hat)
    class Order:
        @staticmethod
        def to_json(obj):
            return {
                "item": obj.item,
                "hat": Hat.to_json(obj.hat),   # explicit — not obj.hat
            }
    
        @staticmethod
        def from_json(data):
            return Order(
                item=data["item"],
                hat=Hat.from_json(data["hat"]),  # symmetric
            )
  5. Configure Durable Functions Strict Typing

    dev

    You can enable strict typing for Durable Functions serialization via an environment variable. This improves security by preventing import_module calls during deserialization and enforces type validation.

    Environment VariableSupported ValuesEffect
    AZURE_FUNCTIONS_DURABLE_STRICT_TYPING1, true, yes (case-insensitive)Enables strict mode. Unset or other values default to loose mode.
  6. Serialize custom objects with df_dumps

    dev

    Use df_dumps(value) to serialize a value to a JSON string following the Durable Functions convention. This is the centralized replacement for manual json.dumps calls using _serialize_custom_object.

    Modes of Operation

    • Loose Mode (Default): Equivalent to json.dumps(value, default=_serialize_custom_object). Custom objects are wrapped in an envelope containing __class__, __module__, and __data__ keys. Nested custom objects are recursively wrapped.
    • Strict Mode: Triggered by setting the environment variable AZURE_FUNCTIONS_DURABLE_STRICT_TYPING to 1, true, or yes. In this mode, the top-level custom object is wrapped in the legacy envelope, but its to_json() output is serialized as plain JSON (without the default= hook).

    Warning: In Strict Mode, any nested value that is not natively JSON-serializable will raise a TypeError. You must ensure that to_json() explicitly serializes nested custom objects (e.g., by calling NestedClass.to_json(self.nested_obj) instead of returning the object itself).

    from azure.functions import df_dumps
    
    # Loose mode (default)
    json_string = df_dumps(my_custom_object)
  7. Deserialize JSON with df_loads

    dev

    Use df_loads(s, expected_type=None) to deserialize a JSON string. This function provides centralized, secure deserialization for Durable Functions payloads.

    Usage Patterns

    1. Untyped Deserialization (Loose Mode)

    If expected_type is None, it behaves like json.loads(s, object_hook=_deserialize_custom_object). This is backward-compatible and used when type information is unavailable.

    2. Typed Deserialization (Loose Mode - Default)

    When expected_type is provided, the function parses the JSON and compares the payload's class/module against the expected_type.

    • If there is a mismatch, it logs a warning but falls back to the legacy object_hook path to maintain compatibility.

    3. Typed Deserialization (Strict Mode)

    When AZURE_FUNCTIONS_DURABLE_STRICT_TYPING is enabled (1, true, or yes):

    • If the payload is a legacy custom-object dict and the type mismatches, it raises a TypeError.
    • If the type matches, it calls expected_type.from_json(raw["__data__"]) directly. Crucially, import_module is never called, which eliminates the security risk of arbitrary module loading.
    • If the payload is a primitive/plain-JSON value, it performs an isinstance check and returns the value directly.
    from azure.functions import df_loads, MyCustomClass
    
    # Untyped (Loose)
    obj = df_loads(json_string)
    
    # Typed (Strict or Loose)
    obj = df_loads(json_string, expected_type=MyCustomClass)
  8. Use `df_dumps` and `df_loads` for Durable Functions serialization

    dev

    The library provides df_dumps and df_loads for handling serialization and deserialization of custom objects within Durable Functions. These functions are intended to replace direct use of internal underscore-prefixed functions like _serialize_custom_object and _deserialize_custom_object.

    Serialization Modes

    When using df_loads, the behavior depends on whether an expected_type is provided and the configured mode (Loose vs. Strict):

    • Loose Mode (Default):
      • If expected_type is provided and matches the payload, the correct object is returned without warnings.
      • If expected_type is provided but mismatches the payload, a warning is logged, but the legacy path still runs to attempt deserialization.
    • Strict Mode:
      • If expected_type matches, from_json is called directly, avoiding import_module calls.
      • If expected_type mismatches or the type lacks a from_json method, a TypeError is raised.

    Best Practices

    • Avoid internal functions: Do not use _serialize_custom_object or _deserialize_custom_object directly; use the public df_dumps and df_loads APIs instead.
    # Example conceptual usage
    import azure.functions as func
    
    # Serializing a custom object
    serialized_data = func.df_dumps(my_custom_object)
    
    # Deserializing with an expected type (Strict/Loose behavior applies)
    obj = func.df_loads(serialized_data, expected_type=MyCustomClass)