Skip to content

Commit e4b8319

Browse files
authored
fix: improve function error messages (#1743)
* update worker.config * explicit fail for invalid streaming case + lint * test fixes * fix regex * skip test for 3.13 * actually skip test for 3.13 * rename
1 parent 89defbe commit e4b8319

File tree

11 files changed

+104
-37
lines changed

11 files changed

+104
-37
lines changed

runtimes/v1/tests/unittests/test_handle_event.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
import azure_functions_runtime_v1.handle_event as handle_event
66
import tests.protos as test_protos
77

8-
from azure_functions_runtime_v1.handle_event import (worker_init_request,
9-
functions_metadata_request,
10-
function_load_request,
11-
function_environment_reload_request)
8+
from azure_functions_runtime_v1.handle_event import (
9+
worker_init_request,
10+
functions_metadata_request,
11+
function_load_request,
12+
function_environment_reload_request)
1213
from tests.utils import testutils
1314
from tests.utils.constants import UNIT_TESTS_FOLDER
1415
from tests.utils.mock_classes import FunctionRequest, Metadata, Request, WorkerRequest

runtimes/v1/tests/unittests/test_opentelemetry.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from azure_functions_runtime_v1.handle_event import otel_manager, worker_init_request
88
from azure_functions_runtime_v1.otel import (initialize_azure_monitor,
9-
update_opentelemetry_status)
9+
update_opentelemetry_status)
1010
from azure_functions_runtime_v1.logging import logger
1111
from tests.utils.constants import UNIT_TESTS_FOLDER
1212
from tests.utils.mock_classes import FunctionRequest, Request, WorkerRequest

runtimes/v1/tests/unittests/test_utilities.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
from unittest.mock import patch
88

99
from azure_functions_runtime_v1.utils import (app_setting_manager,
10-
helpers,
11-
wrappers)
10+
helpers,
11+
wrappers)
1212

1313
TEST_APP_SETTING_NAME = "TEST_APP_SETTING_NAME"
1414
TEST_FEATURE_FLAG = "APP_SETTING_FEATURE_FLAG"

runtimes/v2/azure_functions_runtime/functions.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,15 @@ def validate_function_params(params: dict, bound_params: dict,
142142
raise FunctionLoadError(
143143
func_name,
144144
'Function parameter mismatch — the following trigger/input bindings '
145-
'are declared in the function decorators but missing from the '
146-
'Python function signature: ' + repr(set(params) - set(bound_params)))
145+
'are declared in Python but missing from the '
146+
'function decorator: ' + repr(set(params) - set(bound_params)))
147147

148148
if set(bound_params) - set(params):
149149
raise FunctionLoadError(
150150
func_name,
151-
'Extra parameters in function signature — the following parameters '
152-
'are present in the Python function definition but are not declared '
153-
'as bindings: ' + repr(set(params) - set(bound_params)))
151+
'Extra parameters in binding definition — the following parameters '
152+
'are declared as bindings but are not '
153+
'present in Python: ' + repr(set(params) - set(bound_params)))
154154

155155
input_types: typing.Dict[str, ParamTypeInfo] = {}
156156
output_types: typing.Dict[str, ParamTypeInfo] = {}

runtimes/v2/tests/unittests/test_handle_event.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
import tests.protos as test_protos
77

88
from azure_functions_runtime.handle_event import (worker_init_request,
9-
functions_metadata_request,
10-
function_load_request,
11-
function_environment_reload_request)
9+
functions_metadata_request,
10+
function_load_request,
11+
function_environment_reload_request)
1212
from tests.utils import testutils
1313
from tests.utils.constants import UNIT_TESTS_FOLDER
1414
from tests.utils.mock_classes import FunctionRequest, Request, WorkerRequest

runtimes/v2/tests/unittests/test_opentelemetry.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from azure_functions_runtime.handle_event import otel_manager, worker_init_request
88
from azure_functions_runtime.otel import (initialize_azure_monitor,
9-
update_opentelemetry_status)
9+
update_opentelemetry_status)
1010
from azure_functions_runtime.logging import logger
1111
from tests.utils.constants import UNIT_TESTS_FOLDER
1212
from tests.utils.mock_classes import FunctionRequest, Request, WorkerRequest

runtimes/v2/tests/unittests/test_utilities.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
from unittest.mock import patch
88

99
from azure_functions_runtime.utils import (app_setting_manager,
10-
helpers,
11-
validators,
12-
wrappers)
10+
helpers,
11+
validators,
12+
wrappers)
1313

1414
TEST_APP_SETTING_NAME = "TEST_APP_SETTING_NAME"
1515
TEST_FEATURE_FLAG = "APP_SETTING_FEATURE_FLAG"

workers/azure_functions_worker/functions.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,15 @@ def validate_function_params(params: dict, bound_params: dict,
136136
if set(params) - set(bound_params):
137137
raise FunctionLoadError(
138138
func_name,
139-
'the following parameters are declared in Python but '
140-
f'not in function.json: {set(params) - set(bound_params)!r}')
139+
'the following parameters are declared in Python '
140+
'but not in the function definition (function.json or '
141+
f'function decorators): {set(params) - set(bound_params)!r}')
141142

142143
if set(bound_params) - set(params):
143144
raise FunctionLoadError(
144145
func_name,
145-
f'the following parameters are declared in function.json but '
146+
'the following parameters are declared in the function '
147+
'definition (function.json or function decorators) but '
146148
f'not in Python: {set(bound_params) - set(params)!r}')
147149

