From 8bc4939c5b559ae9601d873ce544a65745d4ec31 Mon Sep 17 00:00:00 2001 From: Chris White Date: Tue, 3 Sep 2024 13:31:35 -0500 Subject: [PATCH] Fix task key comp (#15190) --- src/prefect/tasks.py | 11 ++++++++++- tests/test_tasks.py | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/prefect/tasks.py b/src/prefect/tasks.py index 2b8355126fd1..6fac57389e1a 100644 --- a/src/prefect/tasks.py +++ b/src/prefect/tasks.py @@ -206,8 +206,17 @@ def _generate_task_key(fn: Callable[..., Any]) -> str: qualname = fn.__qualname__.split(".")[-1] + try: + code_obj = getattr(fn, "__code__", None) + if code_obj is None: + code_obj = fn.__call__.__code__ + except AttributeError: + raise AttributeError( + f"{fn} is not a standard Python function object and could not be converted to a task." + ) from None + code_hash = ( - h[:NUM_CHARS_DYNAMIC_KEY] if (h := hash_objects(fn.__code__)) else "unknown" + h[:NUM_CHARS_DYNAMIC_KEY] if (h := hash_objects(code_obj)) else "unknown" ) return f"{qualname}-{code_hash}" diff --git a/tests/test_tasks.py b/tests/test_tasks.py index 2702ae5747a3..e74681290f5e 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -117,6 +117,21 @@ def test_task_key_after_import(self): assert noop.task_key.startswith("noop-") + def test_task_key_with_funky_class(self): + class Funky: + def __call__(self, x): + return x + + # set up class to trigger certain code path + # see https://github.com/PrefectHQ/prefect/issues/15058 + funky = Funky() + funky.__qualname__ = "__main__.Funky" + if hasattr(funky, "__code__"): + del funky.__code__ + + tt = task(funky) + assert tt.task_key.startswith("Funky-") + class TestTaskRunName: def test_run_name_default(self):