Skip to content

Commit eea3c46

Browse files
committed
Pyright fixes
1 parent 483c4aa commit eea3c46

4 files changed

Lines changed: 28 additions & 15 deletions

File tree

azure-functions-durable/azure/durable_functions/decorators/durable_app.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ def _register_builtin_http_functions(self) -> None:
6565
activity=BUILTIN_HTTP_ACTIVITY_NAME)(builtin_http_activity)
6666
self.orchestration_trigger(
6767
context_name="context",
68-
orchestration=BUILTIN_HTTP_POLL_ORCHESTRATOR_NAME)(builtin_http_poll_orchestrator)
68+
orchestration=BUILTIN_HTTP_POLL_ORCHESTRATOR_NAME)(
69+
builtin_http_poll_orchestrator) # pyright: ignore[reportArgumentType]
6970

7071
def configure_scheduled_tasks(self) -> None:
7172
"""Opt in to durabletask scheduled tasks by registering their built-ins.
@@ -138,14 +139,19 @@ def configure_history_export(self) -> None:
138139
context_name="context", entity_name=EXPORT_ENTITY_NAME)(ExportJobEntity)
139140
self.orchestration_trigger(context_name="context")(export_job_orchestrator)
140141

141-
def _list_terminal_instances(input: dict) -> dict:
142+
def _list_terminal_instances(input: dict[str, Any]) -> dict[str, Any]:
142143
return list_terminal_instances(None, input) # type: ignore[arg-type]
143144

144-
def _export_instance_history(input: dict) -> dict:
145+
def _export_instance_history(input: dict[str, Any]) -> dict[str, Any]:
145146
return export_instance_history(None, input) # type: ignore[arg-type]
146147

147148
_list_terminal_instances.__name__ = LIST_TERMINAL_INSTANCES_ACTIVITY
148149
_export_instance_history.__name__ = EXPORT_INSTANCE_HISTORY_ACTIVITY
150+
# The worker reads the runtime ``__annotations__`` during indexing and
151+
# rejects parameterized generics, so reset them to the bare ``dict`` it
152+
# accepts (the signatures above stay typed for static analysis).
153+
_list_terminal_instances.__annotations__ = {"input": dict, "return": dict}
154+
_export_instance_history.__annotations__ = {"input": dict, "return": dict}
149155
self.activity_trigger(
150156
input_name="input",
151157
activity=LIST_TERMINAL_INSTANCES_ACTIVITY)(_list_terminal_instances)

azure-functions-durable/azure/durable_functions/http/builtin.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def _acquire_bearer_token(resource: str) -> str:
5959
return credential.get_token(scope).token
6060

6161

62-
def builtin_http_activity(input: dict) -> dict:
62+
def builtin_http_activity(input: dict[str, Any]) -> dict[str, Any]:
6363
"""Execute a single HTTP request and return the response payload.
6464
6565
``input`` is the JSON form of a
@@ -68,14 +68,14 @@ def builtin_http_activity(input: dict) -> dict:
6868
return value is the JSON form of a
6969
:class:`~azure.durable_functions.http.models.DurableHttpResponse`.
7070
71-
The parameter and return are annotated with the plain ``dict`` type on
72-
purpose. The Azure Functions Python worker inspects trigger annotations
73-
during indexing and requires them to be a real ``type`` (it rejects
71+
The parameter and return are declared as ``dict[str, Any]`` for static type
72+
checking, but the *runtime* annotations are reset to the bare ``dict`` type
73+
just below the function. The Azure Functions Python worker inspects trigger
74+
annotations during indexing and requires a real ``type`` -- it rejects
7475
parameterized generics such as ``dict[str, Any]`` with
7576
``FunctionLoadError: ... invalid non-type annotation`` and, for a
7677
``typing.Union`` origin like ``Optional[...]``, raises
77-
``TypeError: issubclass() arg 1 must be a class``). A bare ``dict`` keeps
78-
worker indexing happy while the body still defends against ``None`` below.
78+
``TypeError: issubclass() arg 1 must be a class``.
7979
"""
8080
request = input or {}
8181
method = str(request.get("method", "GET")).upper()
@@ -113,6 +113,13 @@ def builtin_http_activity(input: dict) -> dict:
113113
status_code=status, headers=resp_headers, content=body).to_json()
114114

115115

116+
# The Azure Functions worker reads a trigger function's runtime ``__annotations__``
117+
# during indexing and rejects parameterized generics (it requires a bare
118+
# ``dict``). The signature above is typed ``dict[str, Any]`` for static analysis;
119+
# reset the runtime annotations to the bare ``dict`` the worker accepts.
120+
builtin_http_activity.__annotations__ = {"input": dict, "return": dict}
121+
122+
116123
def _get_header(headers: dict[str, str], name: str) -> Optional[str]:
117124
"""Case-insensitively look up ``name`` in ``headers``."""
118125
lowered = name.lower()
@@ -135,11 +142,9 @@ def _retry_after_seconds(headers: dict[str, str]) -> int:
135142
if raw.isdigit():
136143
return max(int(raw), 0)
137144
try:
138-
retry_at = parsedate_to_datetime(raw)
145+
parsedate_to_datetime(raw)
139146
except (TypeError, ValueError):
140147
return _DEFAULT_POLL_INTERVAL_SECONDS
141-
if retry_at is None:
142-
return _DEFAULT_POLL_INTERVAL_SECONDS
143148
return _DEFAULT_POLL_INTERVAL_SECONDS
144149

145150

@@ -156,7 +161,7 @@ def builtin_http_poll_orchestrator(context: Any) -> Generator[Any, Any, dict[str
156161
BUILTIN_HTTP_ACTIVITY_NAME, request)
157162

158163
while response.get("status_code") == 202:
159-
headers = response.get("headers") or {}
164+
headers: dict[str, str] = response.get("headers") or {}
160165
location = _get_header(headers, "Location")
161166
if not location:
162167
# Cannot poll without a Location; return the 202 as-is.

azure-functions-durable/azure/durable_functions/internal/compat/durable_orchestration_status.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@ def output(self) -> Any:
114114
@property
115115
def runtime_status(self) -> Optional[OrchestrationRuntimeStatus]:
116116
"""Get the runtime status as a v1 ``OrchestrationRuntimeStatus``."""
117-
if self._state is None or self._state.runtime_status is None:
117+
# ``OrchestrationState.runtime_status`` is typed ``OrchestrationStatus``
118+
# but is built via ``cast`` from a value that can be ``None`` at runtime
119+
if self._state is None or self._state.runtime_status is None: # pyright: ignore[reportUnnecessaryComparison]
118120
return None
119121
return from_durabletask_status(self._state.runtime_status)
120122

azure-functions-durable/azure/durable_functions/internal/history_export_compat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from durabletask.internal.helpers import ensure_aware
2929

3030
from durabletask.extensions.history_export._internal import dt_from_iso
31-
from durabletask.extensions.history_export.activities import _require_context
31+
from durabletask.extensions.history_export.activities import _require_context # pyright: ignore[reportPrivateUsage]
3232

3333
# The activity registers under the same name the export orchestrator calls, so
3434
# it transparently replaces the core activity.

0 commit comments

Comments
 (0)