15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)import logging
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import sys
76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)import traceback
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_no_value = object()
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def _DefaultErrorHandler(error):
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  raise error
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)def All(futures, except_pass=None, except_pass_log=False):
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  '''Creates a Future which returns a list of results from each Future in
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  |futures|.
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  If any Future raises an error other than those in |except_pass| the returned
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Future will raise as well.
226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  If any Future raises an error in |except_pass| then None will be inserted as
246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  its result. If |except_pass_log| is True then the exception will be logged.
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  '''
260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  def resolve():
270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    resolved = []
280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for f in futures:
290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      try:
300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        resolved.append(f.Get())
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      # "except None" will simply not catch any errors.
320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      except except_pass:
336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        if except_pass_log:
346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          logging.error(traceback.format_exc())
356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        resolved.append(None)
360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        pass
370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return resolved
380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return Future(callback=resolve)
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)def Race(futures, except_pass=None, default=_no_value):
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  '''Returns a Future which resolves to the first Future in |futures| that
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  either succeeds or throws an error apart from those in |except_pass|.
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  If all Futures throw errors in |except_pass| then |default| is returned,
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if specified. If |default| is not specified then one of the passed errors
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  will be re-thrown, for a nice stack trace.
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  '''
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def resolve():
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    first_future = None
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for future in futures:
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if first_future is None:
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        first_future = future
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      try:
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return future.Get()
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      # "except None" will simply not catch any errors.
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      except except_pass:
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        pass
596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if default is not _no_value:
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return default
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # Everything failed and there is no default value, propagate the first
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # error even though it was caught by |except_pass|.
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return first_future.Get()
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return Future(callback=resolve)
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Future(object):
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  '''Stores a value, error, or callback to be used later.
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  '''
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  def __init__(self, value=_no_value, callback=None, exc_info=None):
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._value = value
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    self._callback = callback
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self._exc_info = exc_info
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (self._value is _no_value and
75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        self._callback is None and
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        self._exc_info is None):
77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      raise ValueError('Must have either a value, error, or callback.')
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def Then(self, callback, error_handler=_DefaultErrorHandler):
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    '''Creates and returns a future that runs |callback| on the value of this
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    future, or runs optional |error_handler| if resolving this future results in
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    an exception.
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    If |callback| returns a non-Future value then the returned Future will
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    resolve to that value.
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    If |callback| returns a Future then it gets chained to the current Future.
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    This means that the returned Future will resolve to *that* Future's value.
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    This behaviour is transitive.
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    For example,
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      def fortytwo():
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return Future(value=42)
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      def inc(x):
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return x + 1
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      def inc_future(x):
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return Future(value=x + 1)
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    fortytwo().Then(inc).Get()                         ==> 43
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    fortytwo().Then(inc_future).Get()                  ==> 43
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    fortytwo().Then(inc_future).Then(inc_future).Get() ==> 44
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    '''
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def then():
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      val = None
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      try:
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        val = self.Get()
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      except Exception as e:
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        val = error_handler(e)
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      else:
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        val = callback(val)
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return val.Get() if isinstance(val, Future) else val
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return Future(callback=then)
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Get(self):
118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    '''Gets the stored value, error, or callback contents.
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    '''
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._value is not _no_value:
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self._value
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if self._exc_info is not None:
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self._Raise()
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      self._value = self._callback()
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return self._value
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    except:
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self._exc_info = sys.exc_info()
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self._Raise()
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def _Raise(self):
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    exc_info = self._exc_info
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    raise exc_info[0], exc_info[1], exc_info[2]
134