Skip to content
1 change: 1 addition & 0 deletions workers/azure_functions_worker/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ def get_function_return_type(annotations: dict, has_explicit_return: bool,
return_anno = annotations.get('return')
if typing_inspect.is_generic_type(
return_anno) and typing_inspect.get_origin(
return_anno) is not None and typing_inspect.get_origin(
return_anno).__name__ == 'Out':
raise FunctionLoadError(
func_name,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,87 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import logging
import time
from datetime import datetime

import azure.functions as func

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


@app.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
)


@app.route(route="http_func")
def http_func(req: func.HttpRequest) -> func.HttpResponse:
time.sleep(1)

current_time = datetime.now().strftime("%H:%M:%S")
return func.HttpResponse(f"{current_time}")
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import json
import logging
import time

from datetime import datetime
from typing import Generic, Mapping, Optional, TypeVar, Union

import azure.functions as func

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

JsonType = Union[list, tuple, dict, str, int, float, bool]
T = TypeVar("T", bound=JsonType)


class JsonResponse(Generic[T], func.HttpResponse):
def __init__(
self,
body: T,
status_code: int = 200,
headers: Optional[Mapping[str, str]] = None,
):
super().__init__(json.dumps(body),
status_code=status_code,
headers=headers,
charset="utf-8")


@app.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
)


@app.route(route="http_func")
def http_func(req: func.HttpRequest) -> func.HttpResponse:
time.sleep(1)

current_time = datetime.now().strftime("%H:%M:%S")
return func.HttpResponse(f"{current_time}")


@app.route(route="custom_response")
def custom_response(req: func.HttpRequest) -> JsonResponse:
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 JsonResponse(
{
"name": name
},
)
else:
return JsonResponse(
{
"status": "healthy"
},
)
Original file line number Diff line number Diff line change
@@ -1,38 +1,85 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import logging

import azure.functions as func

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


@app.function_name(name="default_template")
@app.generic_trigger(arg_name="req",
type="httpTrigger",
route="default_template")
@app.generic_output_binding(arg_name="$return", type="http")
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
)
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import json
import logging

from typing import Generic, Mapping, Optional, TypeVar, Union

import azure.functions as func

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


JsonType = Union[list, tuple, dict, str, int, float, bool]
T = TypeVar("T", bound=JsonType)


class JsonResponse(Generic[T], func.HttpResponse):
def __init__(
self,
body: T,
status_code: int = 200,
headers: Optional[Mapping[str, str]] = None,
):
super().__init__(json.dumps(body),
status_code=status_code,
headers=headers,
charset="utf-8")


@app.function_name(name="default_template")
@app.generic_trigger(arg_name="req",
type="httpTrigger",
route="default_template")
@app.generic_output_binding(arg_name="$return", type="http")
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
)


@app.generic_trigger(arg_name="req",
type="httpTrigger",
route="custom_response")
@app.generic_output_binding(arg_name="$return", type="http")
def custom_response(req: func.HttpRequest) -> JsonResponse:
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 JsonResponse(
{
"name": name
},
)
else:
return JsonResponse(
{
"status": "healthy"
},
)
27 changes: 26 additions & 1 deletion workers/tests/endtoend/test_http_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,33 @@ def get_script_dir(cls):
return testutils.E2E_TESTS_FOLDER / 'http_functions' / \
'http_functions_stein'

@testutils.retryable_test(3, 5)
def test_return_custom_class(self):
"""Test if returning a custom class returns OK
"""
r = self.webhost.request('GET', 'custom_response',
timeout=REQUEST_TIMEOUT_SEC)
self.assertEqual(
r.content,
b'{"status": "healthy"}'
)
self.assertTrue(r.ok)

@testutils.retryable_test(3, 5)
def test_return_custom_class_with_query_param(self):
"""Test if query is accepted
"""
r = self.webhost.request('GET', 'custom_response',
params={'name': 'query'},
timeout=REQUEST_TIMEOUT_SEC)
self.assertTrue(r.ok)
self.assertEqual(
r.content,
b'{"name": "query"}'
)


class TestHttpFunctionsSteinGeneric(TestHttpFunctions):
class TestHttpFunctionsSteinGeneric(TestHttpFunctionsStein):

@classmethod
def get_script_dir(cls):
Expand Down
3 changes: 3 additions & 0 deletions workers/tests/unittests/test_typing_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,14 @@ class GetUtilityTestCase(TestCase):

def test_origin(self):
T = TypeVar('T')
class MyClass(Generic[T]): pass

self.assertEqual(get_origin(int), None)
self.assertEqual(get_origin(ClassVar[int]), None)
self.assertEqual(get_origin(Generic), Generic)
self.assertEqual(get_origin(Generic[T]), Generic)
self.assertEqual(get_origin(List[Tuple[T, T]][int]), list)
self.assertEqual(get_origin(MyClass), None)

def test_parameters(self):
T = TypeVar('T')
Expand Down
Loading