浏览代码

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
rdb 7 年之前
父节点
当前提交
649372d333
共有 1 个文件被更改,包括 42 次插入20 次删除
  1. 42 20
      direct/src/showbase/Loader.py

+ 42 - 20
direct/src/showbase/Loader.py

@@ -27,6 +27,42 @@ class Loader(DirectObject):
         # This indicates that this class behaves like a Future.
         # This indicates that this class behaves like a Future.
         _asyncio_future_blocking = False
         _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):
         def __init__(self, loader, numObjects, gotList, callback, extraArgs):
             self._loader = loader
             self._loader = loader
             self.objects = [None] * numObjects
             self.objects = [None] * numObjects
@@ -81,16 +117,14 @@ class Loader(DirectObject):
         def __await__(self):
         def __await__(self):
             """ Returns a generator that raises StopIteration when the loading
             """ Returns a generator that raises StopIteration when the loading
             is complete.  This allows this class to be used with 'await'."""
             is complete.  This allows this class to be used with 'await'."""
+
             if self.requests:
             if self.requests:
                 self._asyncio_future_blocking = True
                 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):
         def __aiter__(self):
             """ This allows using `async for` to iterate asynchronously over
             """ This allows using `async for` to iterate asynchronously over
@@ -100,19 +134,7 @@ class Loader(DirectObject):
             requestList = self.requestList
             requestList = self.requestList
             assert requestList is not None, "Request was cancelled."
             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
     # special methods
     def __init__(self, base):
     def __init__(self, base):