@@ -36,8 +36,9 @@ def trio2aio(proc):
3636class Asyncio_Trio_Wrapper :
3737 """
3838 This wrapper object encapsulates an asyncio-style coroutine,
39- generator, or iterator, to be called seamlessly from Trio.
39+ procedure, generator, or iterator, to be called seamlessly from Trio.
4040 """
41+
4142 def __init__ (self , proc , args = [], loop = None ):
4243 self .proc = proc
4344 self .args = args
@@ -52,7 +53,7 @@ def loop(self):
5253 return loop
5354
5455 def __get__ (self , obj , cls ):
55- """If this is used to decorate an instance,
56+ """If this is used to decorate an instance/class method ,
5657 we need to forward the original ``self`` to the wrapped method.
5758 """
5859 if obj is None :
@@ -63,6 +64,7 @@ async def __call__(self, *args, **kwargs):
6364 if self .args :
6465 raise RuntimeError ("Call 'aio_as_trio(proc)(*args)', not 'aio_as_trio(proc, *args)'" )
6566
67+ # TODO: do this within the loop context
6668 f = self .proc (* args , ** kwargs )
6769 return await self .loop .run_aio_coroutine (f )
6870
@@ -98,20 +100,42 @@ def __aiter__(self):
98100 return run_aio_generator (self .loop , proc_iter ())
99101
100102
101- def aio_as_trio (proc , loop = None ):
103+ def aio_as_trio (proc , * , loop = None ):
104+ """
105+ Encapsulate an asyncio-style coroutine, procedure, generator, or
106+ iterator, to be called seamlessly from Trio.
107+
108+ Note that while adapting coroutines, i.e.
109+ wrap(proc(*args))
110+ is supported (because asyncio uses them a lot) they're not a good
111+ idea because setting up the coroutine won't run within an asyncio
112+ context. If at all possible, use::
113+
114+ wrap(proc, *args)
115+
116+ instead, which translates to::
117+
118+ await aio_as_trio(proc)(*args)
119+ """
102120 return Asyncio_Trio_Wrapper (proc , loop = loop )
103121
104122asyncio_as_trio = aio_as_trio
105123
106124
107125class Trio_Asyncio_Wrapper :
108126 """
109- This wrapper object encapsulates a trio -style coroutine ,
110- generator, or iterator, to be called seamlessly from Trio .
127+ This wrapper object encapsulates a Trio -style procedure ,
128+ generator, or iterator, to be called seamlessly from asyncio .
111129 """
112- def __init__ (self , proc , args = [], loop = None ):
130+
131+ # This class doesn't wrap coroutines because Trio's call convention
132+ # is
133+ # wrap(proc, *args)
134+ # and not
135+ # wrap(proc(*args))
136+
137+ def __init__ (self , proc , loop = None ):
113138 self .proc = proc
114- self .args = args
115139 self ._loop = loop
116140
117141 @property
@@ -123,44 +147,57 @@ def loop(self):
123147 return loop
124148
125149 def __get__ (self , obj , cls ):
126- """If this is used to decorate an instance,
150+ """If this is used to decorate an instance/class method ,
127151 we need to forward the original ``self`` to the wrapped method.
128152 """
129153 if obj is None :
130154 return partial (self .__call__ , cls )
131155 return partial (self .__call__ , obj )
132156
133157 def __call__ (self , * args , ** kwargs ):
134- if self .args :
135- raise RuntimeError ("Call 'trio_as_aio(proc)(*args)', not 'trio_as_aio(proc, *args)'" )
136-
137158 proc = self .proc
138159 if kwargs :
139160 proc = partial (proc , ** kwargs )
140161 return self .loop .trio_as_future (proc , * args )
141162
142163 def __aenter__ (self ):
143164 proc_enter = getattr (self .proc , "__aenter__" , None )
144- if proc_enter is None or self . args :
165+ if proc_enter is None :
145166 raise RuntimeError (
146167 "Call 'trio_as_aio(ctxfactory(*args))', not 'trio_as_aio(ctxfactory, *args)'"
147168 )
148169 return self .loop .trio_as_future (proc_enter )
149170
150171 def __aexit__ (self , * tb ):
151- f = self .proc .__aexit__
152- return self .loop .trio_as_future (f , * tb )
172+ proc_exit = self .proc .__aexit__
173+ return self .loop .trio_as_future (proc_exit , * tb )
153174
154175 def __aiter__ (self ):
155176 proc_iter = getattr (self .proc , "__aiter__" , None )
156- if proc_iter is None or self . args :
177+ if proc_iter is None :
157178 raise RuntimeError (
158179 "Call 'trio_as_aio(gen(*args))', not 'trio_as_aio(gen, *args)'"
159180 )
160181 return run_trio_generator (self .loop , proc_iter ())
161182
162183
163- def trio_as_aio (proc , loop = None ):
184+ def trio_as_aio (proc , * , loop = None ):
185+ """
186+ Encapsulate a Trio-style procedure, generator, or iterator, to be
187+ called seamlessly from asyncio.
188+
189+ Note that adapting coroutines, i.e.::
190+
191+ wrap(proc(*args))
192+
193+ is not supported: Trio's calling convention is to always use::
194+
195+ wrap(proc, *args)
196+
197+ which translates to::
198+
199+ await trio_as_aio(proc)(*args)
200+ """
164201 return Trio_Asyncio_Wrapper (proc , loop = loop )
165202
166203trio_as_asyncio = trio_as_aio
0 commit comments