promise_list.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. from functools import partial
  2. try:
  3. from collections.abc import Iterable
  4. except ImportError:
  5. from collections import Iterable
  6. if False:
  7. from .promise import Promise
  8. from typing import (
  9. Any,
  10. Optional,
  11. Tuple,
  12. Union,
  13. List,
  14. Type,
  15. Collection,
  16. ) # flake8: noqa
  17. class PromiseList(object):
  18. __slots__ = ("_values", "_length", "_total_resolved", "promise", "_promise_class")
  19. def __init__(self, values, promise_class):
  20. # type: (Union[Collection, Promise[Collection]], Type[Promise]) -> None
  21. self._promise_class = promise_class
  22. self.promise = self._promise_class()
  23. self._length = 0
  24. self._total_resolved = 0
  25. self._values = None # type: Optional[Collection]
  26. Promise = self._promise_class
  27. if Promise.is_thenable(values):
  28. values_as_promise = Promise._try_convert_to_promise(
  29. values
  30. )._target() # type: ignore
  31. self._init_promise(values_as_promise)
  32. else:
  33. self._init(values) # type: ignore
  34. def __len__(self):
  35. # type: () -> int
  36. return self._length
  37. def _init_promise(self, values):
  38. # type: (Promise[Collection]) -> None
  39. if values.is_fulfilled:
  40. values = values._value()
  41. elif values.is_rejected:
  42. self._reject(values._reason())
  43. return
  44. self.promise._is_async_guaranteed = True
  45. values._then(self._init, self._reject)
  46. return
  47. def _init(self, values):
  48. # type: (Collection) -> None
  49. self._values = values
  50. if not isinstance(values, Iterable):
  51. err = Exception(
  52. "PromiseList requires an iterable. Received {}.".format(repr(values))
  53. )
  54. self.promise._reject_callback(err, False)
  55. return
  56. if not values:
  57. self._resolve([])
  58. return
  59. self._iterate(values)
  60. return
  61. def _iterate(self, values):
  62. # type: (Collection[Any]) -> None
  63. Promise = self._promise_class
  64. is_resolved = False
  65. self._length = len(values)
  66. self._values = [None] * self._length
  67. result = self.promise
  68. for i, val in enumerate(values):
  69. if Promise.is_thenable(val):
  70. maybe_promise = Promise._try_convert_to_promise(val)._target()
  71. # if is_resolved:
  72. # # maybe_promise.suppressUnhandledRejections
  73. # pass
  74. if maybe_promise.is_pending:
  75. maybe_promise._add_callbacks(
  76. partial(self._promise_fulfilled, i=i),
  77. self._promise_rejected,
  78. None,
  79. )
  80. self._values[i] = maybe_promise
  81. elif maybe_promise.is_fulfilled:
  82. is_resolved = self._promise_fulfilled(maybe_promise._value(), i)
  83. elif maybe_promise.is_rejected:
  84. is_resolved = self._promise_rejected(maybe_promise._reason())
  85. else:
  86. is_resolved = self._promise_fulfilled(val, i)
  87. if is_resolved:
  88. break
  89. if not is_resolved:
  90. result._is_async_guaranteed = True
  91. def _promise_fulfilled(self, value, i):
  92. # type: (Any, int) -> bool
  93. if self.is_resolved:
  94. return False
  95. # assert not self.is_resolved
  96. # assert isinstance(self._values, Iterable)
  97. # assert isinstance(i, int)
  98. self._values[i] = value # type: ignore
  99. self._total_resolved += 1
  100. if self._total_resolved >= self._length:
  101. self._resolve(self._values) # type: ignore
  102. return True
  103. return False
  104. def _promise_rejected(self, reason):
  105. # type: (Exception) -> bool
  106. if self.is_resolved:
  107. return False
  108. # assert not self.is_resolved
  109. # assert isinstance(self._values, Iterable)
  110. self._total_resolved += 1
  111. self._reject(reason)
  112. return True
  113. @property
  114. def is_resolved(self):
  115. # type: () -> bool
  116. return self._values is None
  117. def _resolve(self, value):
  118. # type: (Collection[Any]) -> None
  119. assert not self.is_resolved
  120. assert not isinstance(value, self._promise_class)
  121. self._values = None
  122. self.promise._fulfill(value)
  123. def _reject(self, reason):
  124. # type: (Exception) -> None
  125. assert not self.is_resolved
  126. self._values = None
  127. self.promise._reject_callback(reason, False)