Skip to content

Commit 6210130

Browse files
committed
Merge branch 'dev' of https://github.com/Azure/azure-functions-python-library into hallvictoria/simplified-mcp-decorator
2 parents 857ff63 + 6de1aa0 commit 6210130

File tree

8 files changed

+102
-26
lines changed

8 files changed

+102
-26
lines changed

.azuredevops/dependabot.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Mirrored repository. We use dependabot via GitHub, not Azure DevOps.
2+
version: 2
3+
enable-security-updates: false
4+
enable-campaigned-updates: false

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,15 @@
77

88
## Overview
99

10-
Python support for Azure Functions is based on Python 3.8, 3.9, 3.10, 3.11, and 3.12 serverless hosting on Linux, and the Functions 2.x ([EOL](https://learn.microsoft.com/azure/azure-functions/functions-versions?#retired-versions)), 3.x ([EOL](https://learn.microsoft.com/azure/azure-functions/functions-versions?#retired-versions)) and 4.0 runtime.
10+
Python support for Azure Functions is based on Python 3.10, 3.11, 3.12, and 3.13 serverless hosting on Linux, and the Functions 2.x ([EOL](https://learn.microsoft.com/azure/azure-functions/functions-versions?#retired-versions)), 3.x ([EOL](https://learn.microsoft.com/azure/azure-functions/functions-versions?#retired-versions)) and 4.0 runtime.
1111

1212
Here is the current status of Python in Azure Functions:
1313

1414
_What are the supported Python versions?_
1515

16-
| Azure Functions Runtime | Python 3.8 | Python 3.9 | Python 3.10 | Python 3.11 | Python 3.12 |
17-
|-------------------------|--------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|-------------|-------------|-------------|
18-
| Azure Functions 3.0 | [EOL](https://learn.microsoft.com/azure/azure-functions/migrate-version-3-version-4) | [EOL](https://learn.microsoft.com/azure/azure-functions/migrate-version-3-version-4) | - | - | - |
19-
| Azure Functions 4.0 | ✓ | ✓ | ✓ | ✓ | ✓ |
16+
| Azure Functions Runtime | Python 3.10 | Python 3.11 | Python 3.12 | Python 3.13 |
17+
|----------------------------------|------------|------------|-------------|-------------|
18+
| Azure Functions 4.0 ||||| | ✓ | ✓ | ✓ |
2019

2120
_What's available?_
2221
- Build, test, debug and publish using Azure Functions Core Tools (CLI) or Visual Studio Code

azure/functions/decorators/function_app.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ def service_bus_queue_trigger(
676676
access_rights: Optional[Union[AccessRights, str]] = None,
677677
is_sessions_enabled: Optional[bool] = None,
678678
cardinality: Optional[Union[Cardinality, str]] = None,
679+
auto_complete_messages: Optional[bool] = None,
679680
**kwargs: Any) -> Callable[..., Any]:
680681
"""
681682
The `on_service_bus_queue_change` decorator adds :class:`ServiceBusQueueTrigger` to the
@@ -700,6 +701,8 @@ def service_bus_queue_trigger(
700701
:param is_sessions_enabled: Set to True if connecting to a session-aware queue
701702
or subscription.
702703
:param cardinality: Set to "many" to enable batching.
704+
:param auto_complete_messages: Indicates whether the message should be automatically
705+
completed.
703706
704707
:return: Decorator function.
705708
"""
@@ -720,6 +723,7 @@ def decorator():
720723
is_sessions_enabled=is_sessions_enabled,
721724
cardinality=parse_singular_param_to_enum(cardinality,
722725
Cardinality),
726+
auto_complete_messages=auto_complete_messages,
723727
**kwargs))
724728
return fb
725729

@@ -737,6 +741,7 @@ def service_bus_topic_trigger(
737741
access_rights: Optional[Union[AccessRights, str]] = None,
738742
is_sessions_enabled: Optional[bool] = None,
739743
cardinality: Optional[Union[Cardinality, str]] = None,
744+
auto_complete_messages: Optional[bool] = None,
740745
**kwargs: Any) -> Callable[..., Any]:
741746
"""
742747
The `on_service_bus_topic_change` decorator adds :class:`ServiceBusTopicTrigger` to the
@@ -762,6 +767,8 @@ def service_bus_topic_trigger(
762767
:param is_sessions_enabled: Set to True if connecting to a session-aware queue
763768
or subscription.
764769
:param cardinality: Set to "many" to enable batching.
770+
:param auto_complete_messages: Indicates whether the message should be automatically
771+
completed.
765772
766773
:return: Decorator function.
767774
"""
@@ -783,6 +790,7 @@ def decorator():
783790
is_sessions_enabled=is_sessions_enabled,
784791
cardinality=parse_singular_param_to_enum(cardinality,
785792
Cardinality),
793+
auto_complete_messages=auto_complete_messages,
786794
**kwargs))
787795
return fb
788796

azure/functions/mysql.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,8 @@ def encode(cls, obj: typing.Any, *,
7676
type='json',
7777
value=json.dumps([dict(d) for d in data])
7878
)
79+
80+
81+
class MySqlTriggerConverter(MySqlConverter,
82+
binding='mysqlTrigger', trigger=True):
83+
pass

eng/templates/jobs/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ jobs:
1818
PYTHON_VERSION: '3.12'
1919
Python313:
2020
PYTHON_VERSION: '3.13'
21+
Python314:
22+
PYTHON_VERSION: '3.14'
2123

2224
steps:
2325
- task: UsePythonVersion@0

eng/templates/jobs/ci-tests.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ jobs:
1818
PYTHON_VERSION: '3.12'
1919
python-313:
2020
PYTHON_VERSION: '3.13'
21+
python-314:
22+
PYTHON_VERSION: '3.14'
2123

2224
steps:
2325
- task: UsePythonVersion@0

tests/decorators/test_servicebus.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,31 @@ def test_service_bus_queue_trigger_valid_creation(self):
3535
"cardinality": Cardinality.ONE
3636
})
3737

