diff --git a/.azuredevops/dependabot.yml b/.azuredevops/dependabot.yml new file mode 100644 index 00000000..d7cbef7f --- /dev/null +++ b/.azuredevops/dependabot.yml @@ -0,0 +1,4 @@ +# Mirrored repository. We use dependabot via GitHub, not Azure DevOps. +version: 2 +enable-security-updates: false +enable-campaigned-updates: false diff --git a/README.md b/README.md index e5b9c07e..efc6c3f4 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,15 @@ ## Overview -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. +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. Here is the current status of Python in Azure Functions: _What are the supported Python versions?_ -| Azure Functions Runtime | Python 3.8 | Python 3.9 | Python 3.10 | Python 3.11 | Python 3.12 | -|-------------------------|--------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|-------------|-------------|-------------| -| 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) | - | - | - | -| Azure Functions 4.0 | ✓ | ✓ | ✓ | ✓ | ✓ | +| Azure Functions Runtime | Python 3.10 | Python 3.11 | Python 3.12 | Python 3.13 | +|----------------------------------|------------|------------|-------------|-------------| +| Azure Functions 4.0 | ✔ | ✔ | ✔ | ✔ | | ✓ | ✓ | ✓ | _What's available?_ - Build, test, debug and publish using Azure Functions Core Tools (CLI) or Visual Studio Code diff --git a/eng/templates/jobs/build.yml b/eng/templates/jobs/build.yml index ea222c87..c4b7d0b1 100644 --- a/eng/templates/jobs/build.yml +++ b/eng/templates/jobs/build.yml @@ -18,6 +18,8 @@ jobs: PYTHON_VERSION: '3.12' Python313: PYTHON_VERSION: '3.13' + Python314: + PYTHON_VERSION: '3.14' steps: - task: UsePythonVersion@0 diff --git a/eng/templates/jobs/ci-tests.yml b/eng/templates/jobs/ci-tests.yml index f36f8e7b..9f1ddedb 100644 --- a/eng/templates/jobs/ci-tests.yml +++ b/eng/templates/jobs/ci-tests.yml @@ -18,6 +18,8 @@ jobs: PYTHON_VERSION: '3.12' python-313: PYTHON_VERSION: '3.13' + python-314: + PYTHON_VERSION: '3.14' steps: - task: UsePythonVersion@0 diff --git a/tests/test_http_asgi.py b/tests/test_http_asgi.py index 465f7600..b4b27f1a 100644 --- a/tests/test_http_asgi.py +++ b/tests/test_http_asgi.py @@ -265,9 +265,11 @@ async def main(req, context): app.response_code = 200 req = self._generate_func_request() ctx = self._generate_func_context() - response = asyncio.get_event_loop().run_until_complete( - AsgiMiddleware(app).handle_async(req, ctx) - ) + + async def run_test(): + return await AsgiMiddleware(app).handle_async(req, ctx) + + response = asyncio.run(run_test()) # Verify asserted self.assertEqual(response.status_code, 200) @@ -276,15 +278,15 @@ async def main(req, context): def test_function_app_lifecycle_events(self): mock_app = MockAsgiApplication() middleware = AsgiMiddleware(mock_app) - asyncio.get_event_loop().run_until_complete( - middleware.notify_startup() - ) - assert mock_app.startup_called - asyncio.get_event_loop().run_until_complete( - middleware.notify_shutdown() - ) - assert mock_app.shutdown_called + async def run_test(): + await middleware.notify_startup() + assert mock_app.startup_called + + await middleware.notify_shutdown() + assert mock_app.shutdown_called + + asyncio.run(run_test()) def test_function_app_lifecycle_events_with_failures(self): apps = [ @@ -295,22 +297,24 @@ def test_function_app_lifecycle_events_with_failures(self): MockAsgiApplication(False, "bork"), MockAsgiApplication("bork", "bork"), ] - for mock_app in apps: + + async def run_test(mock_app): middleware = AsgiMiddleware(mock_app) - asyncio.get_event_loop().run_until_complete( - middleware.notify_startup() - ) + await middleware.notify_startup() assert mock_app.startup_called - asyncio.get_event_loop().run_until_complete( - middleware.notify_shutdown() - ) + await middleware.notify_shutdown() assert mock_app.shutdown_called + for mock_app in apps: + asyncio.run(run_test(mock_app)) + def test_calling_shutdown_without_startup_errors(self): mock_app = MockAsgiApplication() middleware = AsgiMiddleware(mock_app) + + async def run_test(): + await middleware.notify_shutdown() + with pytest.raises(RuntimeError): - asyncio.get_event_loop().run_until_complete( - middleware.notify_shutdown() - ) + asyncio.run(run_test())