1
0

promise.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. from collections import namedtuple
  2. from functools import partial, wraps
  3. from sys import version_info, exc_info
  4. from threading import RLock
  5. from types import TracebackType
  6. from weakref import WeakKeyDictionary
  7. from six import reraise # type: ignore
  8. from .async_ import Async
  9. from .compat import (
  10. Future,
  11. ensure_future,
  12. iscoroutine, # type: ignore
  13. iterate_promise,
  14. ) # type: ignore
  15. from .utils import deprecated, integer_types, string_types, text_type, binary_type, warn
  16. from .promise_list import PromiseList
  17. from .schedulers.immediate import ImmediateScheduler
  18. from typing import TypeVar, Generic
  19. # from .schedulers.gevent import GeventScheduler
  20. # from .schedulers.asyncio import AsyncioScheduler
  21. # from .schedulers.thread import ThreadScheduler
  22. if False:
  23. from typing import (
  24. Type,
  25. List,
  26. Any,
  27. Callable,
  28. Dict,
  29. Iterator,
  30. Optional, # flake8: noqa
  31. Tuple,
  32. Union,
  33. Generic,
  34. Hashable,
  35. MutableMapping,
  36. )
  37. default_scheduler = ImmediateScheduler()
  38. async_instance = Async()
  39. def get_default_scheduler():
  40. # type: () -> ImmediateScheduler
  41. return default_scheduler
  42. def set_default_scheduler(scheduler):
  43. global default_scheduler
  44. default_scheduler = scheduler
  45. IS_PYTHON2 = version_info[0] == 2
  46. DEFAULT_TIMEOUT = None # type: Optional[float]
  47. MAX_LENGTH = 0xFFFF | 0
  48. CALLBACK_SIZE = 3
  49. CALLBACK_FULFILL_OFFSET = 0
  50. CALLBACK_REJECT_OFFSET = 1
  51. CALLBACK_PROMISE_OFFSET = 2
  52. BASE_TYPES = set(
  53. integer_types
  54. + string_types
  55. + (bool, float, complex, tuple, list, dict, text_type, binary_type)
  56. )
  57. # These are the potential states of a promise
  58. STATE_PENDING = -1
  59. STATE_REJECTED = 0
  60. STATE_FULFILLED = 1
  61. def make_self_resolution_error():
  62. # type: () -> TypeError
  63. return TypeError("Promise is self")
  64. def try_catch(handler, *args, **kwargs):
  65. # type: (Callable, Any, Any) -> Union[Tuple[Any, None], Tuple[None, Tuple[Exception, Optional[TracebackType]]]]
  66. try:
  67. return (handler(*args, **kwargs), None)
  68. except Exception as e:
  69. tb = exc_info()[2]
  70. return (None, (e, tb))
  71. T = TypeVar("T")
  72. S = TypeVar("S", contravariant=True)
  73. class Promise(Generic[T]):
  74. """
  75. This is the Promise class that complies
  76. Promises/A+ specification.
  77. """
  78. # __slots__ = ('_state', '_is_final', '_is_bound', '_is_following', '_is_async_guaranteed',
  79. # '_length', '_handlers', '_fulfillment_handler0', '_rejection_handler0', '_promise0',
  80. # '_is_waiting', '_future', '_trace', '_event_instance'
  81. # )
  82. _state = STATE_PENDING # type: int
  83. _is_final = False
  84. _is_bound = False
  85. _is_following = False
  86. _is_async_guaranteed = False
  87. _length = 0
  88. _handlers = None # type: Dict[int, Union[Callable, Promise, None]]
  89. _fulfillment_handler0 = None # type: Any
  90. _rejection_handler0 = None # type: Any
  91. _promise0 = None # type: Optional[Promise]
  92. _future = None # type: Future
  93. _traceback = None # type: Optional[TracebackType]
  94. # _trace = None
  95. _is_waiting = False
  96. _scheduler = None
  97. def __init__(self, executor=None, scheduler=None):
  98. # type: (Optional[Callable[[Callable[[T], None], Callable[[Exception], None]], None]], Any) -> None
  99. """
  100. Initialize the Promise into a pending state.
  101. """
  102. # self._state = STATE_PENDING # type: int
  103. # self._is_final = False
  104. # self._is_bound = False
  105. # self._is_following = False
  106. # self._is_async_guaranteed = False
  107. # self._length = 0
  108. # self._handlers = None # type: Dict[int, Union[Callable, None]]
  109. # self._fulfillment_handler0 = None # type: Union[Callable, partial]
  110. # self._rejection_handler0 = None # type: Union[Callable, partial]
  111. # self._promise0 = None # type: Promise
  112. # self._future = None # type: Future
  113. # self._event_instance = None # type: Event
  114. # self._is_waiting = False
  115. self._scheduler = scheduler
  116. if executor is not None:
  117. self._resolve_from_executor(executor)
  118. # For compatibility reasons
  119. # self.reject = self._deprecated_reject
  120. # self.resolve = self._deprecated_resolve
  121. @property
  122. def scheduler(self):
  123. # type: () -> ImmediateScheduler
  124. return self._scheduler or default_scheduler
  125. @property
  126. def future(self):
  127. # type: (Promise) -> Future
  128. if not self._future:
  129. self._future = Future() # type: ignore
  130. self._then( # type: ignore
  131. self._future.set_result, self._future.set_exception
  132. )
  133. return self._future
  134. def __iter__(self):
  135. # type: () -> Iterator
  136. return iterate_promise(self._target()) # type: ignore
  137. __await__ = __iter__
  138. @deprecated(
  139. "Rejecting directly in a Promise instance is deprecated, as Promise.reject() is now a class method. "
  140. "Please use promise.do_reject() instead.",
  141. name="reject",
  142. )
  143. def _deprecated_reject(self, e):
  144. self.do_reject(e)
  145. @deprecated(
  146. "Resolving directly in a Promise instance is deprecated, as Promise.resolve() is now a class method. "
  147. "Please use promise.do_resolve() instead.",
  148. name="resolve",
  149. )
  150. def _deprecated_resolve(self, value):
  151. self.do_resolve(value)
  152. def _resolve_callback(self, value):
  153. # type: (T) -> None
  154. if value is self:
  155. return self._reject_callback(make_self_resolution_error(), False)
  156. if not self.is_thenable(value):
  157. return self._fulfill(value)
  158. promise = self._try_convert_to_promise(value)._target()
  159. if promise == self:
  160. self._reject(make_self_resolution_error())
  161. return
  162. if promise._state == STATE_PENDING:
  163. len = self._length
  164. if len > 0:
  165. promise._migrate_callback0(self)
  166. for i in range(1, len):
  167. promise._migrate_callback_at(self, i)
  168. self._is_following = True
  169. self._length = 0
  170. self._set_followee(promise)
  171. elif promise._state == STATE_FULFILLED:
  172. self._fulfill(promise._value())
  173. elif promise._state == STATE_REJECTED:
  174. self._reject(promise._reason(), promise._target()._traceback)
  175. def _settled_value(self, _raise=False):
  176. # type: (bool) -> Any
  177. assert not self._is_following
  178. if self._state == STATE_FULFILLED:
  179. return self._rejection_handler0
  180. elif self._state == STATE_REJECTED:
  181. if _raise:
  182. raise_val = self._fulfillment_handler0
  183. reraise(type(raise_val), raise_val, self._traceback)
  184. return self._fulfillment_handler0
  185. def _fulfill(self, value):
  186. # type: (T) -> None
  187. if value is self:
  188. err = make_self_resolution_error()
  189. # self._attach_extratrace(err)
  190. return self._reject(err)
  191. self._state = STATE_FULFILLED
  192. self._rejection_handler0 = value
  193. if self._length > 0:
  194. if self._is_async_guaranteed:
  195. self._settle_promises()
  196. else:
  197. async_instance.settle_promises(self)
  198. def _reject(self, reason, traceback=None):
  199. # type: (Exception, Optional[TracebackType]) -> None
  200. self._state = STATE_REJECTED
  201. self._fulfillment_handler0 = reason
  202. self._traceback = traceback
  203. if self._is_final:
  204. assert self._length == 0
  205. async_instance.fatal_error(reason, self.scheduler)
  206. return
  207. if self._length > 0:
  208. async_instance.settle_promises(self)
  209. else:
  210. self._ensure_possible_rejection_handled()
  211. if self._is_async_guaranteed:
  212. self._settle_promises()
  213. else:
  214. async_instance.settle_promises(self)
  215. def _ensure_possible_rejection_handled(self):
  216. # type: () -> None
  217. # self._rejection_is_unhandled = True
  218. # async_instance.invoke_later(self._notify_unhandled_rejection, self)
  219. pass
  220. def _reject_callback(self, reason, synchronous=False, traceback=None):
  221. # type: (Exception, bool, Optional[TracebackType]) -> None
  222. assert isinstance(
  223. reason, Exception
  224. ), "A promise was rejected with a non-error: {}".format(reason)
  225. # trace = ensure_error_object(reason)
  226. # has_stack = trace is reason
  227. # self._attach_extratrace(trace, synchronous and has_stack)
  228. self._reject(reason, traceback)
  229. def _clear_callback_data_index_at(self, index):
  230. # type: (int) -> None
  231. assert not self._is_following
  232. assert index > 0
  233. base = index * CALLBACK_SIZE - CALLBACK_SIZE
  234. self._handlers[base + CALLBACK_PROMISE_OFFSET] = None
  235. self._handlers[base + CALLBACK_FULFILL_OFFSET] = None
  236. self._handlers[base + CALLBACK_REJECT_OFFSET] = None
  237. def _fulfill_promises(self, length, value):
  238. # type: (int, T) -> None
  239. for i in range(1, length):
  240. handler = self._fulfillment_handler_at(i)
  241. promise = self._promise_at(i)
  242. self._clear_callback_data_index_at(i)
  243. self._settle_promise(promise, handler, value, None)
  244. def _reject_promises(self, length, reason):
  245. # type: (int, Exception) -> None
  246. for i in range(1, length):
  247. handler = self._rejection_handler_at(i)
  248. promise = self._promise_at(i)
  249. self._clear_callback_data_index_at(i)
  250. self._settle_promise(promise, handler, reason, None)
  251. def _settle_promise(
  252. self,
  253. promise, # type: Optional[Promise]
  254. handler, # type: Optional[Callable]
  255. value, # type: Union[T, Exception]
  256. traceback, # type: Optional[TracebackType]
  257. ):
  258. # type: (...) -> None
  259. assert not self._is_following
  260. is_promise = isinstance(promise, self.__class__)
  261. async_guaranteed = self._is_async_guaranteed
  262. if callable(handler):
  263. if not is_promise:
  264. handler(value) # , promise
  265. else:
  266. if async_guaranteed:
  267. promise._is_async_guaranteed = True # type: ignore
  268. self._settle_promise_from_handler( # type: ignore
  269. handler, value, promise # type: ignore
  270. ) # type: ignore
  271. elif is_promise:
  272. if async_guaranteed:
  273. promise._is_async_guaranteed = True # type: ignore
  274. if self._state == STATE_FULFILLED:
  275. promise._fulfill(value) # type: ignore
  276. else:
  277. promise._reject(value, self._traceback) # type: ignore
  278. def _settle_promise0(
  279. self,
  280. handler, # type: Optional[Callable]
  281. value, # type: Any
  282. traceback, # type: Optional[TracebackType]
  283. ):
  284. # type: (...) -> None
  285. promise = self._promise0
  286. self._promise0 = None
  287. self._settle_promise(promise, handler, value, traceback) # type: ignore
  288. def _settle_promise_from_handler(self, handler, value, promise):
  289. # type: (Callable, Any, Promise) -> None
  290. value, error_with_tb = try_catch(handler, value) # , promise
  291. if error_with_tb:
  292. error, tb = error_with_tb
  293. promise._reject_callback(error, False, tb)
  294. else:
  295. promise._resolve_callback(value)
  296. def _promise_at(self, index):
  297. # type: (int) -> Optional[Promise]
  298. assert index > 0
  299. assert not self._is_following
  300. return self._handlers.get( # type: ignore
  301. index * CALLBACK_SIZE - CALLBACK_SIZE + CALLBACK_PROMISE_OFFSET
  302. )
  303. def _fulfillment_handler_at(self, index):
  304. # type: (int) -> Optional[Callable]
  305. assert not self._is_following
  306. assert index > 0
  307. return self._handlers.get( # type: ignore
  308. index * CALLBACK_SIZE - CALLBACK_SIZE + CALLBACK_FULFILL_OFFSET
  309. )
  310. def _rejection_handler_at(self, index):
  311. # type: (int) -> Optional[Callable]
  312. assert not self._is_following
  313. assert index > 0
  314. return self._handlers.get( # type: ignore
  315. index * CALLBACK_SIZE - CALLBACK_SIZE + CALLBACK_REJECT_OFFSET
  316. )
  317. def _migrate_callback0(self, follower):
  318. # type: (Promise) -> None
  319. self._add_callbacks(
  320. follower._fulfillment_handler0,
  321. follower._rejection_handler0,
  322. follower._promise0,
  323. )
  324. def _migrate_callback_at(self, follower, index):
  325. self._add_callbacks(
  326. follower._fulfillment_handler_at(index),
  327. follower._rejection_handler_at(index),
  328. follower._promise_at(index),
  329. )
  330. def _add_callbacks(
  331. self,
  332. fulfill, # type: Optional[Callable]
  333. reject, # type: Optional[Callable]
  334. promise, # type: Optional[Promise]
  335. ):
  336. # type: (...) -> int
  337. assert not self._is_following
  338. if self._handlers is None:
  339. self._handlers = {}
  340. index = self._length
  341. if index > MAX_LENGTH - CALLBACK_SIZE:
  342. index = 0
  343. self._length = 0
  344. if index == 0:
  345. assert not self._promise0
  346. assert not self._fulfillment_handler0
  347. assert not self._rejection_handler0
  348. self._promise0 = promise
  349. if callable(fulfill):
  350. self._fulfillment_handler0 = fulfill
  351. if callable(reject):
  352. self._rejection_handler0 = reject
  353. else:
  354. base = index * CALLBACK_SIZE - CALLBACK_SIZE
  355. assert (base + CALLBACK_PROMISE_OFFSET) not in self._handlers
  356. assert (base + CALLBACK_FULFILL_OFFSET) not in self._handlers
  357. assert (base + CALLBACK_REJECT_OFFSET) not in self._handlers
  358. self._handlers[base + CALLBACK_PROMISE_OFFSET] = promise
  359. if callable(fulfill):
  360. self._handlers[base + CALLBACK_FULFILL_OFFSET] = fulfill
  361. if callable(reject):
  362. self._handlers[base + CALLBACK_REJECT_OFFSET] = reject
  363. self._length = index + 1
  364. return index
  365. def _target(self):
  366. # type: () -> Promise
  367. ret = self
  368. while ret._is_following:
  369. ret = ret._followee()
  370. return ret
  371. def _followee(self):
  372. # type: () -> Promise
  373. assert self._is_following
  374. assert isinstance(self._rejection_handler0, Promise)
  375. return self._rejection_handler0
  376. def _set_followee(self, promise):
  377. # type: (Promise) -> None
  378. assert self._is_following
  379. assert not isinstance(self._rejection_handler0, Promise)
  380. self._rejection_handler0 = promise
  381. def _settle_promises(self):
  382. # type: () -> None
  383. length = self._length
  384. if length > 0:
  385. if self._state == STATE_REJECTED:
  386. reason = self._fulfillment_handler0
  387. traceback = self._traceback
  388. self._settle_promise0(self._rejection_handler0, reason, traceback)
  389. self._reject_promises(length, reason)
  390. else:
  391. value = self._rejection_handler0
  392. self._settle_promise0(self._fulfillment_handler0, value, None)
  393. self._fulfill_promises(length, value)
  394. self._length = 0
  395. def _resolve_from_executor(self, executor):
  396. # type: (Callable[[Callable[[T], None], Callable[[Exception], None]], None]) -> None
  397. # self._capture_stacktrace()
  398. synchronous = True
  399. def resolve(value):
  400. # type: (T) -> None
  401. self._resolve_callback(value)
  402. def reject(reason, traceback=None):
  403. # type: (Exception, TracebackType) -> None
  404. self._reject_callback(reason, synchronous, traceback)
  405. error = None
  406. traceback = None
  407. try:
  408. executor(resolve, reject)
  409. except Exception as e:
  410. traceback = exc_info()[2]
  411. error = e
  412. synchronous = False
  413. if error is not None:
  414. self._reject_callback(error, True, traceback)
  415. @classmethod
  416. def wait(cls, promise, timeout=None):
  417. # type: (Promise, Optional[float]) -> None
  418. async_instance.wait(promise, timeout)
  419. def _wait(self, timeout=None):
  420. # type: (Optional[float]) -> None
  421. self.wait(self, timeout)
  422. def get(self, timeout=None):
  423. # type: (Optional[float]) -> T
  424. target = self._target()
  425. self._wait(timeout or DEFAULT_TIMEOUT)
  426. return self._target_settled_value(_raise=True)
  427. def _target_settled_value(self, _raise=False):
  428. # type: (bool) -> Any
  429. return self._target()._settled_value(_raise)
  430. _value = _reason = _target_settled_value
  431. value = reason = property(_target_settled_value)
  432. def __repr__(self):
  433. # type: () -> str
  434. hex_id = hex(id(self))
  435. if self._is_following:
  436. return "<Promise at {} following {}>".format(hex_id, self._target())
  437. state = self._state
  438. if state == STATE_PENDING:
  439. return "<Promise at {} pending>".format(hex_id)
  440. elif state == STATE_FULFILLED:
  441. return "<Promise at {} fulfilled with {}>".format(
  442. hex_id, repr(self._rejection_handler0)
  443. )
  444. elif state == STATE_REJECTED:
  445. return "<Promise at {} rejected with {}>".format(
  446. hex_id, repr(self._fulfillment_handler0)
  447. )
  448. return "<Promise unknown>"
  449. @property
  450. def is_pending(self):
  451. # type: (Promise) -> bool
  452. """Indicate whether the Promise is still pending. Could be wrong the moment the function returns."""
  453. return self._target()._state == STATE_PENDING
  454. @property
  455. def is_fulfilled(self):
  456. # type: (Promise) -> bool
  457. """Indicate whether the Promise has been fulfilled. Could be wrong the moment the function returns."""
  458. return self._target()._state == STATE_FULFILLED
  459. @property
  460. def is_rejected(self):
  461. # type: (Promise) -> bool
  462. """Indicate whether the Promise has been rejected. Could be wrong the moment the function returns."""
  463. return self._target()._state == STATE_REJECTED
  464. def catch(self, on_rejection):
  465. # type: (Promise, Callable[[Exception], Any]) -> Promise
  466. """
  467. This method returns a Promise and deals with rejected cases only.
  468. It behaves the same as calling Promise.then(None, on_rejection).
  469. """
  470. return self.then(None, on_rejection)
  471. def _then(
  472. self,
  473. did_fulfill=None, # type: Optional[Callable[[T], S]]
  474. did_reject=None, # type: Optional[Callable[[Exception], S]]
  475. ):
  476. # type: (...) -> Promise[S]
  477. promise = self.__class__() # type: Promise
  478. target = self._target()
  479. state = target._state
  480. if state == STATE_PENDING:
  481. target._add_callbacks(did_fulfill, did_reject, promise)
  482. else:
  483. traceback = None
  484. if state == STATE_FULFILLED:
  485. value = target._rejection_handler0
  486. handler = did_fulfill
  487. elif state == STATE_REJECTED:
  488. value = target._fulfillment_handler0
  489. traceback = target._traceback
  490. handler = did_reject # type: ignore
  491. # target._rejection_is_unhandled = False
  492. async_instance.invoke(
  493. partial(target._settle_promise, promise, handler, value, traceback),
  494. promise.scheduler
  495. # target._settle_promise instead?
  496. # settler,
  497. # target,
  498. )
  499. return promise
  500. fulfill = _resolve_callback
  501. do_resolve = _resolve_callback
  502. do_reject = _reject_callback
  503. def then(self, did_fulfill=None, did_reject=None):
  504. # type: (Promise, Callable[[T], S], Optional[Callable[[Exception], S]]) -> Promise[S]
  505. """
  506. This method takes two optional arguments. The first argument
  507. is used if the "self promise" is fulfilled and the other is
  508. used if the "self promise" is rejected. In either case, this
  509. method returns another promise that effectively represents
  510. the result of either the first of the second argument (in the
  511. case that the "self promise" is fulfilled or rejected,
  512. respectively).
  513. Each argument can be either:
  514. * None - Meaning no action is taken
  515. * A function - which will be called with either the value
  516. of the "self promise" or the reason for rejection of
  517. the "self promise". The function may return:
  518. * A value - which will be used to fulfill the promise
  519. returned by this method.
  520. * A promise - which, when fulfilled or rejected, will
  521. cascade its value or reason to the promise returned
  522. by this method.
  523. * A value - which will be assigned as either the value
  524. or the reason for the promise returned by this method
  525. when the "self promise" is either fulfilled or rejected,
  526. respectively.
  527. :type success: (Any) -> object
  528. :type failure: (Any) -> object
  529. :rtype : Promise
  530. """
  531. return self._then(did_fulfill, did_reject)
  532. def done(self, did_fulfill=None, did_reject=None):
  533. # type: (Optional[Callable], Optional[Callable]) -> None
  534. promise = self._then(did_fulfill, did_reject)
  535. promise._is_final = True
  536. def done_all(self, handlers=None):
  537. # type: (Promise, Optional[List[Union[Dict[str, Optional[Callable]], Tuple[Callable, Callable], Callable]]]) -> None
  538. """
  539. :type handlers: list[(Any) -> object] | list[((Any) -> object, (Any) -> object)]
  540. """
  541. if not handlers:
  542. return
  543. for handler in handlers:
  544. if isinstance(handler, tuple):
  545. s, f = handler
  546. self.done(s, f)
  547. elif isinstance(handler, dict):
  548. s = handler.get("success") # type: ignore
  549. f = handler.get("failure") # type: ignore
  550. self.done(s, f)
  551. else:
  552. self.done(handler)
  553. def then_all(self, handlers=None):
  554. # type: (Promise, List[Callable]) -> List[Promise]
  555. """
  556. Utility function which calls 'then' for each handler provided. Handler can either
  557. be a function in which case it is used as success handler, or a tuple containing
  558. the success and the failure handler, where each of them could be None.
  559. :type handlers: list[(Any) -> object] | list[((Any) -> object, (Any) -> object)]
  560. :param handlers
  561. :rtype : list[Promise]
  562. """
  563. if not handlers:
  564. return []
  565. promises = [] # type: List[Promise]
  566. for handler in handlers:
  567. if isinstance(handler, tuple):
  568. s, f = handler
  569. promises.append(self.then(s, f))
  570. elif isinstance(handler, dict):
  571. s = handler.get("success")
  572. f = handler.get("failure")
  573. promises.append(self.then(s, f))
  574. else:
  575. promises.append(self.then(handler))
  576. return promises
  577. @classmethod
  578. def _try_convert_to_promise(cls, obj):
  579. # type: (Any) -> Promise
  580. _type = obj.__class__
  581. if issubclass(_type, Promise):
  582. if cls is not Promise:
  583. return cls(obj.then, obj._scheduler)
  584. return obj
  585. if iscoroutine(obj): # type: ignore
  586. obj = ensure_future(obj) # type: ignore
  587. _type = obj.__class__
  588. if is_future_like(_type):
  589. def executor(resolve, reject):
  590. # type: (Callable, Callable) -> None
  591. if obj.done():
  592. _process_future_result(resolve, reject)(obj)
  593. else:
  594. obj.add_done_callback(_process_future_result(resolve, reject))
  595. # _process_future_result(resolve, reject)(obj)
  596. promise = cls(executor) # type: Promise
  597. promise._future = obj
  598. return promise
  599. return obj
  600. @classmethod
  601. def reject(cls, reason):
  602. # type: (Exception) -> Promise
  603. ret = cls() # type: Promise
  604. # ret._capture_stacktrace();
  605. # ret._rejectCallback(reason, true);
  606. ret._reject_callback(reason, True)
  607. return ret
  608. rejected = reject
  609. @classmethod
  610. def resolve(cls, obj):
  611. # type: (T) -> Promise[T]
  612. if not cls.is_thenable(obj):
  613. ret = cls() # type: Promise
  614. # ret._capture_stacktrace()
  615. ret._state = STATE_FULFILLED
  616. ret._rejection_handler0 = obj
  617. return ret
  618. return cls._try_convert_to_promise(obj)
  619. cast = resolve
  620. fulfilled = cast
  621. @classmethod
  622. def promisify(cls, f):
  623. # type: (Callable) -> Callable[..., Promise]
  624. if not callable(f):
  625. warn(
  626. "Promise.promisify is now a function decorator, please use Promise.resolve instead."
  627. )
  628. return cls.resolve(f)
  629. @wraps(f)
  630. def wrapper(*args, **kwargs):
  631. # type: (*Any, **Any) -> Promise
  632. def executor(resolve, reject):
  633. # type: (Callable, Callable) -> Optional[Any]
  634. return resolve(f(*args, **kwargs))
  635. return cls(executor)
  636. return wrapper
  637. _safe_resolved_promise = None # type: Promise
  638. @classmethod
  639. def safe(cls, fn):
  640. # type: (Callable) -> Callable
  641. from functools import wraps
  642. if not cls._safe_resolved_promise:
  643. cls._safe_resolved_promise = Promise.resolve(None)
  644. @wraps(fn)
  645. def wrapper(*args, **kwargs):
  646. # type: (*Any, **Any) -> Promise
  647. return cls._safe_resolved_promise.then(lambda v: fn(*args, **kwargs))
  648. return wrapper
  649. @classmethod
  650. def all(cls, promises):
  651. # type: (Any) -> Promise
  652. return PromiseList(promises, promise_class=cls).promise
  653. @classmethod
  654. def for_dict(cls, m):
  655. # type: (Dict[Hashable, Promise[S]]) -> Promise[Dict[Hashable, S]]
  656. """
  657. A special function that takes a dictionary of promises
  658. and turns them into a promise for a dictionary of values.
  659. In other words, this turns an dictionary of promises for values
  660. into a promise for a dictionary of values.
  661. """
  662. dict_type = type(m) # type: Type[Dict]
  663. if not m:
  664. return cls.resolve(dict_type()) # type: ignore
  665. def handle_success(resolved_values):
  666. # type: (List[S]) -> Dict[Hashable, S]
  667. return dict_type(zip(m.keys(), resolved_values))
  668. return cls.all(m.values()).then(handle_success)
  669. @classmethod
  670. def is_thenable(cls, obj):
  671. # type: (Any) -> bool
  672. """
  673. A utility function to determine if the specified
  674. object is a promise using "duck typing".
  675. """
  676. _type = obj.__class__
  677. if obj is None or _type in BASE_TYPES:
  678. return False
  679. return (
  680. issubclass(_type, Promise)
  681. or iscoroutine(obj) # type: ignore
  682. or is_future_like(_type)
  683. )
  684. _type_done_callbacks = WeakKeyDictionary() # type: MutableMapping[type, bool]
  685. def is_future_like(_type):
  686. # type: (type) -> bool
  687. if _type not in _type_done_callbacks:
  688. _type_done_callbacks[_type] = callable(
  689. getattr(_type, "add_done_callback", None)
  690. )
  691. return _type_done_callbacks[_type]
  692. promisify = Promise.promisify
  693. promise_for_dict = Promise.for_dict
  694. is_thenable = Promise.is_thenable
  695. def _process_future_result(resolve, reject):
  696. # type: (Callable, Callable) -> Callable
  697. def handle_future_result(future):
  698. # type: (Any) -> None
  699. try:
  700. resolve(future.result())
  701. except Exception as e:
  702. tb = exc_info()[2]
  703. reject(e, tb)
  704. return handle_future_result