148150
input_types: typing.Dict[str, ParamTypeInfo] = {}
@@ -221,7 +223,8 @@ def validate_function_params(params: dict, bound_params: dict,
221223
raise FunctionLoadError(
222224
func_name,
223225
f'binding {param.name} is declared to have the "in" '
224-
'direction in function.json, but its annotation '
226+
'direction in the function definition (function.json '
227+
'or function decorators), but its annotation '
225228
'is azure.functions.Out in Python')
226229

227230
if param_has_anno and param_py_type in (str, bytes) and (
@@ -244,13 +247,16 @@ def validate_function_params(params: dict, bound_params: dict,
244247
func_name,
245248
f'{param.name!r} binding type "{binding.type}" '
246249
f'and dataType "{binding.data_type}" in '
247-
f'function.json do not match the corresponding '
250+
'function definition (function.json or function '
251+
'decorators) do not match the corresponding '
248252
f'function parameter\'s Python type '
249253
f'annotation "{param_py_type.__name__}"')
250254
else:
251255
raise FunctionLoadError(
252256
func_name,
253-
f'type of {param.name} binding in function.json '
257+
f'type of {param.name} binding in function '
258+
'definition (function.json or function '
259+
'decorators) '
254260
f'"{binding.type}" does not match its Python '
255261
f'annotation "{param_py_type.__name__}"')
256262

workers/azure_functions_worker/http_v2.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
X_MS_INVOCATION_ID,
1515
)
1616
from azure_functions_worker.logging import logger
17-
from azure_functions_worker.utils.common import is_envvar_false
17+
from azure_functions_worker.utils.common import is_envvar_true
1818

1919

2020
# Http V2 Exceptions
@@ -28,6 +28,11 @@ class MissingHeaderError(ValueError):
2828
HTTP request."""
2929

3030

31+
class AppSettingDisabledError(Exception):
32+
"""Exception raised when the extension class is included
33+
but PYTHON_ENABLE_INIT_INDEXING is not set or is set to false."""
34+
35+
3136
class BaseContextReference(abc.ABC):
3237
"""
3338
Base class for context references.
@@ -279,14 +284,22 @@ def ext_base(cls):
279284

280285
@classmethod
281286
def _check_http_v2_enabled(cls):
282-
if sys.version_info.minor < BASE_EXT_SUPPORTED_PY_MINOR_VERSION or \
283-
is_envvar_false(PYTHON_ENABLE_INIT_INDEXING):
287+
init_indexing_enabled = is_envvar_true(PYTHON_ENABLE_INIT_INDEXING)
288+
if sys.version_info.minor < BASE_EXT_SUPPORTED_PY_MINOR_VERSION:
284289
return False
285290

286291
import azurefunctions.extensions.base as ext_base
287292
cls._ext_base = ext_base
288293

289-
return cls._ext_base.HttpV2FeatureChecker.http_v2_enabled()
294+
http_v2_enabled = cls._ext_base.HttpV2FeatureChecker.http_v2_enabled()
295+
if http_v2_enabled and not init_indexing_enabled:
296+
raise AppSettingDisabledError("HTTP Streaming is enabled but "
297+
"PYTHON_ENABLE_INIT_INDEXING "
298+
"is not set or is set to false. "
299+
"See aka.ms/functions-python-streaming "
300+
"for more information")
301+
302+
return http_v2_enabled
290303

291304

292305
http_coordinator = HttpCoordinator()

workers/tests/extension_tests/http_v2_tests/test_http_v2.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,46 @@ def send_request():
197197
self.assertTrue(ok)
198198
complete_data = b"".join(data_chunks)
199199
self.assertEqual(content, complete_data)
200+
201+
202+
@unittest.skipIf(is_envvar_true(DEDICATED_DOCKER_TEST)
203+
or is_envvar_true(CONSUMPTION_DOCKER_TEST),
204+
"Tests are flaky when running on Docker")
205+
@unittest.skipIf(sys.version_info.minor < 8, "HTTPv2"
206+
"is only supported for 3.8+.")
207+
@unittest.skipIf(sys.version_info.minor >= 13,
208+
"App Setting is not needed for 3.13+")
209+
class TestHttpFunctionsWithInitIndexingDisabled(testutils.WebHostTestCase):
210+
@classmethod
211+
def setUpClass(cls):
212+
cls.env_variables[PYTHON_ENABLE_INIT_INDEXING] = '0'
213+
os.environ[PYTHON_ENABLE_INIT_INDEXING] = "0"
214+
super().setUpClass()
215+
216+
@classmethod
217+
def tearDownClass(cls):
218+
os.environ.pop(PYTHON_ENABLE_INIT_INDEXING)
219+
super().tearDownClass()
220+
221+
@classmethod
222+
def get_environment_variables(cls):
223+
return cls.env_variables
224+
225+
@classmethod
226+
def get_script_dir(cls):
227+
return testutils.EXTENSION_TESTS_FOLDER / 'http_v2_tests' / \
228+
'http_functions_v2' / \
229+
'fastapi'
230+
231+
@classmethod
232+
def get_libraries_to_install(cls):
233+
return ['azurefunctions-extensions-http-fastapi', 'orjson', 'ujson']
234+
235+
@testutils.retryable_test(3, 5)
236+
def test_return_streaming_disabled(self):
237+
"""Test if the return_streaming function returns an error"""
238+
root_url = self.webhost._addr
239+
streaming_url = f'{root_url}/api/return_streaming'
240+
r = requests.get(
241+
streaming_url, timeout=REQUEST_TIMEOUT_SEC, stream=True)
242+
self.assertFalse(r.ok)

0 commit comments

Comments
 (0)