Skip to content
2 changes: 2 additions & 0 deletions azure/functions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from . import timer # NoQA
from . import durable_functions # NoQA
from . import sql # NoQA
from . import warmup # NoQA


__all__ = (
Expand Down Expand Up @@ -64,6 +65,7 @@
'SqlRow',
'SqlRowList',
'TimerRequest',
'WarmUpContext',

# Middlewares
'WsgiMiddleware',
Expand Down
1 change: 1 addition & 0 deletions azure/functions/decorators/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
SERVICE_BUS = "serviceBus"
SERVICE_BUS_TRIGGER = "serviceBusTrigger"
TIMER_TRIGGER = "timerTrigger"
WARMUP_TRIGGER = "warmupTrigger"
BLOB_TRIGGER = "blobTrigger"
BLOB = "blob"
EVENT_GRID_TRIGGER = "eventGridTrigger"
Expand Down
38 changes: 38 additions & 0 deletions azure/functions/decorators/function_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
parse_iterable_param_to_enums, StringifyEnumJsonEncoder
from azure.functions.http import HttpRequest
from .generic import GenericInputBinding, GenericTrigger, GenericOutputBinding
from .warmup import WarmUpTrigger
from .._http_asgi import AsgiMiddleware
from .._http_wsgi import WsgiMiddleware, Context

Expand Down Expand Up @@ -450,6 +451,43 @@ def decorator():

schedule = timer_trigger

def warm_up_trigger(self,
arg_name: str,
data_type: Optional[Union[DataType, str]] = None,
**kwargs) -> Callable:
"""The warm up decorator adds :class:`WarmUpTrigger` to the
:class:`FunctionBuilder` object
for building :class:`Function` object used in worker function
indexing model. This is equivalent to defining WarmUpTrigger
in the function.json which enables your function be triggered on the
specified schedule.
All optional fields will be given default value by function host when
they are parsed by function host.

Ref: https://aka.ms/azure-function-binding-warmup

:param arg_name: The name of the variable that represents the
:class:`TimerRequest` object in function code.
:param data_type: Defines how Functions runtime should treat the
parameter value.
:return: Decorator function.
"""

@self._configure_function_builder
def wrap(fb):
def decorator():
fb.add_trigger(
trigger=WarmUpTrigger(
name=arg_name,
data_type=parse_singular_param_to_enum(data_type,
DataType),
**kwargs))
return fb

return decorator()

return wrap

def service_bus_queue_trigger(
self,
arg_name: str,
Expand Down
18 changes: 18 additions & 0 deletions azure/functions/decorators/warmup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
from typing import Optional

from azure.functions.decorators.constants import WARMUP_TRIGGER
from azure.functions.decorators.core import Trigger, DataType


class WarmUpTrigger(Trigger):
@staticmethod
def get_binding_name() -> str:
return WARMUP_TRIGGER

def __init__(self,
name: str,
data_type: Optional[DataType] = None,
**kwargs) -> None:
super().__init__(name=name, data_type=data_type)
22 changes: 22 additions & 0 deletions azure/functions/warmup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import typing

from . import meta


class WarmUpContext:
pass


class WarmUpTriggerConverter(meta.InConverter, binding='warmupTrigger',
trigger=True):

@classmethod
def check_input_type_annotation(cls, pytype: type) -> bool:
return issubclass(pytype, WarmUpContext)

@classmethod
def decode(cls, data: meta.Datum, *, trigger_metadata) -> typing.Any:
return WarmUpContext()
44 changes: 43 additions & 1 deletion tests/decorators/test_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from azure.functions.decorators.constants import TIMER_TRIGGER, HTTP_TRIGGER, \
HTTP_OUTPUT, QUEUE, QUEUE_TRIGGER, SERVICE_BUS, SERVICE_BUS_TRIGGER, \
EVENT_HUB, EVENT_HUB_TRIGGER, COSMOS_DB, COSMOS_DB_TRIGGER, BLOB, \
BLOB_TRIGGER, EVENT_GRID_TRIGGER, EVENT_GRID, TABLE
BLOB_TRIGGER, EVENT_GRID_TRIGGER, EVENT_GRID, TABLE, WARMUP_TRIGGER
from azure.functions.decorators.core import DataType, AuthLevel, \
BindingDirection, AccessRights, Cardinality
from azure.functions.decorators.function_app import FunctionApp
Expand Down Expand Up @@ -220,6 +220,48 @@ def dummy():
]
})

def test_warmup_trigger_default_args(self):
app = self.func_app

@app.warm_up_trigger(arg_name="req")
def dummy_func():
pass

func = self._get_user_function(app)
self.assertEqual(func.get_function_name(), "dummy_func")
assert_json(self, func, {
"scriptFile": "function_app.py",
"bindings": [
{
"name": "req",
"type": WARMUP_TRIGGER,
"direction": BindingDirection.IN,
}
]
})

def test_warmup_trigger_full_args(self):
app = self.func_app

@app.warm_up_trigger(arg_name="req", data_type=DataType.STRING,
dummy_field='dummy')
def dummy():
pass

func = self._get_user_function(app)
assert_json(self, func, {
"scriptFile": "function_app.py",
"bindings": [
{
"name": "req",
"type": WARMUP_TRIGGER,
"dataType": DataType.STRING,
"direction": BindingDirection.IN,
'dummyField': 'dummy'
}
]
})

def test_queue_default_args(self):
app = self.func_app

Expand Down
23 changes: 23 additions & 0 deletions tests/decorators/test_warmup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import unittest

from azure.functions.decorators.constants import WARMUP_TRIGGER
from azure.functions.decorators.core import BindingDirection, DataType
from azure.functions.decorators.warmup import WarmUpTrigger


class TestWarmUp(unittest.TestCase):
def test_warmup_trigger_valid_creation(self):
trigger = WarmUpTrigger(name="req",
data_type=DataType.UNDEFINED,
dummy_field="dummy")

self.assertEqual(trigger.get_binding_name(), "warmupTrigger")
self.assertEqual(trigger.get_dict_repr(), {
"type": WARMUP_TRIGGER,
"direction": BindingDirection.IN,
'dummyField': 'dummy',
"name": "req",
"dataType": DataType.UNDEFINED
})
27 changes: 27 additions & 0 deletions tests/test_warmup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import unittest
import azure.functions.warmup as warmup

from azure.functions.meta import Datum


class TestWarmup(unittest.TestCase):
def test_warmup_decode(self):
# given
datum: Datum = Datum(value='''''', type='json')

# when
warmup_context: warmup.WarmUpContext = \
warmup.WarmUpTriggerConverter.decode(datum, trigger_metadata={})

# then
self.assertTrue(isinstance(warmup_context, warmup.WarmUpContext))

def test_warmup_input_type(self):
check_input_type = (
warmup.WarmUpTriggerConverter.check_input_type_annotation
)
self.assertTrue(check_input_type(warmup.WarmUpContext))
self.assertFalse(check_input_type(str))