Skip to content

Commit 5ba097a

Browse files
committed
Strip local from task.
1 parent c2166c3 commit 5ba097a

2 files changed

Lines changed: 17 additions & 0 deletions

File tree

src/pytask_parallel/execute.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from pytask_parallel.utils import create_kwargs_for_task
3333
from pytask_parallel.utils import get_module
3434
from pytask_parallel.utils import parse_future_result
35+
from pytask_parallel.utils import strip_annotation_locals
3536
from pytask_parallel.utils import should_pickle_module_by_value
3637

3738
if TYPE_CHECKING:
@@ -198,6 +199,7 @@ def pytask_execute_task(session: Session, task: PTask) -> Future[WrapperResult]:
198199
kwargs = create_kwargs_for_task(task, remote=remote)
199200

200201
if is_coiled_function(task):
202+
strip_annotation_locals(task)
201203
# Prevent circular import for coiled backend.
202204
from pytask_parallel.wrappers import ( # noqa: PLC0415
203205
rewrap_task_with_coiled_function,
@@ -225,6 +227,7 @@ def pytask_execute_task(session: Session, task: PTask) -> Future[WrapperResult]:
225227
)
226228

227229
if worker_type == WorkerType.PROCESSES:
230+
strip_annotation_locals(task)
228231
# Prevent circular import for loky backend.
229232
from pytask_parallel.wrappers import wrap_task_in_process # noqa: PLC0415
230233

src/pytask_parallel/utils.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class CoiledFunction: ...
4040
"create_kwargs_for_task",
4141
"get_module",
4242
"parse_future_result",
43+
"strip_annotation_locals",
4344
"should_pickle_module_by_value",
4445
]
4546

@@ -154,6 +155,19 @@ def get_module(func: Callable[..., Any], path: Path | None) -> ModuleType:
154155
return inspect.getmodule(func) # type: ignore[return-value]
155156

156157

158+
def strip_annotation_locals(task: PTask) -> None:
159+
"""Remove annotation locals from task functions before pickling.
160+
161+
The locals snapshot is only needed during collection to evaluate annotations.
162+
Keeping it around for execution can break pickling when it contains non-serializable
163+
objects (for example, when importing ``pytask.mark`` in loop-generated tasks).
164+
165+
"""
166+
meta = getattr(task.function, "pytask_meta", None)
167+
if meta is not None and getattr(meta, "annotation_locals", None) is not None:
168+
meta.annotation_locals = None
169+
170+
157171
def should_pickle_module_by_value(module: ModuleType) -> bool:
158172
"""Return whether a module should be pickled by value.
159173

0 commit comments

Comments
 (0)