@@ -78,7 +78,13 @@ def invoke() -> _Result:
7878 return await asyncio .get_running_loop ().run_in_executor (_executor (), copied_context .run , invoke )
7979
8080
81- def wrap_invocation (function : Callable [..., Any ], trigger_name : str ,
81+ def get_invocation_id () -> str | None :
82+ """Return the originating Functions invocation ID, if one is available."""
83+ context = _invocation_context .get ()
84+ return context .invocation_id if context is not None else None
85+
86+
87+ def wrap_invocation (function : Callable [..., Any ], trigger_name : str | None = None ,
8288 * , registered_trigger_name : str | None = None ) -> Callable [..., Any ]:
8389 signature = inspect .signature (function )
8490 registered_name = registered_trigger_name or trigger_name
@@ -87,7 +93,8 @@ def wrap_invocation(function: Callable[..., Any], trigger_name: str,
8793 while registered_name in signature .parameters :
8894 registered_name = "_" + registered_name
8995 parameters = [
90- parameter .replace (name = registered_name ) if parameter .name == trigger_name else parameter
96+ parameter .replace (name = registered_name )
97+ if parameter .name == trigger_name and registered_name is not None else parameter
9198 for parameter in signature .parameters .values ()
9299 ]
93100 inject_context = "context" not in signature .parameters or trigger_name == "context"
@@ -99,27 +106,54 @@ def wrap_invocation(function: Callable[..., Any], trigger_name: str,
99106 parameters .insert (insertion , context_parameter )
100107 host_signature = signature .replace (parameters = parameters )
101108
102- @ wraps ( function )
103- async def wrapper ( * args : Any , ** kwargs : Any ) -> Any :
109+ def bind_invocation (
110+ args : tuple [ Any , ...], kwargs : dict [ str , Any ] ) -> tuple [ inspect . BoundArguments , func . Context | None ] :
104111 bound = host_signature .bind (* args , ** kwargs )
105- context = bound .arguments .get ("context" )
112+ context : func .Context | None = bound .arguments .get ("context" )
113+ # A binding may also be named context. Worker contexts implement the
114+ # runtime contract without inheriting from azure.functions.Context.
115+ if not isinstance (getattr (context , "invocation_id" , None ), str ) \
116+ or not hasattr (context , "thread_local_storage" ):
117+ context = None
106118 if inject_context :
107119 bound .arguments .pop ("context" , None )
108- if registered_name != trigger_name :
120+ if registered_name is not None and trigger_name is not None and registered_name != trigger_name :
109121 bound .arguments [trigger_name ] = bound .arguments .pop (registered_name )
110- token = _invocation_context .set (context )
111- try :
112- original = inspect .BoundArguments (signature , bound .arguments )
113- return await function (* original .args , ** original .kwargs )
114- finally :
115- _invocation_context .reset (token )
122+ return inspect .BoundArguments (signature , bound .arguments ), context
123+
124+ wrapper : Callable [..., Any ]
125+ if inspect .iscoroutinefunction (function ):
126+ @wraps (function )
127+ async def async_wrapper (* args : Any , ** kwargs : Any ) -> Any :
128+ original , context = bind_invocation (args , kwargs )
129+ token = _invocation_context .set (context )
130+ try :
131+ return await function (* original .args , ** original .kwargs )
132+ finally :
133+ _invocation_context .reset (token )
134+
135+ wrapper = async_wrapper
136+ else :
137+ @wraps (function )
138+ def sync_wrapper (* args : Any , ** kwargs : Any ) -> Any :
139+ original , context = bind_invocation (args , kwargs )
140+ token = _invocation_context .set (context )
141+ try :
142+ return function (* original .args , ** original .kwargs )
143+ finally :
144+ _invocation_context .reset (token )
145+
146+ wrapper = sync_wrapper
116147
117148 annotations = dict (function .__annotations__ )
118- if registered_name != trigger_name and trigger_name in annotations :
149+ if registered_name is not None and trigger_name is not None and registered_name != trigger_name \
150+ and trigger_name in annotations :
119151 annotations [registered_name ] = annotations .pop (trigger_name )
120152 if inject_context :
121153 annotations ["context" ] = func .Context
122154 wrapper .__annotations__ = annotations
123155 setattr (wrapper , "__signature__" , host_signature )
124- setattr (wrapper , "_df_trigger_name" , registered_name )
156+ if registered_name is not None :
157+ setattr (wrapper , "_df_trigger_name" , registered_name )
158+ preserve_function_source (wrapper , function )
125159 return wrapper
0 commit comments