38+
def test_service_bus_queue_trigger_autocomplete_valid_creation(self):
39+
trigger = ServiceBusQueueTrigger(name="req", connection="dummy_conn",
40+
queue_name="dummy_queue",
41+
data_type=DataType.UNDEFINED,
42+
access_rights=AccessRights.MANAGE,
43+
is_sessions_enabled=True,
44+
cardinality=Cardinality.ONE,
45+
auto_complete_messages=True,
46+
dummy_field="dummy")
47+
48+
self.assertEqual(trigger.get_binding_name(), "serviceBusTrigger")
49+
self.assertEqual(trigger.get_dict_repr(), {
50+
"type": SERVICE_BUS_TRIGGER,
51+
"direction": BindingDirection.IN,
52+
'dummyField': 'dummy',
53+
"name": "req",
54+
"connection": "dummy_conn",
55+
"queueName": "dummy_queue",
56+
"dataType": DataType.UNDEFINED,
57+
"accessRights": AccessRights.MANAGE,
58+
"isSessionsEnabled": True,
59+
"cardinality": Cardinality.ONE,
60+
"autoCompleteMessages": True
61+
})
62+
3863
def test_service_bus_queue_output_valid_creation(self):
3964
service_bus_queue_output = ServiceBusQueueOutput(
4065
name="res",
@@ -82,6 +107,33 @@ def test_service_bus_topic_trigger_valid_creation(self):
82107
"cardinality": Cardinality.ONE
83108
})
84109

