[Feature Request] Suggest Providing activities extraction utilities to get them from a class and a module
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 35/100
- issue の種類
- 機能追加
- 明瞭さ
- おおむね明確
- 活発さ
- 停滞
- 技術スタック
- python
調査の方向性
まず activity.defn の実装と activity.py モジュールを読み、特にアクティビティ定義がどのように格納されているかを確認してください。クラス、インスタンス、モジュールの抽出について要求されているケースと、提供されているテストを確認してください。これらのケースをカバーする、ドキュメント化されたユーティリティ API があれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Is your feature request related to a problem? Please describe.
Creating activities and decorating them is easy using activy.def in python
Making sure that they are all included in worker launch is more difficult.
Describe the solution you'd like
It would be helpful if a utility was provided that allowed
- extracting activities from a class
- extracting activities from a class instance
- extracting activities from a module
Below is a sample implementation for extraction from class and class instances, assuming async method implementations that uses ast and inspection.
It looks like one could find which methods are decorate by checking if fn.__temporal_activity_definition but that is a private variable name and is not exposed in the temporalio activity.py module. Code that uses __temporal_activity_definition would be simpler and not invoking ast.parse(inspect.getsource(cls)) is preferrable.
import ast
import inspect
import typing
class _MyNodeVisitor(ast.NodeVisitor):
def __init__(self):
self.fn_name_to_decorators: dict[str, set[str]] = {}
def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef):
self.fn_name_to_decorators[node.name] = set()
for decorator in node.decorator_list:
print(decorator)
if isinstance(decorator, ast.Call):
# noinspection PyUnresolvedReferences
name = (
decorator.func.attr
if isinstance(decorator.func, ast.Attribute)
else decorator.func.id
)
else:
# noinspection PyUnresolvedReferences
name = (
decorator.value.id + "." + decorator.attr
if isinstance(decorator, ast.Attribute)
else decorator.id
)
self.fn_name_to_decorators[node.name].add(name)
def get_fn_name_to_decorators(self) -> dict[str, set[str]]:
return self.fn_name_to_decorators
class ActivitiesListProvider:
@classmethod
def __get_activities(
cls,
instance: typing.Union[
type["ActivitiesListProvider"], "ActivitiesListProvider"
],
) -> list[typing.Callable]:
visitor = _MyNodeVisitor()
visitor.visit(ast.parse(inspect.getsource(cls)))
fn_name_to_decorators: dict[str, set[str]] = visitor.get_fn_name_to_decorators()
activities = []
for fn_name, decorators in fn_name_to_decorators.items():
if "activity.defn" in decorators:
method = getattr(instance, fn_name)
activities.append(method)
return activities
def get_activities_from_instance(self) -> list[typing.Callable]:
return self.__get_activities(self)
@classmethod
def get_activities_from_cls(cls) -> list[typing.Callable]:
return cls.__get_activities(cls)
And some Tests:
from workflow_metrics.temporal_tools import activities_class
from temporalio import activity
class SomeActivities(activities_class.ActivitiesListProvider):
@activity.defn
async def instance_method_activity(self):
pass
@activity.defn
async def class_method_activity(self):
pass
@staticmethod
@activity.defn
async def static_method_activity():
pass
def test_get_activities_from_cls():
assert SomeActivities.get_activities_from_cls() == [
SomeActivities.instance_method_activity,
SomeActivities.class_method_activity,
SomeActivities.static_method_activity,
]
class ActivitiesClassThatNeedsInstance(activities_class.ActivitiesListProvider):
@activity.defn
async def instance_method_activity(self):
pass
@activity.defn
async def class_method_activity(self):
pass
@staticmethod
@activity.defn
async def static_method_activity():
pass
def test_get_activities_from_instance():
inst = ActivitiesClassThatNeedsInstance()
assert inst.get_activities_from_instance() == [
inst.instance_method_activity,
inst.class_method_activity,
inst.static_method_activity,
]
Additional context
In code that I am working on activities are mainly defined in one module when they are fns and in class methods.
- 主要言語
- Python
- スター
- 1.2k
- フォーク
- 241
- 平均マージ
- 3日 2時間
- マージ済み PR(30日)
- 49
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
temporalio/sdk-python のほかの issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
temporalio/sdk-python#1517 · コメント 10 件 ·
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
temporalio/sdk-python#496 ·
-
難易度 5/5 1週間以上 初心者へのやさしさ 25/100
temporalio/sdk-python#1890 ·
-
[Bug] Local activity resolutions regrouped on replay since 1.32.0, delivering the wrong payload オープン
難易度 4/5 3〜5日 初心者へのやさしさ 52/100
temporalio/sdk-python#1881 · コメント 1 件 ·
-
bug
temporalio/sdk-python#1817 · コメント 1 件 · 担当者 1 名 ·
temporalio/sdk-python の issue をすべて見る
似ている issue
-
documentation help wanted
難易度 2/5 1〜3時間 初心者へのやさしさ 90/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 90/100
simonw/sqlite-utils#872 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100