Skip to content

Commit 6423d26

Browse files
committed
Document trio_as_aio and aio_as_trio
plus drop args from trio_as_aio
1 parent bb1c336 commit 6423d26

1 file changed

Lines changed: 53 additions & 16 deletions

File tree

trio_asyncio/adapter.py

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ def trio2aio(proc):
3636
class 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

104122
asyncio_as_trio = aio_as_trio
105123

106124

107125
class 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

166203
trio_as_asyncio = trio_as_aio

0 commit comments

Comments
 (0)