From 483cad0c31a1e7933a763976d93cdbaa92fee5db Mon Sep 17 00:00:00 2001 From: Andy Staples Date: Wed, 29 Jul 2026 14:21:20 -0600 Subject: [PATCH 1/2] Mark azure-functions-durable as typed Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3775188c-77e9-48a2-9c79-76e7bfdc25f9 --- azure-functions-durable/CHANGELOG.md | 2 + .../azure/durable_functions/py.typed | 0 azure-functions-durable/pyproject.toml | 3 ++ noxfile.py | 48 +++++++++++++++++-- .../typing/import_package.py | 8 ++++ .../typing/pyrightconfig.json | 7 +++ 6 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 azure-functions-durable/azure/durable_functions/py.typed create mode 100644 tests/azure-functions-durable/typing/import_package.py create mode 100644 tests/azure-functions-durable/typing/pyrightconfig.json diff --git a/azure-functions-durable/CHANGELOG.md b/azure-functions-durable/CHANGELOG.md index e9c022e6..fea8d4dc 100644 --- a/azure-functions-durable/CHANGELOG.md +++ b/azure-functions-durable/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ADDED +- Added PEP 561 type information so strict type checkers recognize +`azure.durable_functions` as a typed package. - Added `azure.durable_functions.testing.execute_entity()` for unit testing function-style and class-based entities without a Functions host or Durable Task backend. The helper returns the operation result, resulting state, and typed diff --git a/azure-functions-durable/azure/durable_functions/py.typed b/azure-functions-durable/azure/durable_functions/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/azure-functions-durable/pyproject.toml b/azure-functions-durable/pyproject.toml index fb675b4c..62698a04 100644 --- a/azure-functions-durable/pyproject.toml +++ b/azure-functions-durable/pyproject.toml @@ -39,5 +39,8 @@ changelog = "https://github.com/microsoft/durabletask-python/blob/main/azure-fun [tool.setuptools.packages.find] include = ["azure.durable_functions", "azure.durable_functions.*"] +[tool.setuptools.package-data] +"azure.durable_functions" = ["py.typed"] + [tool.pytest.ini_options] minversion = "6.0" diff --git a/noxfile.py b/noxfile.py index 075c71cc..0b40212d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -27,8 +27,10 @@ import shutil import socket import subprocess +import tarfile import time import uuid +import zipfile from pathlib import Path from typing import Sequence @@ -311,16 +313,56 @@ def typecheck_core(session: nox.Session) -> None: @nox.session(python=["3.13"]) def typecheck_functions(session: nox.Session) -> None: - """Run strict pyright checks for azure-functions-durable.""" + """Run strict pyright checks for azure-functions-durable and its wheel.""" session.install("-r", "requirements.txt") - _install_packages(session, editable=True) - session.install("pyright") + session.install("-e", str(REPO_ROOT)) + session.install("build", "pyright") + artifact_dir = Path(session.create_tmp()) / "dist" + if artifact_dir.exists(): + shutil.rmtree(artifact_dir) + session.run( + "python", + "-m", + "build", + "--outdir", + str(artifact_dir), + str(AZURE_FUNCTIONS_DURABLE), + ) + + wheels = list(artifact_dir.glob("azure_functions_durable-*.whl")) + sdists = list(artifact_dir.glob("azure_functions_durable-*.tar.gz")) + if len(wheels) != 1 or len(sdists) != 1: + session.error("Expected exactly one wheel and one source distribution") + wheel = wheels[0] + sdist = sdists[0] + marker = "azure/durable_functions/py.typed" + with zipfile.ZipFile(wheel) as archive: + if marker not in archive.namelist(): + session.error(f"{marker} is missing from {wheel.name}") + with tarfile.open(sdist, "r:gz") as archive: + if not any(name.endswith(f"/{marker}") for name in archive.getnames()): + session.error(f"{marker} is missing from {sdist.name}") + + session.install(str(wheel)) session.run( "pyright", "-p", "azure-functions-durable/pyrightconfig.json", *session.posargs, ) + python_path = session.run( + "python", + "-c", + "import sys; print(sys.executable)", + silent=True, + ).strip() + session.run( + "pyright", + "--pythonpath", + python_path, + "-p", + "tests/azure-functions-durable/typing/pyrightconfig.json", + ) @nox.session(python=PYTHON_VERSIONS) diff --git a/tests/azure-functions-durable/typing/import_package.py b/tests/azure-functions-durable/typing/import_package.py new file mode 100644 index 00000000..3beb1350 --- /dev/null +++ b/tests/azure-functions-durable/typing/import_package.py @@ -0,0 +1,8 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +import azure.durable_functions as df + + +def create_app() -> df.DFApp: + return df.DFApp() diff --git a/tests/azure-functions-durable/typing/pyrightconfig.json b/tests/azure-functions-durable/typing/pyrightconfig.json new file mode 100644 index 00000000..68700dda --- /dev/null +++ b/tests/azure-functions-durable/typing/pyrightconfig.json @@ -0,0 +1,7 @@ +{ + "include": [ + "import_package.py" + ], + "pythonVersion": "3.13", + "typeCheckingMode": "strict" +} From a87cd287d9b1ec4db183e622654487a8ef33ea16 Mon Sep 17 00:00:00 2001 From: Andy Staples Date: Wed, 29 Jul 2026 14:27:21 -0600 Subject: [PATCH 2/2] Force reinstall packaged typing artifact Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3775188c-77e9-48a2-9c79-76e7bfdc25f9 --- noxfile.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/noxfile.py b/noxfile.py index 0b40212d..29ce7de9 100644 --- a/noxfile.py +++ b/noxfile.py @@ -344,6 +344,15 @@ def typecheck_functions(session: nox.Session) -> None: session.error(f"{marker} is missing from {sdist.name}") session.install(str(wheel)) + session.run( + "python", + "-m", + "pip", + "install", + "--force-reinstall", + "--no-deps", + str(wheel), + ) session.run( "pyright", "-p",