Adding the orphaned options pages to the navigation
[chromium-blink-merge.git] / chrome / common / extensions / docs / server2 / future.py
blob289761c43d301162fc76a469ea36e54f8a98e9eb
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 import logging
6 import sys
7 import traceback
9 _no_value = object()
12 def _DefaultErrorHandler(error):
13 raise error
16 def All(futures, except_pass=None, except_pass_log=False):
17 '''Creates a Future which returns a list of results from each Future in
18 |futures|.
20 If any Future raises an error other than those in |except_pass| the returned
21 Future will raise as well.
23 If any Future raises an error in |except_pass| then None will be inserted as
24 its result. If |except_pass_log| is True then the exception will be logged.
25 '''
26 def resolve():
27 resolved = []
28 for f in futures:
29 try:
30 resolved.append(f.Get())
31 # "except None" will simply not catch any errors.
32 except except_pass:
33 if except_pass_log:
34 logging.error(traceback.format_exc())
35 resolved.append(None)
36 pass
37 return resolved
38 return Future(callback=resolve)
41 def Race(futures, except_pass=None, default=_no_value):
42 '''Returns a Future which resolves to the first Future in |futures| that
43 either succeeds or throws an error apart from those in |except_pass|.
45 If all Futures throw errors in |except_pass| then |default| is returned,
46 if specified. If |default| is not specified then one of the passed errors
47 will be re-thrown, for a nice stack trace.
48 '''
49 def resolve():
50 first_future = None
51 for future in futures:
52 if first_future is None:
53 first_future = future
54 try:
55 return future.Get()
56 # "except None" will simply not catch any errors.
57 except except_pass:
58 pass
59 if default is not _no_value:
60 return default
61 # Everything failed and there is no default value, propagate the first
62 # error even though it was caught by |except_pass|.
63 return first_future.Get()
64 return Future(callback=resolve)
67 class Future(object):
68 '''Stores a value, error, or callback to be used later.
69 '''
70 def __init__(self, value=_no_value, callback=None, exc_info=None):
71 self._value = value
72 self._callback = callback
73 self._exc_info = exc_info
74 if (self._value is _no_value and
75 self._callback is None and
76 self._exc_info is None):
77 raise ValueError('Must have either a value, error, or callback.')
79 def Then(self, callback, error_handler=_DefaultErrorHandler):
80 '''Creates and returns a future that runs |callback| on the value of this
81 future, or runs optional |error_handler| if resolving this future results in
82 an exception.
84 If |callback| returns a non-Future value then the returned Future will
85 resolve to that value.
87 If |callback| returns a Future then it gets chained to the current Future.
88 This means that the returned Future will resolve to *that* Future's value.
89 This behaviour is transitive.
91 For example,
93 def fortytwo():
94 return Future(value=42)
96 def inc(x):
97 return x + 1
99 def inc_future(x):
100 return Future(value=x + 1)
102 fortytwo().Then(inc).Get() ==> 43
103 fortytwo().Then(inc_future).Get() ==> 43
104 fortytwo().Then(inc_future).Then(inc_future).Get() ==> 44
106 def then():
107 val = None
108 try:
109 val = self.Get()
110 except Exception as e:
111 val = error_handler(e)
112 else:
113 val = callback(val)
114 return val.Get() if isinstance(val, Future) else val
115 return Future(callback=then)
117 def Get(self):
118 '''Gets the stored value, error, or callback contents.
120 if self._value is not _no_value:
121 return self._value
122 if self._exc_info is not None:
123 self._Raise()
124 try:
125 self._value = self._callback()
126 return self._value
127 except:
128 self._exc_info = sys.exc_info()
129 self._Raise()
131 def _Raise(self):
132 exc_info = self._exc_info
133 raise exc_info[0], exc_info[1], exc_info[2]