Skip to content

Commit 6448eed

Browse files
committed
add flag as part of FunctionInfo + tests
1 parent af10930 commit 6448eed

File tree

7 files changed

+90
-38
lines changed

7 files changed

+90
-38
lines changed

azure_functions_worker/bindings/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from .meta import has_implicit_output
99
from .meta import is_trigger_binding, load_binding_registry
1010
from .meta import from_incoming_proto, to_outgoing_proto, \
11-
to_outgoing_param_binding, set_deferred_bindings_flag
11+
to_outgoing_param_binding, check_deferred_bindings_enabled
1212
from .out import Out
1313

1414

@@ -19,5 +19,5 @@
1919
'check_input_type_annotation', 'check_output_type_annotation',
2020
'has_implicit_output',
2121
'from_incoming_proto', 'to_outgoing_proto', 'TraceContext', 'RetryContext',
22-
'to_outgoing_param_binding', 'set_deferred_bindings_flag'
22+
'to_outgoing_param_binding', 'check_deferred_bindings_enabled'
2323
)

azure_functions_worker/bindings/meta.py

+8-10
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
BINDING_REGISTRY = None
2222
DEFERRED_BINDING_REGISTRY = None
23-
deferred_bindings_enabled = False
2423
deferred_bindings_cache = {}
2524

2625

@@ -259,12 +258,11 @@ def deferred_bindings_decode(binding: typing.Any,
259258
return deferred_binding_type
260259

261260

262-
def set_deferred_bindings_flag(param_anno: type):
263-
# If flag hasn't already been set
264-
# If DEFERRED_BINDING_REGISTRY is not None
265-
# If the binding type is a deferred binding type
266-
global deferred_bindings_enabled
267-
if (not deferred_bindings_enabled
268-
and DEFERRED_BINDING_REGISTRY is not None
269-
and DEFERRED_BINDING_REGISTRY.check_supported_type(param_anno)):
270-
deferred_bindings_enabled = True
261+
def check_deferred_bindings_enabled(param_anno: type,
262+
deferred_bindings_enabled: bool) -> bool:
263+
# If previous binding was SDK type, deferred_bindings_enabled will be
264+
# True
265+
return (deferred_bindings_enabled
266+
or (DEFERRED_BINDING_REGISTRY is not None
267+
and DEFERRED_BINDING_REGISTRY.check_supported_type(
268+
param_anno)))

azure_functions_worker/functions.py

+26-15
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class FunctionInfo(typing.NamedTuple):
3131
output_types: typing.Mapping[str, ParamTypeInfo]
3232
return_type: typing.Optional[ParamTypeInfo]
3333

34+
deferred_bindings_enabled: bool
35+
3436

3537
class FunctionLoadError(RuntimeError):
3638

@@ -137,15 +139,19 @@ def validate_function_params(params: dict, bound_params: dict,
137139

138140
input_types: typing.Dict[str, ParamTypeInfo] = {}
139141
output_types: typing.Dict[str, ParamTypeInfo] = {}
142+
deferred_bindings_enabled = False
140143

141144
for param in params.values():
142145
binding = bound_params[param.name]
143146

144147
param_has_anno = param.name in annotations
145148
param_anno = annotations.get(param.name)
146149

147-
# Check the declared type
148-
bindings_utils.set_deferred_bindings_flag(param_anno)
150+
# Check if deferred bindings is enabled
151+
deferred_bindings_enabled = (
152+
bindings_utils.check_deferred_bindings_enabled(
153+
param_anno,
154+
deferred_bindings_enabled))
149155

150156
if param_has_anno:
151157
if typing_inspect.is_generic_type(param_anno):
@@ -245,7 +251,7 @@ def validate_function_params(params: dict, bound_params: dict,
245251
output_types[param.name] = param_type_info
246252
else:
247253
input_types[param.name] = param_type_info
248-
return input_types, output_types
254+
return input_types, output_types, deferred_bindings_enabled
249255

250256
@staticmethod
251257
def get_function_return_type(annotations: dict, has_explicit_return: bool,
@@ -298,7 +304,8 @@ def add_func_to_registry_and_return_funcinfo(self, function,
298304
str, ParamTypeInfo],
299305
output_types: typing.Dict[
300306
str, ParamTypeInfo],
301-
return_type: str):
307+
return_type: str,
308+
deferred_bindings_enabled: bool):
302309

303310
function_info = FunctionInfo(
304311
func=function,
@@ -310,7 +317,8 @@ def add_func_to_registry_and_return_funcinfo(self, function,
310317
has_return=has_explicit_return or has_implicit_return,
311318
input_types=input_types,
312319
output_types=output_types,
313-
return_type=return_type)
320+
return_type=return_type,
321+
deferred_bindings_enabled=deferred_bindings_enabled)
314322

315323
self._functions[function_id] = function_info
316324
return function_info
@@ -347,10 +355,10 @@ def add_function(self, function_id: str,
347355
annotations,
348356
func_name)
349357

350-
input_types, output_types = self.validate_function_params(params,
351-
bound_params,
352-
annotations,
353-
func_name)
358+
input_types, output_types, _ = self.validate_function_params(params,
359+
bound_params,
360+
annotations,
361+
func_name)
354362

355363
return_type = \
356364
self.get_function_return_type(annotations,
@@ -366,7 +374,7 @@ def add_function(self, function_id: str,
366374
has_explicit_return,
367375
has_implicit_return,
368376
input_types,
369-
output_types, return_type)
377+
output_types, return_type, _)
370378

371379
def add_indexed_function(self, function):
372380
func = function.get_user_function()
@@ -404,10 +412,12 @@ def add_indexed_function(self, function):
404412
annotations,
405413
func_name)
406414

407-
input_types, output_types = self.validate_function_params(params,
408-
bound_params,
409-
annotations,
410-
func_name)
415+
(input_types, output_types,
416+
deferred_bindings_enabled) = self.validate_function_params(
417+
params,
418+
bound_params,
419+
annotations,
420+
func_name)
411421

412422
return_type = \
413423
self.get_function_return_type(annotations,
@@ -425,4 +435,5 @@ def add_indexed_function(self, function):
425435
has_implicit_return,
426436
input_types,
427437
output_types,
428-
return_type)
438+
return_type,
439+
deferred_bindings_enabled)

