Commit 971b0bf6 authored by kalman@chromium.org's avatar kalman@chromium.org

Convert APIListDataSource to use Future.Then() rather than Get().

I needed to change the behaviour of Future.Then() to implement this.

BUG=306341
R=yoz@chromium.org
NOTRY=true

Review URL: https://codereview.chromium.org/438403002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287633 0039d316-1c4b-4281-b951-d872f2087c98
parent 986ee1a7
...@@ -32,22 +32,24 @@ class APIListDataSource(DataSource): ...@@ -32,22 +32,24 @@ class APIListDataSource(DataSource):
def _GenerateAPIDict(self): def _GenerateAPIDict(self):
def make_list_for_content_scripts(): def make_list_for_content_scripts():
content_script_apis = self._platform_bundle.GetAPIModels( def convert_to_list(content_script_apis):
'extensions').GetContentScriptAPIs().Get() content_script_apis_list = [csa.__dict__ for api_name, csa
content_script_apis_list = [csa.__dict__ for api_name, csa in content_script_apis.iteritems()
in content_script_apis.iteritems() if self._platform_bundle.GetAPICategorizer(
if self._platform_bundle.GetAPICategorizer( 'extensions').IsDocumented(api_name)]
'extensions').IsDocumented(api_name)] content_script_apis_list.sort(key=itemgetter('name'))
for csa in content_script_apis_list:
restricted_nodes = csa['restrictedTo']
if restricted_nodes:
restricted_nodes.sort(key=itemgetter('node'))
MarkFirstAndLast(restricted_nodes)
else:
del csa['restrictedTo']
return content_script_apis_list
content_script_apis_list.sort(key=itemgetter('name')) return (self._platform_bundle.GetAPIModels('extensions')
for csa in content_script_apis_list: .GetContentScriptAPIs()
restricted_nodes = csa['restrictedTo'] .Then(convert_to_list))
if restricted_nodes:
restricted_nodes.sort(key=itemgetter('node'))
MarkFirstAndLast(restricted_nodes)
else:
del csa['restrictedTo']
return content_script_apis_list
def make_dict_for_platform(platform): def make_dict_for_platform(platform):
platform_dict = { platform_dict = {
...@@ -95,20 +97,24 @@ class APIListDataSource(DataSource): ...@@ -95,20 +97,24 @@ class APIListDataSource(DataSource):
platform_dict[key] = apis platform_dict[key] = apis
return platform_dict return platform_dict
api_dict = dict((platform, make_dict_for_platform(platform))
for platform in GetPlatforms()) def make_api_dict(content_script_apis):
api_dict['contentScripts'] = make_list_for_content_scripts() api_dict = dict((platform, make_dict_for_platform(platform))
return api_dict for platform in GetPlatforms())
api_dict['contentScripts'] = content_script_apis
return api_dict
return make_list_for_content_scripts().Then(make_api_dict)
def _GetCachedAPIData(self): def _GetCachedAPIData(self):
data_future = self._object_store.Get('api_data') def persist_and_return(data):
def resolve(): self._object_store.Set('api_data', data)
data = data_future.Get() return data
def return_or_generate(data):
if data is None: if data is None:
data = self._GenerateAPIDict() return self._GenerateAPIDict().Then(persist_and_return)
self._object_store.Set('api_data', data)
return data return data
return Future(callback=resolve) return self._object_store.Get('api_data').Then(return_or_generate)
def get(self, key): def get(self, key):
return self._GetCachedAPIData().Get().get(key) return self._GetCachedAPIData().Get().get(key)
......
application: chrome-apps-doc application: chrome-apps-doc
version: 3-39-0 version: 3-39-1
runtime: python27 runtime: python27
api_version: 1 api_version: 1
threadsafe: false threadsafe: false
......
...@@ -2,4 +2,4 @@ cron: ...@@ -2,4 +2,4 @@ cron:
- description: Repopulates all cached data. - description: Repopulates all cached data.
url: /_cron url: /_cron
schedule: every 5 minutes schedule: every 5 minutes
target: 3-39-0 target: 3-39-1
...@@ -69,13 +69,38 @@ class Future(object): ...@@ -69,13 +69,38 @@ class Future(object):
'''Creates and returns a future that runs |callback| on the value of this '''Creates and returns a future that runs |callback| on the value of this
future, or runs optional |error_handler| if resolving this future results in future, or runs optional |error_handler| if resolving this future results in
an exception. an exception.
If |callback| returns a non-Future value then the returned Future will
resolve to that value.
If |callback| returns a Future then it gets chained to the current Future.
This means that the returned Future will resolve to *that* Future's value.
This behaviour is transitive.
For example,
def fortytwo():
return Future(value=42)
def inc(x):
return x + 1
def inc_future(x):
return Future(value=x + 1)
fortytwo().Then(inc).Get() ==> 43
fortytwo().Then(inc_future).Get() ==> 43
fortytwo().Then(inc_future).Then(inc_future).Get() ==> 44
''' '''
def then(): def then():
val = None
try: try:
val = self.Get() val = self.Get()
except Exception as e: except Exception as e:
return error_handler(e) val = error_handler(e)
return callback(val) else:
val = callback(val)
return val.Get() if isinstance(val, Future) else val
return Future(callback=then) return Future(callback=then)
def Get(self): def Get(self):
......
...@@ -161,11 +161,12 @@ class FutureTest(unittest.TestCase): ...@@ -161,11 +161,12 @@ class FutureTest(unittest.TestCase):
def testThen(self): def testThen(self):
def assertIs42(val): def assertIs42(val):
self.assertEquals(val, 42) self.assertEqual(val, 42)
return val
then = Future(value=42).Then(assertIs42) then = Future(value=42).Then(assertIs42)
# Shouldn't raise an error. # Shouldn't raise an error.
then.Get() self.assertEqual(42, then.Get())
# Test raising an error. # Test raising an error.
then = Future(value=41).Then(assertIs42) then = Future(value=41).Then(assertIs42)
...@@ -184,7 +185,7 @@ class FutureTest(unittest.TestCase): ...@@ -184,7 +185,7 @@ class FutureTest(unittest.TestCase):
raise Exception raise Exception
then = Future(callback=raiseValueError).Then(assertIs42, handle) then = Future(callback=raiseValueError).Then(assertIs42, handle)
self.assertEquals(then.Get(), 'Caught') self.assertEqual('Caught', then.Get())
then = Future(callback=raiseException).Then(assertIs42, handle) then = Future(callback=raiseException).Then(assertIs42, handle)
self.assertRaises(Exception, then.Get) self.assertRaises(Exception, then.Get)
...@@ -192,7 +193,7 @@ class FutureTest(unittest.TestCase): ...@@ -192,7 +193,7 @@ class FutureTest(unittest.TestCase):
addOne = lambda val: val + 1 addOne = lambda val: val + 1
then = Future(value=40).Then(addOne).Then(addOne).Then(assertIs42) then = Future(value=40).Then(addOne).Then(addOne).Then(assertIs42)
# Shouldn't raise an error. # Shouldn't raise an error.
then.Get() self.assertEqual(42, then.Get())
# Test error in chain. # Test error in chain.
then = Future(value=40).Then(addOne).Then(assertIs42).Then(addOne) then = Future(value=40).Then(addOne).Then(assertIs42).Then(addOne)
...@@ -216,6 +217,46 @@ class FutureTest(unittest.TestCase): ...@@ -216,6 +217,46 @@ class FutureTest(unittest.TestCase):
myHandle) myHandle)
self.assertEquals(then.Get(), 10) self.assertEquals(then.Get(), 10)
def testThenResolvesReturnedFutures(self):
def returnsFortyTwo():
return Future(value=42)
def inc(x):
return x + 1
def incFuture(x):
return Future(value=x + 1)
self.assertEqual(43, returnsFortyTwo().Then(inc).Get())
self.assertEqual(43, returnsFortyTwo().Then(incFuture).Get())
self.assertEqual(44, returnsFortyTwo().Then(inc).Then(inc).Get())
self.assertEqual(44, returnsFortyTwo().Then(inc).Then(incFuture).Get())
self.assertEqual(44, returnsFortyTwo().Then(incFuture).Then(inc).Get())
self.assertEqual(
44, returnsFortyTwo().Then(incFuture).Then(incFuture).Get())
# The same behaviour should apply to error handlers.
def raisesSomething():
def boom(): raise ValueError
return Future(callback=boom)
def shouldNotHappen(_):
raise AssertionError()
def oops(error):
return 'oops'
def oopsFuture(error):
return Future(value='oops')
self.assertEqual(
'oops', raisesSomething().Then(shouldNotHappen, oops).Get())
self.assertEqual(
'oops', raisesSomething().Then(shouldNotHappen, oopsFuture).Get())
self.assertEqual(
'oops',
raisesSomething().Then(shouldNotHappen, raisesSomething)
.Then(shouldNotHappen, oops).Get())
self.assertEqual(
'oops',
raisesSomething().Then(shouldNotHappen, raisesSomething)
.Then(shouldNotHappen, oopsFuture).Get())
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment