Skip to content

Commit 25ddb07

Browse files
authored
Merge branch 'dev' into jviau/targets
2 parents d3b1842 + 5299308 commit 25ddb07

File tree

20 files changed

+323
-19
lines changed

20 files changed

+323
-19
lines changed

azure_functions_worker/bindings/datumdef.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ def datum_as_proto(datum: Datum) -> protos.TypedData:
199199
enable_content_negotiation=False,
200200
body=datum_as_proto(datum.value['body']),
201201
))
202+
elif datum.type is None:
203+
return None
202204
else:
203205
raise NotImplementedError(
204206
'unexpected Datum type: {!r}'.format(datum.type)

azure_functions_worker/bindings/generic.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,17 @@ def encode(cls, obj: Any, *,
2828

2929
elif isinstance(obj, (bytes, bytearray)):
3030
return datumdef.Datum(type='bytes', value=bytes(obj))
31-
31+
elif obj is None:
32+
return datumdef.Datum(type=None, value=obj)
3233
else:
3334
raise NotImplementedError
3435

3536
@classmethod
3637
def decode(cls, data: datumdef.Datum, *, trigger_metadata) -> typing.Any:
38+
# Enabling support for Dapr bindings
39+
# https://github.com/Azure/azure-functions-python-worker/issues/1316
40+
if data is None:
41+
return None
3742
data_type = data.type
3843

3944
if data_type == 'string':
@@ -42,6 +47,8 @@ def decode(cls, data: datumdef.Datum, *, trigger_metadata) -> typing.Any:
4247
result = data.value
4348
elif data_type == 'json':
4449
result = data.value
50+
elif data_type is None:
51+
result = None
4552
else:
4653
raise ValueError(
4754
f'unexpected type of data received for the "generic" binding '

azure_functions_worker/bindings/meta.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,8 @@ def to_outgoing_param_binding(binding: str, obj: typing.Any, *,
270270
rpc_shared_memory=shared_mem_value)
271271
else:
272272
# If not, send it as part of the response message over RPC
273+
# rpc_val can be None here as we now support a None return type
273274
rpc_val = datumdef.datum_as_proto(datum)
274-
if rpc_val is None:
275-
raise TypeError('Cannot convert datum to rpc_val')
276275
return protos.ParameterBinding(
277276
name=out_name,
278277
data=rpc_val)

azure_functions_worker/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,6 @@
8080

8181
# Base extension supported Python minor version
8282
BASE_EXT_SUPPORTED_PY_MINOR_VERSION = 8
83+
84+
PYTHON_ENABLE_OPENTELEMETRY = "PYTHON_ENABLE_OPENTELEMETRY"
85+
PYTHON_ENABLE_OPENTELEMETRY_DEFAULT = True

azure_functions_worker/dispatcher.py

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
PYTHON_SCRIPT_FILE_NAME,
3131
PYTHON_SCRIPT_FILE_NAME_DEFAULT,
3232
PYTHON_LANGUAGE_RUNTIME, PYTHON_ENABLE_INIT_INDEXING,
33-
METADATA_PROPERTIES_WORKER_INDEXED)
33+
METADATA_PROPERTIES_WORKER_INDEXED,
34+
PYTHON_ENABLE_OPENTELEMETRY,
35+
PYTHON_ENABLE_OPENTELEMETRY_DEFAULT)
3436
from .extension import ExtensionManager
3537
from .http_v2 import http_coordinator, initialize_http_server, HttpV2Registry, \
3638
sync_http_request, HttpServerInitError
@@ -318,10 +320,12 @@ async def _handle__worker_init_request(self, request):
318320
constants.SHARED_MEMORY_DATA_TRANSFER: _TRUE,
319321
}
320322

321-
self.update_opentelemetry_status()
323+
if get_app_setting(setting=PYTHON_ENABLE_OPENTELEMETRY,
324+
default_value=PYTHON_ENABLE_OPENTELEMETRY_DEFAULT):
325+
self.update_opentelemetry_status()
322326

323-
if self._otel_libs_available:
324-
capabilities[constants.WORKER_OPEN_TELEMETRY_ENABLED] = _TRUE
327+
if self._otel_libs_available:
328+
capabilities[constants.WORKER_OPEN_TELEMETRY_ENABLED] = _TRUE
325329

326330
if DependencyManager.should_load_cx_dependencies():
327331
DependencyManager.prioritize_customer_dependencies()
@@ -383,8 +387,10 @@ def load_function_metadata(self, function_app_directory, caller_info):
383387
function_path = os.path.join(function_app_directory,
384388
script_file_name)
385389

390+
# For V1, the function path will not exist and
391+
# return None.
386392
self._function_metadata_result = (
387-
self.index_functions(function_path)) \
393+
self.index_functions(function_path, function_app_directory)) \
388394
if os.path.exists(function_path) else None
389395

390396
async def _handle__functions_metadata_request(self, request):
@@ -439,8 +445,9 @@ async def _handle__function_load_request(self, request):
439445

440446
logger.info(
441447
'Received WorkerLoadRequest, request ID %s, function_id: %s,'
442-
'function_name: %s',
443-
self.request_id, function_id, function_name)
448+
'function_name: %s, function_app_directory : %s',
449+
self.request_id, function_id, function_name,
450+
function_app_directory)
444451

