azure-functions-runtime 1.0.0.dev0__tar.gz → 1.1.0b2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/PKG-INFO +3 -2
  2. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/__init__.py +9 -1
  3. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/meta.py +41 -10
  4. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/nullable_converters.py +13 -1
  5. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/functions.py +27 -11
  6. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/handle_event.py +19 -8
  7. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/http_v2.py +2 -2
  8. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/loader.py +22 -4
  9. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/otel.py +1 -1
  10. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/constants.py +1 -0
  11. azure_functions_runtime-1.1.0b2/azure_functions_runtime/utils/threadpool.py +88 -0
  12. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/tracing.py +22 -24
  13. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/version.py +1 -1
  14. {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/azure_functions_runtime.egg-info/PKG-INFO +3 -2
  15. azure_functions_runtime-1.1.0b2/azure_functions_runtime.egg-info/SOURCES.txt +33 -0
  16. {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/azure_functions_runtime.egg-info/requires.txt +1 -0
  17. azure_functions_runtime-1.1.0b2/azure_functions_runtime.egg-info/top_level.txt +2 -0
  18. {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/pyproject.toml +5 -4
  19. azure_functions_runtime-1.0.0.dev0/azure_functions_runtime.egg-info/SOURCES.txt +0 -32
  20. azure_functions_runtime-1.0.0.dev0/azure_functions_runtime.egg-info/top_level.txt +0 -3
  21. {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/README.md +0 -0
  22. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/context.py +0 -0
  23. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/datumdef.py +0 -0
  24. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/generic.py +0 -0
  25. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/out.py +0 -0
  26. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/retrycontext.py +0 -0
  27. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/tracecontext.py +0 -0
  28. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/logging.py +0 -0
  29. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/__init__.py +0 -0
  30. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/app_setting_manager.py +0 -0
  31. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/executor.py +0 -0
  32. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/helpers.py +0 -0
  33. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/typing_inspect.py +0 -0
  34. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/validators.py +0 -0
  35. {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/wrappers.py +0 -0
  36. {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/azure_functions_runtime.egg-info/dependency_links.txt +0 -0
  37. {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/setup.cfg +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: azure-functions-runtime
3
- Version: 1.0.0.dev0
3
+ Version: 1.1.0b2
4
4
  Summary: Python Language Worker for Azure Functions Runtime
5
5
  Author-email: "Azure Functions team at Microsoft Corp." <azurefunctions@microsoft.com>
6
- Project-URL: Documentation, https://github.com/Azure/azure-functions-python-worker/blob/dev/azure_functions_worker_v2/README.md
6
+ Project-URL: Documentation, https://github.com/Azure/azure-functions-python-worker/blob/dev/azure_functions_runtime/README.md
7
7
  Project-URL: Repository, https://github.com/Azure/azure-functions-python-worker
8
8
  Keywords: azure,functions,azurefunctions,python,serverless
9
9
  Classifier: Development Status :: 5 - Production/Stable
@@ -29,6 +29,7 @@ Requires-Dist: requests==2.*; extra == "dev"
29
29
  Requires-Dist: coverage; extra == "dev"
30
30
  Requires-Dist: grpcio~=1.70.0; extra == "dev"
31
31
  Requires-Dist: grpcio-tools~=1.70.0; extra == "dev"
32
+ Requires-Dist: protobuf~=5.29.0; extra == "dev"
32
33
  Requires-Dist: pytest-sugar; extra == "dev"
33
34
  Requires-Dist: pytest-cov; extra == "dev"
34
35
  Requires-Dist: pytest-xdist; extra == "dev"
@@ -5,9 +5,17 @@ from .handle_event import (worker_init_request,
5
5
  function_environment_reload_request,
6
6
  invocation_request,
7
7
  function_load_request)
8
+ from .utils.threadpool import (
9
+ start_threadpool_executor,
10
+ stop_threadpool_executor,
11
+ get_threadpool_executor,
12
+ )
8
13
 
9
14
  __all__ = ('worker_init_request',
10
15
  'functions_metadata_request',
11
16
  'function_environment_reload_request',
12
17
  'invocation_request',
13
- 'function_load_request')
18
+ 'function_load_request',
19
+ 'start_threadpool_executor',
20
+ 'stop_threadpool_executor',
21
+ 'get_threadpool_executor')
@@ -1,7 +1,6 @@
1
1
  # Copyright (c) Microsoft Corporation. All rights reserved.
2
2
  # Licensed under the MIT License.
3
3
  # mypy: disable-error-code="attr-defined"
4
- import importlib.util
5
4
  import os
6
5
  import sys
7
6
 
@@ -16,9 +15,9 @@ from ..utils.constants import (
16
15
  CUSTOMER_PACKAGES_PATH,
17
16
  HTTP,
18
17
  HTTP_TRIGGER,
18
+ SERVICE_BUS_CLIENT_NAME
19
19
  )
20
20
  from ..utils.helpers import set_sdk_version
21
- from ..utils.tracing import serialize_exception_as_str
22
21
 
23
22
 
24
23
  PB_TYPE = 'rpc_data'
@@ -87,16 +86,12 @@ def load_binding_registry() -> None:
87
86
  import azurefunctions.extensions.base as clients
88
87
  global DEFERRED_BINDING_REGISTRY
89
88
  DEFERRED_BINDING_REGISTRY = clients.get_binding_registry()
90
- except Exception as e:
91
- func_spec = importlib.util.find_spec('azure.functions')
92
- logger.info('Base extension not found. Exception: %s. '
93
- 'Azure Functions library spec: %s, '
89
+ except ImportError:
90
+ logger.debug('Base extension not found. '
94
91
  'Python version: 3.%s, Sys path: %s, '
95
92
  'Sys Module: %s, python-packages Path exists: %s.',
96
- serialize_exception_as_str(e), func_spec,
97
- sys.version_info.minor,
98
- sys.path, sys.modules,
99
- os.path.exists(CUSTOMER_PACKAGES_PATH))
93
+ sys.version_info.minor, sys.path,
94
+ sys.modules, os.path.exists(CUSTOMER_PACKAGES_PATH))
100
95
 
101
96
 
102
97
  def get_binding(bind_name: str,
@@ -292,3 +287,39 @@ def get_deferred_raw_bindings(indexed_function, input_types):
292
287
  raw_bindings, bindings_logs = DEFERRED_BINDING_REGISTRY.get_raw_bindings(
293
288
  indexed_function, input_types)
294
289
  return raw_bindings, bindings_logs
290
+
291
+
292
+ def get_settlement_client():
293
+ return DEFERRED_BINDING_REGISTRY.get(SERVICE_BUS_CLIENT_NAME).get_client()
294
+
295
+
296
+ def validate_settlement_param(params: dict,
297
+ bound_params: dict,
298
+ annotations: dict) -> str:
299
+ """
300
+ Checks if the settlement client is enabled for a given function.
301
+
302
+ If there is more than one param that is not bound, return an empty string
303
+ indicating no settlement client support. This is a bad app.
304
+
305
+ If there is only one unbound param, check if it's a type that is supported
306
+ by the settlement client. If so, return the param_name, where param_name
307
+ is the name of the param that is supported. If not, return an empty string
308
+ indicating no settlement client support.
309
+
310
+ Note: If a param does not have a type annotation, it will be skipped and not
311
+ considered for settlement client support.
312
+ """
313
+ if len(set(params) - set(bound_params)) > 1:
314
+ return None
315
+
316
+ # There is only one unbound param, check the type
317
+ settlement_param = next(iter(set(params) - set(bound_params)))
318
+ try:
319
+ param_type = annotations.get(settlement_param)
320
+ # Check if the type is a supported type for the settlement client
321
+ if DEFERRED_BINDING_REGISTRY.check_supported_grpc_client_type(param_type):
322
+ return settlement_param
323
+ except Exception:
324
+ param_type = None
325
+ return None
@@ -1,5 +1,7 @@
1
1
  # Copyright (c) Microsoft Corporation. All rights reserved.
2
2
  # Licensed under the MIT License.
3
+ import sys
4
+
3
5
  from datetime import datetime
4
6
  from typing import Optional, Union
5
7
 
@@ -103,8 +105,18 @@ def to_nullable_timestamp(date_time: Optional[Union[datetime, int]],
103
105
  int) else \
104
106
  date_time.timestamp()
105
107
 
108
+ try:
109
+ from google.protobuf.timestamp_pb2 import Timestamp
110
+ except ImportError:
111
+ raise ImportError(
112
+ "protobuf not found when trying to "
113
+ "import Timestamp."
114
+ "Sys Path: %s. "
115
+ "Sys Modules: %s. ",
116
+ sys.path, sys.modules)
117
+
106
118
  return protos.NullableTimestamp(
107
- value=protos.Timestamp(seconds=int(time_in_seconds)))
119
+ value=Timestamp(seconds=int(time_in_seconds)))
108
120
  except Exception:
109
121
  raise TypeError(
110
122
  "A 'datetime' or 'int'"
@@ -11,7 +11,8 @@ from .logging import logger
11
11
  from .bindings.meta import (has_implicit_output,
12
12
  check_deferred_bindings_enabled,
13
13
  check_output_type_annotation,
14
- check_input_type_annotation)
14
+ check_input_type_annotation,
15
+ validate_settlement_param)
15
16
  from .utils.constants import HTTP_TRIGGER
16
17
  from .utils.typing_inspect import is_generic_type, get_origin, get_args # type: ignore
17
18
 
@@ -33,6 +34,7 @@ class FunctionInfo(typing.NamedTuple):
33
34
  has_return: bool
34
35
  is_http_func: bool
35
36
  deferred_bindings_enabled: bool
37
+ settlement_client_arg: typing.Optional[str]
36
38
 
37
39
  input_types: typing.Mapping[str, ParamTypeInfo]
38
40
  output_types: typing.Mapping[str, ParamTypeInfo]
@@ -138,19 +140,27 @@ class Registry:
138
140
  protos):
139
141
  logger.debug("Params: %s, BoundParams: %s, Annotations: %s, FuncName: %s",
140
142
  params, bound_params, annotations, func_name)
143
+ settlement_client_arg = None
141
144
  if set(params) - set(bound_params):
142
- raise FunctionLoadError(
143
- func_name,
144
- '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
+ # Check for settlement client support for the missing parameters
146
+ settlement_client_arg = validate_settlement_param(
147
+ params, bound_params, annotations)
148
+ if settlement_client_arg is not None:
149
+ params.pop(settlement_client_arg)
150
+ else:
151
+ # Not supported by settlement client, raise error for missing parameters
152
+ raise FunctionLoadError(
153
+ func_name,
154
+ 'the following parameters are declared in Python '
155
+ 'but not in the function definition (function.json or '
156
+ f'function decorators): {set(params) - set(bound_params)!r}')
147
157
 
148
158
  if set(bound_params) - set(params):
149
159
  raise FunctionLoadError(
150
160
  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)))
161
+ 'Extra parameters in binding definition — the following parameters '
162
+ 'are declared as bindings but are not '
163
+ 'present in Python: ' + repr(set(params) - set(bound_params)))
154
164
 
155
165
  input_types: typing.Dict[str, ParamTypeInfo] = {}
156
166
  output_types: typing.Dict[str, ParamTypeInfo] = {}
@@ -278,7 +288,8 @@ class Registry:
278
288
  output_types[param.name] = param_type_info
279
289
  else:
280
290
  input_types[param.name] = param_type_info
281
- return input_types, output_types, fx_deferred_bindings_enabled
291
+ return (input_types, output_types, fx_deferred_bindings_enabled,
292
+ settlement_client_arg)
282
293
 
283
294
  @staticmethod
284
295
  def get_function_return_type(annotations: dict, has_explicit_return: bool,
@@ -289,6 +300,7 @@ class Registry:
289
300
  return_anno = annotations.get('return')
290
301
  if is_generic_type(
291
302
  return_anno) and get_origin(
303
+ return_anno) is not None and get_origin(
292
304
  return_anno).__name__ == 'Out':
293
305
  raise FunctionLoadError(
294
306
  func_name,
@@ -329,6 +341,7 @@ class Registry:
329
341
  has_explicit_return: bool,
330
342
  has_implicit_return: bool,
331
343
  deferred_bindings_enabled: bool,
344
+ settlement_client_arg: typing.Optional[str],
332
345
  input_types: typing.Dict[str, ParamTypeInfo],
333
346
  output_types: typing.Dict[str, ParamTypeInfo],
334
347
  return_type: str):
@@ -354,6 +367,7 @@ class Registry:
354
367
  has_return=has_explicit_return or has_implicit_return,
355
368
  is_http_func=is_http_func,
356
369
  deferred_bindings_enabled=deferred_bindings_enabled,
370
+ settlement_client_arg=settlement_client_arg,
357
371
  input_types=input_types,
358
372
  output_types=output_types,
359
373
  return_type=return_type,
@@ -411,7 +425,8 @@ class Registry:
411
425
  func_name)
412
426
 
413
427
  (input_types, output_types,
414
- deferred_bindings_enabled) = self.validate_function_params(
428
+ deferred_bindings_enabled,
429
+ settlement_client_arg) = self.validate_function_params(
415
430
  params,
416
431
  bound_params,
417
432
  annotations,
@@ -430,5 +445,6 @@ class Registry:
430
445
  func, func_name, function_id, func_dir,
431
446
  requires_context, has_explicit_return,
432
447
  has_implicit_return, deferred_bindings_enabled,
448
+ settlement_client_arg,
433
449
  input_types, output_types,
434
450
  return_type)
@@ -22,6 +22,7 @@ from .version import VERSION
22
22
 
23
23
  from .bindings.context import get_context
24
24
  from .bindings.meta import (from_incoming_proto,
25
+ get_settlement_client,
25
26
  is_trigger_binding,
26
27
  load_binding_registry,
27
28
  to_outgoing_param_binding,
@@ -47,6 +48,7 @@ from .utils.constants import (FUNCTION_DATA_CACHE,
47
48
  WORKER_OPEN_TELEMETRY_ENABLED,
48
49
  WORKER_STATUS)
49
50
  from .utils.executor import get_current_loop, execute_async, run_sync_func
51
+ from .utils.threadpool import get_threadpool_executor
50
52
  from .utils.helpers import change_cwd, get_sdk_version, get_worker_metadata
51
53
  from .utils.tracing import serialize_exception
52
54
  from .utils.validators import validate_script_file_name
@@ -165,10 +167,15 @@ async def invocation_request(request):
165
167
  invocation_id = invoc_request.invocation_id
166
168
  function_id = invoc_request.function_id
167
169
  http_v2_enabled = False
168
- threadpool = request.properties.get("threadpool")
169
- logger.debug("All variables obtained from proxy worker."
170
- " Invocation ID: %s, Function ID: %s, Threadpool: %s",
171
- invocation_id, function_id, threadpool)
170
+
171
+ threadpool = get_threadpool_executor()
172
+ logger.debug(
173
+ "Invocation context prepared. Invocation ID: %s, Function ID: %s, "
174
+ "Threadpool id: %s",
175
+ invocation_id,
176
+ function_id,
177
+ id(threadpool) if threadpool else None,
178
+ )
172
179
 
173
180
  try:
174
181
  fi: FunctionInfo = _functions.get_function(
@@ -218,6 +225,9 @@ async def invocation_request(request):
218
225
  if fi.requires_context:
219
226
  args['context'] = fi_context
220
227
 
228
+ if fi.settlement_client_arg is not None:
229
+ args[fi.settlement_client_arg] = get_settlement_client()
230
+
221
231
  if fi.output_types:
222
232
  for name in fi.output_types:
223
233
  args[name] = Out()
@@ -292,7 +302,7 @@ async def function_environment_reload_request(request):
292
302
  This is called only when placeholder mode is true. On worker restarts
293
303
  worker init request will be called directly.
294
304
  """
295
- logger.debug("V2 Library Worker: received WorkerEnvReloadRequest,"
305
+ logger.debug("V2 Library Worker: received FunctionEnvironmentReloadRequest, "
296
306
  "Version %s", VERSION)
297
307
  global _host, protos
298
308
  try:
@@ -406,7 +416,7 @@ def index_functions(function_path: str, function_dir: str):
406
416
  indexed_functions = index_function_app(function_path)
407
417
 
408
418
  if indexed_functions:
409
- fx__metadata_results, fx_bindings_logs = (
419
+ fx_metadata_results, fx_bindings_logs = (
410
420
  process_indexed_function(
411
421
  protos,
412
422
  _functions,
@@ -434,8 +444,9 @@ def index_functions(function_path: str, function_dir: str):
434
444
  "function_count": len(indexed_functions),
435
445
  "functions": " ".join(indexed_function_logs),
436
446
  "deferred_bindings_enabled": _functions.deferred_bindings_enabled(),
437
- "app_settings": get_python_appsetting_state()
447
+ "app_settings": get_python_appsetting_state(),
448
+ "azure-functions version": get_sdk_version(),
438
449
  }
439
450
  logger.info(json.dumps(log_data))
440
451
 
441
- return fx__metadata_results
452
+ return fx_metadata_results
@@ -7,9 +7,9 @@ import socket
7
7
 
8
8
  from typing import Any, Dict
9
9
 
10
- from azure_functions_worker_v2.logging import logger
10
+ from azure_functions_runtime.logging import logger
11
11
 
12
- from azure_functions_worker_v2.utils.constants import (
12
+ from azure_functions_runtime.utils.constants import (
13
13
  X_MS_INVOCATION_ID,
14
14
  )
15
15
 
@@ -71,7 +71,16 @@ def get_retry_settings(indexed_function):
71
71
 
72
72
 
73
73
  def build_fixed_delay_retry(protos, retry, max_retry_count, retry_strategy):
74
- delay_interval = protos.Duration(
74
+ try:
75
+ from google.protobuf.duration_pb2 import Duration
76
+ except ImportError:
77
+ raise ImportError(
78
+ "protobuf not found when trying to "
79
+ "import Duration."
80
+ "Sys Path: %s. "
81
+ "Sys Modules: %s. ",
82
+ sys.path, sys.modules)
83
+ delay_interval = Duration(
75
84
  seconds=convert_to_seconds(retry.get(RetryPolicy.DELAY_INTERVAL.value))
76
85
  )
77
86
  return protos.RpcRetryOptions(
@@ -82,11 +91,20 @@ def build_fixed_delay_retry(protos, retry, max_retry_count, retry_strategy):
82
91
 
83
92
 
84
93
  def build_variable_interval_retry(protos, retry, max_retry_count, retry_strategy):
85
- minimum_interval = protos.Duration(
94
+ try:
95
+ from google.protobuf.duration_pb2 import Duration
96
+ except ImportError:
97
+ raise ImportError(
98
+ "protobuf not found when trying to "
99
+ "import Duration."
100
+ "Sys Path: %s. "
101
+ "Sys Modules: %s. ",
102
+ sys.path, sys.modules)
103
+ minimum_interval = Duration(
86
104
  seconds=convert_to_seconds(
87
105
  retry.get(RetryPolicy.MINIMUM_INTERVAL.value))
88
106
  )
89
- maximum_interval = protos.Duration(
107
+ maximum_interval = Duration(
90
108
  seconds=convert_to_seconds(
91
109
  retry.get(RetryPolicy.MAXIMUM_INTERVAL.value))
92
110
  )
@@ -150,7 +168,7 @@ def process_indexed_function(protos,
150
168
  message="Cannot find module. Please check the requirements.txt file for the "
151
169
  "missing module. For more info, please refer the troubleshooting guide: "
152
170
  + MODULE_NOT_FOUND_TS_URL + ". Current sys.path: " + " ".join(sys.path),
153
- debug_logs="Error in index_function_app. Sys Path:" + " ".join(sys.path)
171
+ debug_logs="Error when indexing function. Sys Path:" + " ".join(sys.path)
154
172
  + ", python-packages Path exists: "
155
173
  + str(os.path.exists(CUSTOMER_PACKAGES_PATH)))
156
174
  def index_function_app(function_path: str):
@@ -26,7 +26,7 @@ class OTelManager:
26
26
  return self._azure_monitor_available
27
27
 
28
28
  def set_otel_libs_available(self, otel_libs_available):
29
- self._aotel_libs_available = otel_libs_available
29
+ self._otel_libs_available = otel_libs_available
30
30
 
31
31
  def get_otel_libs_available(self):
32
32
  return self._otel_libs_available
@@ -11,6 +11,7 @@ METADATA_PROPERTIES_WORKER_INDEXED = "worker_indexed"
11
11
  MODULE_NOT_FOUND_TS_URL = "https://aka.ms/functions-modulenotfound"
12
12
  PYTHON_LANGUAGE_RUNTIME = "python"
13
13
  RETRY_POLICY = "retry_policy"
14
+ SERVICE_BUS_CLIENT_NAME = "serviceBusClient"
14
15
  TRUE = "true"
15
16
  TRACEPARENT = "traceparent"
16
17
  TRACESTATE = "tracestate"
@@ -0,0 +1,88 @@
1
+ from __future__ import annotations
2
+
3
+ from concurrent.futures import ThreadPoolExecutor
4
+ from typing import Optional
5
+
6
+ from .app_setting_manager import get_app_setting
7
+ from .constants import (
8
+ PYTHON_THREADPOOL_THREAD_COUNT,
9
+ PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT,
10
+ PYTHON_THREADPOOL_THREAD_COUNT_MIN,
11
+ PYTHON_THREADPOOL_THREAD_COUNT_MAX,
12
+ )
13
+ from ..logging import logger
14
+
15
+ _threadpool_executor: Optional[ThreadPoolExecutor] = None
16
+
17
+
18
+ def _validate_thread_count(value: str) -> bool:
19
+ try:
20
+ int_value = int(value)
21
+ except ValueError:
22
+ logger.warning('%s must be an integer', PYTHON_THREADPOOL_THREAD_COUNT)
23
+ return False
24
+
25
+ if (int_value < PYTHON_THREADPOOL_THREAD_COUNT_MIN
26
+ or int_value > PYTHON_THREADPOOL_THREAD_COUNT_MAX):
27
+ logger.warning(
28
+ '%s must be set to a value between %s and %s. Reverting to '
29
+ 'default value (%s).',
30
+ PYTHON_THREADPOOL_THREAD_COUNT,
31
+ PYTHON_THREADPOOL_THREAD_COUNT_MIN,
32
+ PYTHON_THREADPOOL_THREAD_COUNT_MAX,
33
+ PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT,
34
+ )
35
+ return False
36
+ return True
37
+
38
+
39
+ def _get_max_workers() -> Optional[int]:
40
+ threadpool_count = get_app_setting(
41
+ setting=PYTHON_THREADPOOL_THREAD_COUNT,
42
+ validator=_validate_thread_count,
43
+ )
44
+ if threadpool_count is None:
45
+ return None
46
+ try:
47
+ return int(threadpool_count)
48
+ except (TypeError, ValueError) as e:
49
+ logger.warning(
50
+ 'Failed to convert %s value "%s" to integer: %s',
51
+ PYTHON_THREADPOOL_THREAD_COUNT, threadpool_count, e
52
+ )
53
+ return None
54
+
55
+
56
+ def start_threadpool_executor() -> None:
57
+ global _threadpool_executor
58
+ max_workers = _get_max_workers()
59
+
60
+ if _threadpool_executor is not None:
61
+ try:
62
+ _threadpool_executor.shutdown(wait=False)
63
+ except Exception:
64
+ pass
65
+
66
+ _threadpool_executor = ThreadPoolExecutor(max_workers=max_workers)
67
+ logger.debug(
68
+ 'Started threadpool executor (id=%s) with max_workers=%s',
69
+ id(_threadpool_executor),
70
+ max_workers,
71
+ )
72
+
73
+
74
+ def stop_threadpool_executor() -> None:
75
+ global _threadpool_executor
76
+ if _threadpool_executor is not None:
77
+ try:
78
+ _threadpool_executor.shutdown(wait=True)
79
+ logger.debug(
80
+ 'Stopped threadpool executor (id=%s)',
81
+ id(_threadpool_executor)
82
+ )
83
+ finally:
84
+ _threadpool_executor = None
85
+
86
+
87
+ def get_threadpool_executor() -> Optional[ThreadPoolExecutor]:
88
+ return _threadpool_executor
@@ -2,14 +2,11 @@
2
2
  # Licensed under the MIT License.
3
3
  import traceback
4
4
 
5
- from traceback import StackSummary, extract_tb
6
- from typing import List
7
-
8
5
 
9
6
  def extend_exception_message(exc: Exception, msg: str) -> Exception:
10
7
  # Reconstruct exception message
11
8
  # From: ImportModule: no module name
12
- # To: ImportModule: no module name. msg
9
+ # To: ImportModule: no module name. msg
13
10
  old_tb = exc.__traceback__
14
11
  old_msg = getattr(exc, 'msg', None) or str(exc) or ''
15
12
  new_msg = (old_msg.rstrip('.') + '. ' + msg).rstrip()
@@ -18,26 +15,27 @@ def extend_exception_message(exc: Exception, msg: str) -> Exception:
18
15
 
19
16
 
20
17
  def marshall_exception_trace(exc: Exception) -> str:
21
- stack_summary: StackSummary = extract_tb(exc.__traceback__)
22
- if isinstance(exc, ModuleNotFoundError):
23
- stack_summary = _marshall_module_not_found_error(stack_summary)
24
- return ''.join(stack_summary.format())
25
-
26
-
27
- def _marshall_module_not_found_error(tbss: StackSummary) -> StackSummary:
28
- tbss = _remove_frame_from_stack(tbss, '<frozen importlib._bootstrap>')
29
- tbss = _remove_frame_from_stack(
30
- tbss, '<frozen importlib._bootstrap_external>')
31
- return tbss
32
-
33
-
34
- def _remove_frame_from_stack(tbss: StackSummary,
35
- framename: str) -> StackSummary:
36
- filtered_stack_list: List[traceback.FrameSummary] = \
37
- list(filter(lambda frame: getattr(frame,
38
- 'filename') != framename, tbss))
39
- filtered_stack: StackSummary = StackSummary.from_list(filtered_stack_list)
40
- return filtered_stack
18
+ try:
19
+ # Use traceback.format_exception to capture the full exception chain
20
+ # This includes __cause__ and __context__ chained exceptions
21
+ full_traceback = traceback.format_exception(type(exc), exc, exc.__traceback__)
22
+
23
+ # If it's a ModuleNotFoundError, we might want to clean up the traceback
24
+ if isinstance(exc, ModuleNotFoundError):
25
+ # For consistency with the original logic, we'll still filter
26
+ # but we need to work with the formatted strings
27
+ filtered_lines = []
28
+ for line in full_traceback:
29
+ if '<frozen importlib._bootstrap>' not in line and \
30
+ '<frozen importlib._bootstrap_external>' not in line:
31
+ filtered_lines.append(line)
32
+ if filtered_lines:
33
+ return ''.join(filtered_lines)
34
+
35
+ return ''.join(full_traceback)
36
+ except Exception as sub_exc:
37
+ return (f'Could not extract traceback. '
38
+ f'Sub-exception: {type(sub_exc).__name__}: {str(sub_exc)}')
41
39
 
42
40
 
43
41
  def serialize_exception(exc: Exception, protos):
@@ -1,4 +1,4 @@
1
1
  # Copyright (c) Microsoft Corporation. All rights reserved.
2
2
  # Licensed under the MIT License.
3
3
 
4
- VERSION = '1.0.0dev0'
4
+ VERSION = '1.1.0b2'
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: azure-functions-runtime
3
- Version: 1.0.0.dev0
3
+ Version: 1.1.0b2
4
4
  Summary: Python Language Worker for Azure Functions Runtime
5
5
  Author-email: "Azure Functions team at Microsoft Corp." <azurefunctions@microsoft.com>
6
- Project-URL: Documentation, https://github.com/Azure/azure-functions-python-worker/blob/dev/azure_functions_worker_v2/README.md
6
+ Project-URL: Documentation, https://github.com/Azure/azure-functions-python-worker/blob/dev/azure_functions_runtime/README.md
7
7
  Project-URL: Repository, https://github.com/Azure/azure-functions-python-worker
8
8
  Keywords: azure,functions,azurefunctions,python,serverless
9
9
  Classifier: Development Status :: 5 - Production/Stable
@@ -29,6 +29,7 @@ Requires-Dist: requests==2.*; extra == "dev"
29
29
  Requires-Dist: coverage; extra == "dev"
30
30
  Requires-Dist: grpcio~=1.70.0; extra == "dev"
31
31
  Requires-Dist: grpcio-tools~=1.70.0; extra == "dev"
32
+ Requires-Dist: protobuf~=5.29.0; extra == "dev"
32
33
  Requires-Dist: pytest-sugar; extra == "dev"
33
34
  Requires-Dist: pytest-cov; extra == "dev"
34
35
  Requires-Dist: pytest-xdist; extra == "dev"
@@ -0,0 +1,33 @@
1
+ README.md
2
+ pyproject.toml
3
+ azure_functions_runtime/__init__.py
4
+ azure_functions_runtime/functions.py
5
+ azure_functions_runtime/handle_event.py
6
+ azure_functions_runtime/http_v2.py
7
+ azure_functions_runtime/loader.py
8
+ azure_functions_runtime/logging.py
9
+ azure_functions_runtime/otel.py
10
+ azure_functions_runtime/version.py
11
+ azure_functions_runtime.egg-info/PKG-INFO
12
+ azure_functions_runtime.egg-info/SOURCES.txt
13
+ azure_functions_runtime.egg-info/dependency_links.txt
14
+ azure_functions_runtime.egg-info/requires.txt
15
+ azure_functions_runtime.egg-info/top_level.txt
16
+ azure_functions_runtime/bindings/context.py
17
+ azure_functions_runtime/bindings/datumdef.py
18
+ azure_functions_runtime/bindings/generic.py
19
+ azure_functions_runtime/bindings/meta.py
20
+ azure_functions_runtime/bindings/nullable_converters.py
21
+ azure_functions_runtime/bindings/out.py
22
+ azure_functions_runtime/bindings/retrycontext.py
23
+ azure_functions_runtime/bindings/tracecontext.py
24
+ azure_functions_runtime/utils/__init__.py
25
+ azure_functions_runtime/utils/app_setting_manager.py
26
+ azure_functions_runtime/utils/constants.py
27
+ azure_functions_runtime/utils/executor.py
28
+ azure_functions_runtime/utils/helpers.py
29
+ azure_functions_runtime/utils/threadpool.py
30
+ azure_functions_runtime/utils/tracing.py
31
+ azure_functions_runtime/utils/typing_inspect.py
32
+ azure_functions_runtime/utils/validators.py
33
+ azure_functions_runtime/utils/wrappers.py
@@ -10,6 +10,7 @@ requests==2.*
10
10
  coverage
11
11
  grpcio~=1.70.0
12
12
  grpcio-tools~=1.70.0
13
+ protobuf~=5.29.0
13
14
  pytest-sugar
14
15
  pytest-cov
15
16
  pytest-xdist
@@ -0,0 +1,2 @@
1
+ azure_functions_runtime
2
+ dist
@@ -28,7 +28,7 @@ dependencies = [
28
28
  ]
29
29
 
30
30
  [project.urls]
31
- Documentation = "https://github.com/Azure/azure-functions-python-worker/blob/dev/azure_functions_worker_v2/README.md"
31
+ Documentation = "https://github.com/Azure/azure-functions-python-worker/blob/dev/azure_functions_runtime/README.md"
32
32
  Repository = "https://github.com/Azure/azure-functions-python-worker"
33
33
 
34
34
  [project.optional-dependencies]
@@ -41,6 +41,7 @@ dev = [
41
41
  "coverage",
42
42
  "grpcio~=1.70.0",
43
43
  "grpcio-tools~=1.70.0",
44
+ "protobuf~=5.29.0",
44
45
  "pytest-sugar",
45
46
  "pytest-cov",
46
47
  "pytest-xdist",
@@ -76,9 +77,9 @@ profile = "black"
76
77
  line_length = 88
77
78
  multi_line_output = 3
78
79
  include_trailing_comma = true
79
- known_first_party = ["azure_functions_worker_v2"]
80
+ known_first_party = ["azure_functions_runtime"]
80
81
  default_section = "THIRDPARTY"
81
- src_paths = ["azure_functions_worker_v2"]
82
+ src_paths = ["azure_functions_runtime"]
82
83
  skip_glob = [
83
84
  "build",
84
85
  "dist",
@@ -99,4 +100,4 @@ skip_glob = [
99
100
  ]
100
101
 
101
102
  [tool.setuptools.dynamic]
102
- version = {attr = "azure_functions_worker_v2.version.VERSION"}
103
+ version = {attr = "azure_functions_runtime.version.VERSION"}
@@ -1,32 +0,0 @@
1
- README.md
2
- pyproject.toml
3
- azure_functions_runtime.egg-info/PKG-INFO
4
- azure_functions_runtime.egg-info/SOURCES.txt
5
- azure_functions_runtime.egg-info/dependency_links.txt
6
- azure_functions_runtime.egg-info/requires.txt
7
- azure_functions_runtime.egg-info/top_level.txt
8
- azure_functions_worker_v2/__init__.py
9
- azure_functions_worker_v2/functions.py
10
- azure_functions_worker_v2/handle_event.py
11
- azure_functions_worker_v2/http_v2.py
12
- azure_functions_worker_v2/loader.py
13
- azure_functions_worker_v2/logging.py
14
- azure_functions_worker_v2/otel.py
15
- azure_functions_worker_v2/version.py
16
- azure_functions_worker_v2/bindings/context.py
17
- azure_functions_worker_v2/bindings/datumdef.py
18
- azure_functions_worker_v2/bindings/generic.py
19
- azure_functions_worker_v2/bindings/meta.py
20
- azure_functions_worker_v2/bindings/nullable_converters.py
21
- azure_functions_worker_v2/bindings/out.py
22
- azure_functions_worker_v2/bindings/retrycontext.py
23
- azure_functions_worker_v2/bindings/tracecontext.py
24
- azure_functions_worker_v2/utils/__init__.py
25
- azure_functions_worker_v2/utils/app_setting_manager.py
26
- azure_functions_worker_v2/utils/constants.py
27
- azure_functions_worker_v2/utils/executor.py
28
- azure_functions_worker_v2/utils/helpers.py
29
- azure_functions_worker_v2/utils/tracing.py
30
- azure_functions_worker_v2/utils/typing_inspect.py
31
- azure_functions_worker_v2/utils/validators.py
32
- azure_functions_worker_v2/utils/wrappers.py
@@ -1,3 +0,0 @@
1
- azure_functions_worker_v2
2
- build
3
- dist