Skip to content

Commit 32773c3

Browse files
authored
Merge 1d390cb into d15d7bb
2 parents d15d7bb + 1d390cb commit 32773c3

File tree

4 files changed

+34
-7
lines changed

4 files changed

+34
-7
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ releases are available on [PyPI](https://pypi.org/project/pytask-parallel) and
1010
- {pull}`62` deprecates Python 3.7.
1111
- {pull}`64` aligns pytask-parallel with pytask v0.4.0rc2.
1212
- {pull}`66` deactivates parallelization for dry-runs.
13+
- {pull}`67` fixes parallelization with partialed task functions.
14+
- {pull}`68` updates dependencies and syntaxes.
1315

1416
## 0.3.1 - 2023-05-27
1517

environment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ dependencies:
1212
- toml
1313

1414
# Package dependencies
15-
- pytask>=0.4.0rc2
15+
- pytask>=0.4.0rc4
1616
- cloudpickle
1717
- loky
1818
- optree

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@ project_urls =
2424
[options]
2525
packages = find:
2626
install_requires =
27+
attrs>=21.3.0
2728
click
2829
cloudpickle
2930
loky
3031
optree>=0.9.0
32+
pluggy>=1.0.0
3133
pytask>=0.4.0rc2
34+
rich
3235
python_requires = >=3.8
3336
include_package_data = True
3437
package_dir = =src

src/pytask_parallel/execute.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
import time
77
import warnings
88
from concurrent.futures import Future
9+
from pathlib import Path
10+
from types import ModuleType
911
from types import TracebackType
1012
from typing import Any
1113
from typing import Callable
12-
from typing import List
1314

14-
import attr
1515
import cloudpickle
16+
from attrs import define
17+
from attrs import field
1618
from pytask import console
1719
from pytask import ExecutionReport
1820
from pytask import get_marks
@@ -56,6 +58,8 @@ def pytask_execute_build(session: Session) -> bool | None: # noqa: C901, PLR091
5658
3. Process all reports and report the result on the command line.
5759
5860
"""
61+
__tracebackhide__ = True
62+
5963
if session.config["n_workers"] > 1:
6064
reports = session.execution_reports
6165
running_tasks: dict[str, Future[Any]] = {}
@@ -191,7 +195,7 @@ def pytask_execute_task(session: Session, task: PTask) -> Future[Any] | None:
191195
# the child process. We have to register the module as dynamic again, so
192196
# that cloudpickle will pickle it with the function. See cloudpickle#417,
193197
# pytask#373 and pytask#374.
194-
task_module = inspect.getmodule(task.function)
198+
task_module = _get_module(task.function, getattr(task, "path", None))
195199
cloudpickle.register_pickle_by_value(task_module)
196200

197201
return session.config["_parallel_executor"].submit(
@@ -344,7 +348,7 @@ def _create_kwargs_for_task(task: PTask) -> dict[str, PyTree[Any]]:
344348
return kwargs
345349

346350

347-
@attr.s(kw_only=True)
351+
@define(kw_only=True)
348352
class _Sleeper:
349353
"""A sleeper that always sleeps a bit and up to 1 second if you don't wake it up.
350354
@@ -353,8 +357,8 @@ class _Sleeper:
353357
354358
"""
355359

356-
timings = attr.ib(type=List[float], default=[(i / 10) ** 2 for i in range(1, 11)])
357-
timing_idx = attr.ib(type=int, default=0)
360+
timings: list[float] = field(default=[(i / 10) ** 2 for i in range(1, 11)])
361+
timing_idx: int = 0
358362

359363
def reset(self) -> None:
360364
self.timing_idx = 0
@@ -365,3 +369,21 @@ def increment(self) -> None:
365369

366370
def sleep(self) -> None:
367371
time.sleep(self.timings[self.timing_idx])
372+
373+
374+
def _get_module(func: Callable[..., Any], path: Path) -> ModuleType:
375+
"""Get the module of a python function.
376+
377+
For Python <3.10, functools.partial does not set a `__module__` attribute which is
378+
why ``inspect.getmodule`` returns ``None`` and ``cloudpickle.pickle_by_value``
379+
fails. In later versions, ``functools`` is returned and everything seems to work
380+
fine.
381+
382+
Therefore, we use the path from the task module to aid the search which works for
383+
Python <3.10.
384+
385+
We do not unwrap the partialed function with ``func.func``, since pytask in general
386+
does not really support ``functools.partial``. Instead, use ``@task(kwargs=...)``.
387+
388+
"""
389+
return inspect.getmodule(func, path.as_posix())

0 commit comments

Comments
 (0)