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):
def _GenerateAPIDict(self):
def make_list_for_content_scripts():
content_script_apis = self._platform_bundle.GetAPIModels(
'extensions').GetContentScriptAPIs().Get()
content_script_apis_list = [csa.__dict__ for api_name, csa
in content_script_apis.iteritems()
if self._platform_bundle.GetAPICategorizer(
'extensions').IsDocumented(api_name)]
def convert_to_list(content_script_apis):
content_script_apis_list = [csa.__dict__ for api_name, csa
in content_script_apis.iteritems()
if self._platform_bundle.GetAPICategorizer(
'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'))
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
return (self._platform_bundle.GetAPIModels('extensions')
.GetContentScriptAPIs()
.Then(convert_to_list))
def make_dict_for_platform(platform):
platform_dict = {
......@@ -95,20 +97,24 @@ class APIListDataSource(DataSource):
platform_dict[key] = apis
return platform_dict
api_dict = dict((platform, make_dict_for_platform(platform))
for platform in GetPlatforms())
api_dict['contentScripts'] = make_list_for_content_scripts()
return api_dict
def make_api_dict(content_script_apis):
api_dict = dict((platform, make_dict_for_platform(platform))
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):
data_future = self._object_store.Get('api_data')
def resolve():
data = data_future.Get()
def persist_and_return(data):
self._object_store.Set('api_data', data)
return data
def return_or_generate(data):
if data is None:
data = self._GenerateAPIDict()
self._object_store.Set('api_data', data)
return self._GenerateAPIDict().Then(persist_and_return)
return data
return Future(callback=resolve)
return self._object_store.Get('api_data').Then(return_or_generate)
def get(self, key):
return self._GetCachedAPIData().Get().get(key)
......
application: chrome-apps-doc
version: 3-39-0
version: 3-39-1
runtime: python27
api_version: 1
threadsafe: false
......
......@@ -2,4 +2,4 @@ cron:
- description: Repopulates all cached data.
url: /_cron
schedule: every 5 minutes
target: 3-39-0
target: 3-39-1
......@@ -69,13 +69,38 @@ class Future(object):
'''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
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():
val = None
try:
val = self.Get()
except Exception as e:
return error_handler(e)
return callback(val)
val = error_handler(e)
else:
val = callback(val)
return val.Get() if isinstance(val, Future) else val
return Future(callback=then)
def Get(self):
......
......@@ -161,11 +161,12 @@ class FutureTest(unittest.TestCase):
def testThen(self):
def assertIs42(val):
self.assertEquals(val, 42)
self.assertEqual(val, 42)
return val
then = Future(value=42).Then(assertIs42)
# Shouldn't raise an error.
then.Get()
self.assertEqual(42, then.Get())
# Test raising an error.
then = Future(value=41).Then(assertIs42)
......@@ -184,7 +185,7 @@ class FutureTest(unittest.TestCase):
raise Exception
then = Future(callback=raiseValueError).Then(assertIs42, handle)
self.assertEquals(then.Get(), 'Caught')
self.assertEqual('Caught', then.Get())
then = Future(callback=raiseException).Then(assertIs42, handle)
self.assertRaises(Exception, then.Get)
......@@ -192,7 +193,7 @@ class FutureTest(unittest.TestCase):
addOne = lambda val: val + 1
then = Future(value=40).Then(addOne).Then(addOne).Then(assertIs42)
# Shouldn't raise an error.
then.Get()
self.assertEqual(42, then.Get())
# Test error in chain.
then = Future(value=40).Then(addOne).Then(assertIs42).Then(addOne)
......@@ -216,6 +217,46 @@ class FutureTest(unittest.TestCase):
myHandle)
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__':
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