azure_functions_worker/loader.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -245,13 +245,7 @@ def index_function_app(function_path: str):
245245

246246

247247
def get_fx_raw_bindings(indexed_function, function_info):
248-
# If the flag is True, we know that:
249-
# 1. Library is imported
250-
# 2. At least one binding is a defined deferred binding type
251-
# 3. DEFERRED_BINDING_REGISTRY is not None
252-
if bindings.meta.deferred_bindings_enabled:
253-
# Reset the flag
254-
bindings.meta.deferred_bindings_enabled = False
248+
if function_info.deferred_bindings_enabled:
255249
return bindings.meta.DEFERRED_BINDING_REGISTRY.get_raw_bindings(
256250
indexed_function, function_info.input_types)
257251

tests/extension_tests/deferred_bindings_tests/deferred_bindings_blob_functions/function_app.py

+19
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,25 @@ def bc_and_inputstream_input(req: func.HttpRequest, client: bindings.BlobClient,
197197
return output_msg
198198

199199

200+
@app.function_name(name="inputstream_and_bc_input")
201+
@app.route(route="inputstream_and_bc_input")
202+
@app.blob_input(arg_name="blob",
203+
path="python-worker-tests/test-blob-extension-str.txt",
204+
data_type="STRING",
205+
connection="AzureWebJobsStorage")
206+
@app.blob_input(arg_name="client",
207+
path="python-worker-tests/test-blob-extension-str.txt",
208+
data_type="STRING",
209+
connection="AzureWebJobsStorage")
210+
def inputstream_and_bc_input(req: func.HttpRequest, blob: func.InputStream,
211+
client: bindings.BlobClient) -> str:
212+
output_msg = ""
213+
file = blob.read().decode('utf-8')
214+
client_file = client.download_blob(encoding='utf-8').readall()
215+
output_msg = file + " - input stream " + client_file + " - blob client"
216+
return output_msg
217+
218+
200219
@app.function_name(name="type_undefined")
201220
@app.route(route="type_undefined")
202221
@app.blob_input(arg_name="file",

tests/extension_tests/deferred_bindings_tests/test_deferred_bindings.py

+25-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
import unittest
44
import sys
55

6+
import azure.functions as func
7+
68
from azure_functions_worker import protos
79
from azure_functions_worker.bindings import datumdef, meta
810
from tests.utils import testutils
911

10-
from azure.functions.extension.blob import BlobClient, BlobClientConverter
12+
# Even if the tests are skipped for <=3.8, the library is still imported as
13+
# it is used for these tests.
14+
if sys.version_info.minor >= 9:
15+
from azure.functions.extension.blob import BlobClient, BlobClientConverter
1116

1217
DEFERRED_BINDINGS_ENABLED_DIR = testutils.EXTENSION_TESTS_FOLDER / \
1318
'deferred_bindings_tests' / \
@@ -73,7 +78,6 @@ async def test_non_deferred_bindings_metadata(self):
7378
self.assertIsInstance(r.response, protos.FunctionMetadataResponse)
7479
self.assertEqual(r.response.result.status,
7580
protos.StatusResult.Success)
76-
self.assertFalse(meta.deferred_bindings_enabled)
7781

7882

7983
@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
@@ -117,3 +121,22 @@ def test_deferred_bindings_decode(self):
117121
pytype=BlobClient, datum=datum, metadata={})
118122

119123
self.assertIsNotNone(obj)
124+
125+
async def test_check_deferred_bindings_enabled(self):
126+
async with testutils.start_mockhost(
127+
script_root=DEFERRED_BINDINGS_DISABLED_DIR) as host:
128+
await host.init_worker()
129+
130+
self.assertFalse(meta.check_deferred_bindings_enabled(
131+
func.InputStream,
132+
False))
133+
self.assertTrue(meta.check_deferred_bindings_enabled(
134+
func.InputStream,
135+
True))
136+
137+
self.assertTrue(meta.check_deferred_bindings_enabled(
138+
BlobClient,
139+
False))
140+
self.assertTrue(meta.check_deferred_bindings_enabled(
141+
BlobClient,
142+
True))

tests/extension_tests/deferred_bindings_tests/test_deferred_bindings_blob_functions.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ def test_bc_and_inputstream_input(self):
150150
self.assertEqual(r.status_code, 200)
151151
self.assertEqual(r.text, 'test-data - input stream test-data - blob client')
152152

153+
def test_inputstream_and_bc_input(self):
154+
r = self.webhost.request('POST', 'put_blob_str', data='test-data')
155+
self.assertEqual(r.status_code, 200)
156+
self.assertEqual(r.text, 'OK')
157+
158+
r = self.webhost.request('GET', 'inputstream_and_bc_input')
159+
self.assertEqual(r.status_code, 200)
160+
self.assertEqual(r.text, 'test-data - input stream test-data - blob client')
161+
153162
def test_type_undefined(self):
154163
r = self.webhost.request('POST', 'put_blob_str', data='test-data')
155164
self.assertEqual(r.status_code, 200)
@@ -159,8 +168,6 @@ def test_type_undefined(self):
159168
self.assertEqual(r.status_code, 200)
160169
self.assertEqual(r.text, 'test-data')
161170

162-
self.assertFalse(meta.deferred_bindings_enabled)
163-
164171
def test_caching(self):
165172
# Cache is empty at the start
166173
self.assertEqual(meta.deferred_bindings_cache, {})

0 commit comments

Comments
 (0)