1
1
import typing as T
2
2
import asyncio
3
+ import inspect
3
4
from datetime import datetime
4
5
from concurrent .futures import Future
5
6
import threading
@@ -49,20 +50,28 @@ def _gen_initializer(gen_func, args=tuple(), kwargs={}): # pragma: no cover
49
50
_thread_locals ._generator = gen_func (* args , ** kwargs )
50
51
51
52
52
- def _gen_next (fut = None ): # pragma: no cover
53
+ def _gen_next (send_value = None , fut = None ): # pragma: no cover
53
54
global _thread_locals
54
55
if fut is None :
55
- return next ( _thread_locals ._generator )
56
+ g = _thread_locals ._generator
56
57
else :
57
- return next (fut )
58
+ g = fut
59
+ if send_value is None :
60
+ return next (g )
61
+ else :
62
+ return g .send (send_value )
58
63
59
64
60
- def _gen_anext (fut = None ): # pragma: no cover
65
+ def _gen_anext (send_value = None , fut = None ): # pragma: no cover
61
66
global _thread_locals
62
67
if fut is None :
63
- return asyncio .run (_thread_locals ._generator .__anext__ ())
68
+ g = _thread_locals ._generator
69
+ else :
70
+ g = fut
71
+ if send_value is None :
72
+ return asyncio .run (g .__anext__ ())
64
73
else :
65
- return asyncio .run (fut . __anext__ ( ))
74
+ return asyncio .run (g . asend ( send_value ))
66
75
67
76
68
77
class GeneratorWrapper ():
@@ -75,19 +84,28 @@ def __init__(self, job: "Job", fut: T.Optional[Future] = None):
75
84
self ._fut = fut
76
85
self ._local_res = None
77
86
87
+
88
+ class SyncGeneratorWrapper (GeneratorWrapper ):
89
+ """
90
+ wrap a generator in executor pool
91
+ """
78
92
def __iter__ (self ):
79
93
return self
80
94
81
- def __next__ (self ):
95
+ def _next (self , send_value = None ):
82
96
try :
83
97
if self ._job ._executor is not None :
84
98
return self ._job ._executor .submit (
85
- _gen_next , self ._fut ).result ()
99
+ _gen_next , send_value , self ._fut ).result ()
86
100
else :
101
+ # create local generator
87
102
if self ._local_res is None :
88
103
self ._local_res = self ._job .func (
89
104
* self ._job .args , ** self ._job .kwargs )
90
- return next (self ._local_res )
105
+ if send_value is not None :
106
+ return self ._local_res .send (send_value )
107
+ else :
108
+ return next (self ._local_res )
91
109
except Exception as e :
92
110
engine = self ._job .engine
93
111
if engine is None :
@@ -102,23 +120,52 @@ def __next__(self):
102
120
fut .result ()
103
121
raise e
104
122
123
+ def __next__ (self ):
124
+ return self ._next ()
125
+
126
+ def send (self , value ):
127
+ return self ._next (value )
128
+
129
+
130
+ class AsyncGeneratorWrapper (GeneratorWrapper ):
131
+ """
132
+ wrap a generator in executor pool
133
+ """
105
134
def __aiter__ (self ):
106
135
return self
107
136
108
- async def __anext__ (self ):
137
+ async def _anext (self , send_value = None ):
109
138
try :
110
139
if self ._job ._executor is not None :
111
- fut = self ._job ._executor .submit (_gen_anext , self ._fut )
140
+ fut = self ._job ._executor .submit (
141
+ _gen_anext , send_value , self ._fut )
112
142
res = await asyncio .wrap_future (fut )
113
143
return res
114
144
else :
115
145
if self ._local_res is None :
116
146
self ._local_res = self ._job .func (
117
147
* self ._job .args , ** self ._job .kwargs )
118
- return await self ._local_res .__anext__ ()
148
+ if send_value is not None :
149
+ return await self ._local_res .asend (send_value )
150
+ else :
151
+ return await self ._local_res .__anext__ ()
119
152
except Exception as e :
120
153
if isinstance (e , StopAsyncIteration ):
121
154
await self ._job .on_done (self )
122
155
else :
123
156
await self ._job .on_failed (e )
124
157
raise e
158
+
159
+ async def __anext__ (self ):
160
+ return await self ._anext ()
161
+
162
+ async def asend (self , value ):
163
+ return await self ._anext (value )
164
+
165
+
166
+ def create_generator_wrapper (
167
+ job : "Job" , fut : T .Optional [Future ] = None ) -> GeneratorWrapper :
168
+ if inspect .isasyncgenfunction (job .func ):
169
+ return AsyncGeneratorWrapper (job , fut )
170
+ else :
171
+ return SyncGeneratorWrapper (job , fut )
0 commit comments