Skip to content

Commit b7239e0

Browse files
wip
1 parent 45e7084 commit b7239e0

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

pedantic/decorators/fn_deco_in_subprocess.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from multiprocess import Process, Pipe
99
from multiprocess.connection import Connection
1010

11-
mp.set_start_method(method="spawn", force=True)
11+
mp.set_start_method(method="spawn", force=True) # child processes are fresh, no memory or state is inherited
1212
except ImportError:
1313
Process: Optional[Type] = None
1414
Pipe: Optional[Type] = None
@@ -33,6 +33,12 @@ def in_subprocess(func: Callable[..., Union[T, Awaitable[T]]]) -> Callable[...,
3333
of your application synchronously. That ensures that other asyncio.Tasks can work without any problem
3434
at the same time.
3535
36+
IMPORTANT! All *args and **kwargs passed to your function must be serializable with dill
37+
https://pypi.org/project/dill, e.g. the following must work:
38+
>>> import dill as pickle
39+
>>> obj = 42 # can be anything
40+
>>> assert pickle.loads(pickle.dumps(obj)) == obj
41+
3642
Example:
3743
>>> import time
3844
>>> import asyncio
@@ -109,14 +115,9 @@ async def calculate_in_subprocess(func: Callable[..., Union[T, Awaitable[T]]], *
109115
def _inner(tx: Connection, fun: Callable[..., Union[T, Awaitable[T]]], *a, **kw_args) -> None:
110116
""" This runs in another process. """
111117

112-
event_loop = None
113-
if inspect.iscoroutinefunction(fun):
114-
event_loop = asyncio.new_event_loop()
115-
asyncio.set_event_loop(event_loop)
116-
117118
try:
118-
if event_loop is not None:
119-
res = event_loop.run_until_complete(fun(*a, **kw_args))
119+
if inspect.iscoroutinefunction(fun):
120+
res = asyncio.run(fun(*a, **kw_args))
120121
else:
121122
res = fun(*a, **kw_args)
122123
except Exception as ex:

pedantic/tests/test_in_subprocess.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import unittest
44
from typing import NoReturn
55

6+
import dill
67
from multiprocess import Pipe
78

89
from pedantic import in_subprocess
@@ -150,3 +151,20 @@ def f(a: int, b: int) -> int:
150151
foo = Foo()
151152
assert await foo.pos_args() == 9
152153
assert await foo.kw_args() == 9
154+
155+
async def test_unpicklable_arg(self):
156+
class NonPickableObject:
157+
def __getstate__(self):
158+
raise TypeError("This object cannot be pickled")
159+
160+
obj = NonPickableObject()
161+
162+
with self.assertRaises(expected_exception=TypeError):
163+
dill.dumps(obj)
164+
165+
@in_subprocess
166+
def f(x: NonPickableObject):
167+
return x
168+
169+
with self.assertRaises(expected_exception=TypeError):
170+
await f(obj)

0 commit comments

Comments
 (0)