445452
programming_model = "V2"
446453
try:
@@ -705,9 +712,14 @@ async def _handle__function_environment_reload_request(self, request):
705712
bindings.load_binding_registry()
706713

707714
capabilities = {}
708-
self.update_opentelemetry_status()
709-
if self._otel_libs_available:
710-
capabilities[constants.WORKER_OPEN_TELEMETRY_ENABLED] = _TRUE
715+
if get_app_setting(
716+
setting=PYTHON_ENABLE_OPENTELEMETRY,
717+
default_value=PYTHON_ENABLE_OPENTELEMETRY_DEFAULT):
718+
self.update_opentelemetry_status()
719+
720+
if self._otel_libs_available:
721+
capabilities[constants.WORKER_OPEN_TELEMETRY_ENABLED] = (
722+
_TRUE)
711723

712724
if is_envvar_true(PYTHON_ENABLE_INIT_INDEXING):
713725
try:
@@ -749,7 +761,7 @@ async def _handle__function_environment_reload_request(self, request):
749761
request_id=self.request_id,
750762
function_environment_reload_response=failure_response)
751763

752-
def index_functions(self, function_path: str):
764+
def index_functions(self, function_path: str, function_dir: str):
753765
indexed_functions = loader.index_function_app(function_path)
754766
logger.info(
755767
"Indexed function app and found %s functions",
@@ -760,7 +772,8 @@ def index_functions(self, function_path: str):
760772
fx_metadata_results, fx_bindings_logs = (
761773
loader.process_indexed_function(
762774
self._functions,
763-
indexed_functions))
775+
indexed_functions,
776+
function_dir))
764777

765778
indexed_function_logs: List[str] = []
766779
indexed_function_bindings_logs = []

azure_functions_worker/loader.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def build_variable_interval_retry(retry, max_retry_count, retry_strategy):
121121

122122

123123
def process_indexed_function(functions_registry: functions.Registry,
124-
indexed_functions):
124+
indexed_functions, function_dir):
125125
"""
126126
fx_metadata_results is a list of the RpcFunctionMetadata for
127127
all the functions in the particular app.
@@ -150,7 +150,7 @@ def process_indexed_function(functions_registry: functions.Registry,
150150
name=function_info.name,
151151
function_id=function_info.function_id,
152152
managed_dependency_enabled=False, # only enabled for PowerShell
153-
directory=function_info.directory,
153+
directory=function_dir,
154154
script_file=indexed_function.function_script_file,
155155
entry_point=function_info.name,
156156
is_proxy=False, # not supported in V4

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"azure_functions_worker._thirdparty",
7272
]
7373

74-
INSTALL_REQUIRES = ["azure-functions==1.19.0", "python-dateutil~=2.8.2"]
74+
INSTALL_REQUIRES = ["azure-functions==1.20.0b1", "python-dateutil~=2.8.2"]
7575

7676
if sys.version_info[:2] == (3, 7):
7777
INSTALL_REQUIRES.extend(

tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import logging
2+
import time
3+
from datetime import datetime
24

35
import azure.functions as func
46

@@ -29,3 +31,11 @@ def default_template(req: func.HttpRequest) -> func.HttpResponse:
2931
" personalized response.",
3032
status_code=200
3133
)
34+
35+
36+
@bp.route(route="http_func")
37+
def http_func(req: func.HttpRequest) -> func.HttpResponse:
38+
time.sleep(1)
39+
40+
current_time = datetime.now().strftime("%H:%M:%S")
41+
return func.HttpResponse(f"{current_time}")

tests/endtoend/generic_functions/generic_functions_stein/function_app.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
33
import azure.functions as func
4+
import logging
45

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

@@ -29,3 +30,16 @@ def return_processed_last(req: func.HttpRequest, testEntity):
2930
table_name="EventHubBatchTest")
3031
def return_not_processed_last(req: func.HttpRequest, testEntities):
3132
return func.HttpResponse(status_code=200)
33+
34+
35+
@app.function_name(name="mytimer")
36+
@app.schedule(schedule="*/1 * * * * *", arg_name="mytimer",
37+
run_on_startup=False,
38+
use_monitor=False)
39+
@app.generic_input_binding(
40+
arg_name="testEntity",
41+
type="table",
42+
connection="AzureWebJobsStorage",
43+
table_name="EventHubBatchTest")
44+
def mytimer(mytimer: func.TimerRequest, testEntity) -> None:
45+
logging.info("This timer trigger function executed successfully")
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"scriptFile": "main.py",
3+
"bindings": [
4+
{
5+
"name": "mytimer",
6+
"type": "timerTrigger",
7+
"direction": "in",
8+
"schedule": "*/1 * * * * *",
9+
"runOnStartup": false
10+
},
11+
{
12+
"direction": "in",
13+
"type": "table",
14+
"name": "testEntity",
15+
"partitionKey": "test",
16+
"rowKey": "WillBePopulatedWithGuid",
17+
"tableName": "BindingTestTable",
18+
"connection": "AzureWebJobsStorage"
19+
}
20+
]
21+
}

0 commit comments

Comments
 (0)