110+
def test_service_bus_topic_trigger_autocomplete_valid_creation(self):
111+
trigger = ServiceBusTopicTrigger(name="req", connection="dummy_conn",
112+
topic_name="dummy_topic",
113+
subscription_name="dummy_sub",
114+
data_type=DataType.UNDEFINED,
115+
access_rights=AccessRights.MANAGE,
116+
is_sessions_enabled=True,
117+
cardinality=Cardinality.ONE,
118+
auto_complete_messages=True,
119+
dummy_field="dummy")
120+
121+
self.assertEqual(trigger.get_binding_name(), "serviceBusTrigger")
122+
self.assertEqual(trigger.get_dict_repr(), {
123+
"type": SERVICE_BUS_TRIGGER,
124+
"direction": BindingDirection.IN,
125+
'dummyField': 'dummy',
126+
"name": "req",
127+
"connection": "dummy_conn",
128+
"topicName": "dummy_topic",
129+
"subscriptionName": "dummy_sub",
130+
"dataType": DataType.UNDEFINED,
131+
"accessRights": AccessRights.MANAGE,
132+
"isSessionsEnabled": True,
133+
"cardinality": Cardinality.ONE,
134+
"autoCompleteMessages": True
135+
})
136+
85137
def test_service_bus_topic_output_valid_creation(self):
86138
output = ServiceBusTopicOutput(name="res", connection="dummy_conn",
87139
topic_name="dummy_topic",

tests/test_http_asgi.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -265,9 +265,11 @@ async def main(req, context):
265265
app.response_code = 200
266266
req = self._generate_func_request()
267267
ctx = self._generate_func_context()
268-
response = asyncio.get_event_loop().run_until_complete(
269-
AsgiMiddleware(app).handle_async(req, ctx)
270-
)
268+
269+
async def run_test():
270+
return await AsgiMiddleware(app).handle_async(req, ctx)
271+
272+
response = asyncio.run(run_test())
271273

272274
# Verify asserted
273275
self.assertEqual(response.status_code, 200)
@@ -276,15 +278,15 @@ async def main(req, context):
276278
def test_function_app_lifecycle_events(self):
277279
mock_app = MockAsgiApplication()
278280
middleware = AsgiMiddleware(mock_app)
279-
asyncio.get_event_loop().run_until_complete(
280-
middleware.notify_startup()
281-
)
282-
assert mock_app.startup_called
283281

284-
asyncio.get_event_loop().run_until_complete(
285-
middleware.notify_shutdown()
286-
)
287-
assert mock_app.shutdown_called
282+
async def run_test():
283+
await middleware.notify_startup()
284+
assert mock_app.startup_called
285+
286+
await middleware.notify_shutdown()
287+
assert mock_app.shutdown_called
288+
289+
asyncio.run(run_test())
288290

289291
def test_function_app_lifecycle_events_with_failures(self):
290292
apps = [
@@ -295,22 +297,24 @@ def test_function_app_lifecycle_events_with_failures(self):
295297
MockAsgiApplication(False, "bork"),
296298
MockAsgiApplication("bork", "bork"),
297299
]
298-
for mock_app in apps:
300+
301+
async def run_test(mock_app):
299302
middleware = AsgiMiddleware(mock_app)
300-
asyncio.get_event_loop().run_until_complete(
301-
middleware.notify_startup()
302-
)
303+
await middleware.notify_startup()
303304
assert mock_app.startup_called
304305

305-
asyncio.get_event_loop().run_until_complete(
306-
middleware.notify_shutdown()
307-
)
306+
await middleware.notify_shutdown()
308307
assert mock_app.shutdown_called
309308

309+
for mock_app in apps:
310+
asyncio.run(run_test(mock_app))
311+
310312
def test_calling_shutdown_without_startup_errors(self):
311313
mock_app = MockAsgiApplication()
312314
middleware = AsgiMiddleware(mock_app)
315+
316+
async def run_test():
317+
await middleware.notify_shutdown()
318+
313319
with pytest.raises(RuntimeError):
314-
asyncio.get_event_loop().run_until_complete(
315-
middleware.notify_shutdown()
316-
)
320+
asyncio.run(run_test())

0 commit comments

Comments
 (0)