Loader: work around Python 3.7 await headache caused by PEP 479

Generators can no longer raise StopIteration, and we are supposed to use "return" instead.  But, return with value inside generator is a syntax error in Python 2.

Fixes #513
This commit is contained in:
rdb 2019-01-09 22:13:16 +01:00
parent d1845530aa
commit 649372d333

View File

@ -27,6 +27,42 @@ class Loader(DirectObject):
# This indicates that this class behaves like a Future.
_asyncio_future_blocking = False
class ResultAwaiter(object):
"""Reinvents generators because of PEP 479, sigh. See #513."""
__slots__ = 'requestList', 'index'
def __init__(self, requestList):
self.requestList = requestList
self.index = 0
def __await__(self):
return self
def __anext__(self):
if self.index >= len(self.requestList):
raise StopAsyncIteration
return self
def __iter__(self):
return self
def __next__(self):
i = self.index
request = self.requestList[i]
if not request.done():
return request
self.index = i + 1
result = request.result()
if isinstance(result, PandaNode):
result = NodePath(result)
exc = StopIteration(result)
exc.value = result
raise exc
def __init__(self, loader, numObjects, gotList, callback, extraArgs):
self._loader = loader
self.objects = [None] * numObjects
@ -81,16 +117,14 @@ class Loader(DirectObject):
def __await__(self):
""" Returns a generator that raises StopIteration when the loading
is complete. This allows this class to be used with 'await'."""
if self.requests:
self._asyncio_future_blocking = True
yield self
# This should be a simple return, but older versions of Python
# don't allow return statements with arguments.
result = self.result()
exc = StopIteration(result)
exc.value = result
raise exc
if self.gotList:
return self.ResultAwaiter([self])
else:
return self.ResultAwaiter(self.requestList)
def __aiter__(self):
""" This allows using `async for` to iterate asynchronously over
@ -100,19 +134,7 @@ class Loader(DirectObject):
requestList = self.requestList
assert requestList is not None, "Request was cancelled."
class AsyncIter:
index = 0
def __anext__(self):
if self.index < len(requestList):
i = self.index
self.index = i + 1
return requestList[i]
else:
raise StopAsyncIteration
iter = AsyncIter()
iter.objects = self.objects
return iter
return self.ResultAwaiter(requestList)
# special methods
def __init__(self, base):