[Bug] An activity method with an annotated `self` receives its arguments without their types
メンテナーはふだん 1 日以内に返信
評価
この issue はまだ評価されていません。
説明
Package: temporalio 1.35.0, the latest release, and main (d488ff5).
What happens
An activity defined as a method, async def m(self, loc: Loc), receives loc as a Loc. The same method with an annotated receiver, such as self: Self in a module with from __future__ import annotations, receives loc as a plain dict.
_type_hints_from_func in temporalio/common.py skips the first parameter only when it is named self and is unannotated, or its annotation's text is typing.Self:
if (
index == 0
and value.name == "self"
and (
value.annotation is inspect.Parameter.empty
or str(value.annotation) == "typing.Self"
)
):
continue
Under postponed annotations the text is Self, so arg_types gets an entry for the receiver. The Worker then has two types for one argument, and worker/_activity.py falls back to decoding without types (arg_types is not None and len(arg_types) != len(start.input)). The same holds for self: T with a TypeVar bound to the class, self: "Svc", and typing_extensions.Self on Python 3.10. It affects workflow.execute_activity_method and anything else that runs a registered bound method.
Reproduction
One file. It uses a local dev server (temporal CLI on PATH) and exits 1 when the method annotated self: Self receives a dict.
"""An activity method whose `self` is annotated receives its other arguments without their types.
Exits 1 when the method annotated `self: Self` receives a dict instead of a `Loc`.
"""
from __future__ import annotations
import asyncio
import dataclasses
import shutil
import sys
import uuid
from datetime import timedelta
from typing import Self
from temporalio import activity, workflow
from temporalio.testing import WorkflowEnvironment
from temporalio.worker import UnsandboxedWorkflowRunner, Worker
@dataclasses.dataclass
class Loc:
city: str
class Svc:
@activity.defn
async def plain(self, loc: Loc) -> str:
return type(loc).__name__
@activity.defn
async def annotated(self: Self, loc: Loc) -> str:
return type(loc).__name__
@workflow.defn
class LocWorkflow:
@workflow.run
async def run(self) -> list[str]:
timeout = timedelta(seconds=10)
return [
await workflow.execute_activity_method(
Svc.plain, Loc("Rome"), start_to_close_timeout=timeout
),
await workflow.execute_activity_method(
Svc.annotated, Loc("Rome"), start_to_close_timeout=timeout
),
]
async def main() -> None:
svc = Svc()
async with await WorkflowEnvironment.start_local(
dev_server_existing_path=shutil.which("temporal")
) as env:
async with Worker(
env.client,
task_queue="tq",
workflows=[LocWorkflow],
activities=[svc.plain, svc.annotated],
workflow_runner=UnsandboxedWorkflowRunner(),
):
plain, annotated = await env.client.execute_workflow(
LocWorkflow.run, id=str(uuid.uuid4()), task_queue="tq"
)
print(f"plain(self, loc: Loc) received: {plain}")
print(f"annotated(self: Self, loc: Loc) received: {annotated}")
sys.exit(0 if annotated == "Loc" else 1)
if __name__ == "__main__":
asyncio.run(main())
Output:
Python 3.13.16 temporalio 1.35.0
$ python annotated_self.py
plain(self, loc: Loc) received: Loc
annotated(self: Self, loc: Loc) received: dict
exit 1
Expected
The Worker registers the method bound to an instance, which supplies self however it is annotated. So annotated should receive a Loc, as plain does.
Proposed fix
When the first parameter is named self, skip it whatever its annotation, as for an unannotated self.
Found while reviewing temporalio/ai-integrations#206, which builds agent tools from activity methods.
- 主要言語
- Python
- スター
- 1.2k
- フォーク
- 285
- 平均マージ
- 1日 23時間
- マージ済み PR(30日)
- 89
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
temporalio/sdk-python のほかの issue
-
難易度 4/5 3〜5日 初心者へのやさしさ 18/100
temporalio/sdk-python#2080 ·
メンテナーはふだん 1 日以内に返信
-
[Bug] Sandboxed datetime hints can fail decoding and drop signals対応中かも @VegetarianOrc が今日担当しました。 オープン
temporalio/sdk-python#2072 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
[Bug] TaskGroup cancellation of mixed Temporal operations can break replay対応中かも @VegetarianOrc が今日担当しました。 オープン
temporalio/sdk-python#2069 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
sdk-python
難易度 4/5 3〜5日 初心者へのやさしさ 22/100
temporalio/sdk-python#2067 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
[Bug] lambda_worker otel.apply_defaults leaks a span exporter thread and gRPC channel on every warm invocation対応中かも @avanish-garg が 5 日前に担当しました。 オープンbug sdk-python
難易度 4/5 1〜2日 初心者へのやさしさ 30/100
temporalio/sdk-python#2040 ·
メンテナーはふだん 1 日以内に返信
temporalio/sdk-python の issue をすべて見る
似ている issue
-
bug ready-for-dev
難易度 1/5 1〜3時間 初心者へのやさしさ 92/100
OpenHands/extensions#897 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
tensorflow/datasets#11253 ·
メンテナーはふだん 1 日以内に返信
-
fix(core): a config section with all keys commented out crashes startup対応中かも @Aryanbhargava18 が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
kubeflow/mcp-server#512 ·
メンテナーはふだん 1 日以内に返信
-
Stop trusting the compromised eMudhra CA certificates対応中かも @anth-volk が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
PolicyEngine/uk-triple-lock#54 ·
メンテナーはふだん 1 日以内に返信
-
DBFS append mode silently overwrites existing files対応中かも @IlyaKhalafi が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
fsspec/filesystem_spec#2429 ·
メンテナーはふだん 1 日以内に返信