Skip to content

Commit 2ea9183

Browse files
authored
Merge branch 'dev' into mysql-trigger
2 parents 7652a86 + d2e5d9f commit 2ea9183

File tree

8 files changed

+66
-31
lines changed

8 files changed

+66
-31
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/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,4 @@
102102
'BlobSource'
103103
)
104104

105-
__version__ = '1.24.0b4'
105+
__version__ = '1.25.0b1'

azure/functions/durable_functions.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,10 @@ def decode(cls,
9999
except json.JSONDecodeError:
100100
# String failover if the content is not json serializable
101101
result = data.value
102-
except Exception:
102+
except Exception as e:
103103
raise ValueError(
104104
'activity trigger input must be a string or a '
105-
f'valid json serializable ({data.value})')
105+
f'valid json serializable ({data.value})') from e
106106
else:
107107
raise NotImplementedError(
108108
f'unsupported activity trigger payload type: {data_type}')
@@ -115,9 +115,9 @@ def encode(cls, obj: typing.Any, *,
115115
try:
116116
callback = _durable_functions._serialize_custom_object
117117
result = json.dumps(obj, default=callback)
118-
except TypeError:
118+
except TypeError as e:
119119
raise ValueError(
120-
f'activity trigger output must be json serializable ({obj})')
120+
f'activity trigger output must be json serializable ({obj})') from e
121121

122122
return meta.Datum(type='json', value=result)
123123

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/test_durable_functions.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,19 @@ def test_activity_trigger_encode(self):
165165
expected_type=type(datum['output']))
166166
self.assertEqual(encoded, datum['expected_value'])
167167

168+
def test_activity_trigger_encode_failure_exception_has_cause(self):
169+
class NonEncodable:
170+
def __init__(self):
171+
self.value = 'foo'
172+
173+
data = NonEncodable()
174+
175+
try:
176+
ActivityTriggerConverter.encode(data, expected_type=None)
177+
except ValueError as e:
178+
self.assertIsNotNone(e.__cause__)
179+
self.assertIsInstance(e.__cause__, TypeError)
180+
168181
def test_activity_trigger_decode(self):
169182
# Activity Trigger allow inputs to be any JSON serializables
170183
# The input values to the trigger should be passed into arguments
@@ -209,6 +222,17 @@ def test_activity_trigger_decode(self):
209222
trigger_metadata=None)
210223
self.assertEqual(decoded, datum['expected_value'])
211224

225+
def test_activity_trigger_decode_failure_exception_has_cause(self):
226+
data = Datum('{"value": "bar"}', 'json')
227+
228+
try:
229+
ActivityTriggerConverter.decode(
230+
data=data,
231+
trigger_metadata=None)
232+
except ValueError as e:
233+
self.assertIsNotNone(e.__cause__)
234+
self.assertIsInstance(e.__cause__, TypeError)
235+
212236
def test_activity_trigger_has_implicit_return(self):
213237
self.assertTrue(
214238
ActivityTriggerConverter.has_implicit_output()

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)