Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(513)

Side by Side Diff: chrome/common/extensions/docs/server2/api_data_source.py

Issue 18323018: Linking AvailabilityFinder with APIDataSource and intro-table templates. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import copy 5 import copy
6 import json as json_library
not at google - send to devlin 2013/07/03 19:54:56 not used?
epeterson 2013/07/09 20:51:18 Done.
6 import logging 7 import logging
7 import os 8 import os
8 from collections import defaultdict, Mapping 9 from collections import defaultdict, Mapping
9 10
11 import svn_constants
10 import third_party.json_schema_compiler.json_parse as json_parse 12 import third_party.json_schema_compiler.json_parse as json_parse
11 import third_party.json_schema_compiler.model as model 13 import third_party.json_schema_compiler.model as model
12 import third_party.json_schema_compiler.idl_schema as idl_schema 14 import third_party.json_schema_compiler.idl_schema as idl_schema
13 import third_party.json_schema_compiler.idl_parser as idl_parser 15 import third_party.json_schema_compiler.idl_parser as idl_parser
14 16
15 def _RemoveNoDocs(item): 17 def _RemoveNoDocs(item):
16 if json_parse.IsDict(item): 18 if json_parse.IsDict(item):
17 if item.get('nodoc', False): 19 if item.get('nodoc', False):
18 return True 20 return True
19 for key, value in item.items(): 21 for key, value in item.items():
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 def _FormatValue(value): 98 def _FormatValue(value):
97 """Inserts commas every three digits for integer values. It is magic. 99 """Inserts commas every three digits for integer values. It is magic.
98 """ 100 """
99 s = str(value) 101 s = str(value)
100 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) 102 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1])
101 103
102 class _JSCModel(object): 104 class _JSCModel(object):
103 """Uses a Model from the JSON Schema Compiler and generates a dict that 105 """Uses a Model from the JSON Schema Compiler and generates a dict that
104 a Handlebar template can use for a data source. 106 a Handlebar template can use for a data source.
105 """ 107 """
106 def __init__(self, json, ref_resolver, disable_refs, idl=False): 108 def __init__(self,
109 json,
110 ref_resolver,
111 disable_refs,
112 availability_finder,
113 intro_cache,
114 idl=False):
107 self._ref_resolver = ref_resolver 115 self._ref_resolver = ref_resolver
108 self._disable_refs = disable_refs 116 self._disable_refs = disable_refs
117 self._availability_finder = availability_finder
118 self._intro_tables = intro_cache.GetFromFile(
119 '%s/intro_tables.json' % svn_constants.JSON_PATH)
109 clean_json = copy.deepcopy(json) 120 clean_json = copy.deepcopy(json)
110 if _RemoveNoDocs(clean_json): 121 if _RemoveNoDocs(clean_json):
111 self._namespace = None 122 self._namespace = None
112 else: 123 else:
113 if idl: 124 if idl:
114 _DetectInlineableTypes(clean_json) 125 _DetectInlineableTypes(clean_json)
115 _InlineDocs(clean_json) 126 _InlineDocs(clean_json)
116 self._namespace = model.Namespace(clean_json, clean_json['namespace']) 127 self._namespace = model.Namespace(clean_json, clean_json['namespace'])
117 128
118 def _FormatDescription(self, description): 129 def _FormatDescription(self, description):
119 if self._disable_refs: 130 if self._disable_refs:
120 return description 131 return description
121 return self._ref_resolver.ResolveAllLinks(description, 132 return self._ref_resolver.ResolveAllLinks(description,
122 namespace=self._namespace.name) 133 namespace=self._namespace.name)
123 134
124 def _GetLink(self, link): 135 def _GetLink(self, link):
125 if self._disable_refs: 136 if self._disable_refs:
126 type_name = link.split('.', 1)[-1] 137 type_name = link.split('.', 1)[-1]
127 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link } 138 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link }
128 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name) 139 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name)
129 140
130 def ToDict(self): 141 def ToDict(self):
131 if self._namespace is None: 142 if self._namespace is None:
132 return {} 143 return {}
133 return { 144 return {
134 'name': self._namespace.name, 145 'name': self._namespace.name,
135 'description': self._namespace.description, 146 'description': self._namespace.description,
147 'availability': self._GetApiAvailability(),
148 'experimental': self._CheckExperimental(),
149 'api_permissions': self._GetPermissions(),
150 'learn_more': self._GetMoreLearning(),
136 'types': self._GenerateTypes(self._namespace.types.values()), 151 'types': self._GenerateTypes(self._namespace.types.values()),
137 'functions': self._GenerateFunctions(self._namespace.functions), 152 'functions': self._GenerateFunctions(self._namespace.functions),
138 'events': self._GenerateEvents(self._namespace.events), 153 'events': self._GenerateEvents(self._namespace.events),
139 'properties': self._GenerateProperties(self._namespace.properties) 154 'properties': self._GenerateProperties(self._namespace.properties)
140 } 155 }
141 156
157 def _GetApiAvailability(self):
158 """Finds the earliest stable version of chrome where an API was available
159 using AvailabilityFinder. If an API hasn't been released to stable yet,
160 then the development channel that the API is currently available on will
161 be returned instead.
162 """
163 if not self._CheckExperimental():
164 availability = self._availability_finder.GetApiAvailability(
165 self._namespace.name)
166 if availability:
167 if availability.channel == 'stable':
168 return availability.version
169 return availability.channel
170 # A special message for experimental APIs' availability will be displayed.
171 return None
not at google - send to devlin 2013/07/03 19:54:56 invert the condition here: if self._CheckExperime
epeterson 2013/07/09 20:51:18 Done.
172
173 def _CheckExperimental(self):
not at google - send to devlin 2013/07/03 19:54:56 IsExperimental
epeterson 2013/07/09 20:51:18 Done.
174 return self._namespace.name.startswith('experimental')
175
176 def _GetPermissions(self):
177 """This is a temporary fix for generating API intro tables automatically.
178 Information on an API's permissions is pulled from a json file so that it
179 can be sent to the templates along with other relevant intro data.
180 """
181 table_info = self._intro_tables.get(self._namespace.name)
182 return table_info.get('Permissions') if table_info else None
183
184 def _GetMoreLearning(self):
not at google - send to devlin 2013/07/08 17:08:02 Update: this actually needs to be more generic. Se
185 """We can't automatically generate the "Learn more" field in an API's.
186 intro table; instead, we pull it from a json file so that it can be sent to
187 the templates along with other relevant intro data.
188 """
189 table_info = self._intro_tables.get(self._namespace.name)
190 return table_info.get('LearnMore') if table_info else None
191
142 def _GenerateTypes(self, types): 192 def _GenerateTypes(self, types):
143 return [self._GenerateType(t) for t in types] 193 return [self._GenerateType(t) for t in types]
144 194
145 def _GenerateType(self, type_): 195 def _GenerateType(self, type_):
146 type_dict = { 196 type_dict = {
147 'name': type_.simple_name, 197 'name': type_.simple_name,
148 'description': self._FormatDescription(type_.description), 198 'description': self._FormatDescription(type_.description),
149 'properties': self._GenerateProperties(type_.properties), 199 'properties': self._GenerateProperties(type_.properties),
150 'functions': self._GenerateFunctions(type_.functions), 200 'functions': self._GenerateFunctions(type_.functions),
151 'events': self._GenerateEvents(type_.events), 201 'events': self._GenerateEvents(type_.events),
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 self._samples = samples 368 self._samples = samples
319 369
320 def get(self, key): 370 def get(self, key):
321 return self._samples.FilterSamples(key, self._api_name) 371 return self._samples.FilterSamples(key, self._api_name)
322 372
323 class APIDataSource(object): 373 class APIDataSource(object):
324 """This class fetches and loads JSON APIs from the FileSystem passed in with 374 """This class fetches and loads JSON APIs from the FileSystem passed in with
325 |compiled_fs_factory|, so the APIs can be plugged into templates. 375 |compiled_fs_factory|, so the APIs can be plugged into templates.
326 """ 376 """
327 class Factory(object): 377 class Factory(object):
328 def __init__(self, compiled_fs_factory, base_path): 378 def __init__(self,
379 compiled_fs_factory,
380 base_path,
381 availability_finder_factory):
329 def create_compiled_fs(fn, category): 382 def create_compiled_fs(fn, category):
330 return compiled_fs_factory.Create(fn, APIDataSource, category=category) 383 return compiled_fs_factory.Create(fn, APIDataSource, category=category)
331 384
332 self._permissions_cache = create_compiled_fs(self._LoadPermissions, 385 self._permissions_cache = create_compiled_fs(self._LoadPermissions,
333 'permissions') 386 'permissions')
334 387
335 self._json_cache = create_compiled_fs( 388 self._json_cache = create_compiled_fs(
336 lambda api_name, api: self._LoadJsonAPI(api, False), 389 lambda api_name, api: self._LoadJsonAPI(api, False),
337 'json') 390 'json')
338 self._idl_cache = create_compiled_fs( 391 self._idl_cache = create_compiled_fs(
339 lambda api_name, api: self._LoadIdlAPI(api, False), 392 lambda api_name, api: self._LoadIdlAPI(api, False),
340 'idl') 393 'idl')
341 394
342 # These caches are used if an APIDataSource does not want to resolve the 395 # These caches are used if an APIDataSource does not want to resolve the
343 # $refs in an API. This is needed to prevent infinite recursion in 396 # $refs in an API. This is needed to prevent infinite recursion in
344 # ReferenceResolver. 397 # ReferenceResolver.
345 self._json_cache_no_refs = create_compiled_fs( 398 self._json_cache_no_refs = create_compiled_fs(
346 lambda api_name, api: self._LoadJsonAPI(api, True), 399 lambda api_name, api: self._LoadJsonAPI(api, True),
347 'json-no-refs') 400 'json-no-refs')
348 self._idl_cache_no_refs = create_compiled_fs( 401 self._idl_cache_no_refs = create_compiled_fs(
349 lambda api_name, api: self._LoadIdlAPI(api, True), 402 lambda api_name, api: self._LoadIdlAPI(api, True),
350 'idl-no-refs') 403 'idl-no-refs')
351 404
352 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names') 405 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names')
353 self._names_cache = create_compiled_fs(self._GetAllNames, 'names') 406 self._names_cache = create_compiled_fs(self._GetAllNames, 'names')
354 407
355 self._base_path = base_path 408 self._base_path = base_path
356 409 self._availability_finder = availability_finder_factory.Create()
410 self._intro_cache = create_compiled_fs(
411 lambda _, json: json_parse.Parse(json),
412 'intro-cache')
357 # These must be set later via the SetFooDataSourceFactory methods. 413 # These must be set later via the SetFooDataSourceFactory methods.
358 self._ref_resolver_factory = None 414 self._ref_resolver_factory = None
359 self._samples_data_source_factory = None 415 self._samples_data_source_factory = None
360 416
361 def SetSamplesDataSourceFactory(self, samples_data_source_factory): 417 def SetSamplesDataSourceFactory(self, samples_data_source_factory):
362 self._samples_data_source_factory = samples_data_source_factory 418 self._samples_data_source_factory = samples_data_source_factory
363 419
364 def SetReferenceResolverFactory(self, ref_resolver_factory): 420 def SetReferenceResolverFactory(self, ref_resolver_factory):
365 self._ref_resolver_factory = ref_resolver_factory 421 self._ref_resolver_factory = ref_resolver_factory
366 422
(...skipping 25 matching lines...) Expand all
392 samples, 448 samples,
393 disable_refs) 449 disable_refs)
394 450
395 def _LoadPermissions(self, file_name, json_str): 451 def _LoadPermissions(self, file_name, json_str):
396 return json_parse.Parse(json_str) 452 return json_parse.Parse(json_str)
397 453
398 def _LoadJsonAPI(self, api, disable_refs): 454 def _LoadJsonAPI(self, api, disable_refs):
399 return _JSCModel( 455 return _JSCModel(
400 json_parse.Parse(api)[0], 456 json_parse.Parse(api)[0],
401 self._ref_resolver_factory.Create() if not disable_refs else None, 457 self._ref_resolver_factory.Create() if not disable_refs else None,
402 disable_refs).ToDict() 458 disable_refs,
459 self._availability_finder,
460 self._intro_cache).ToDict()
403 461
404 def _LoadIdlAPI(self, api, disable_refs): 462 def _LoadIdlAPI(self, api, disable_refs):
405 idl = idl_parser.IDLParser().ParseData(api) 463 idl = idl_parser.IDLParser().ParseData(api)
406 return _JSCModel( 464 return _JSCModel(
407 idl_schema.IDLSchema(idl).process()[0], 465 idl_schema.IDLSchema(idl).process()[0],
408 self._ref_resolver_factory.Create() if not disable_refs else None, 466 self._ref_resolver_factory.Create() if not disable_refs else None,
409 disable_refs, 467 disable_refs,
468 self._availability_finder,
469 self._intro_cache,
410 idl=True).ToDict() 470 idl=True).ToDict()
411 471
412 def _GetIDLNames(self, base_dir, apis): 472 def _GetIDLNames(self, base_dir, apis):
413 return self._GetExtNames(apis, ['idl']) 473 return self._GetExtNames(apis, ['idl'])
414 474
415 def _GetAllNames(self, base_dir, apis): 475 def _GetAllNames(self, base_dir, apis):
416 return self._GetExtNames(apis, ['json', 'idl']) 476 return self._GetExtNames(apis, ['json', 'idl'])
417 477
418 def _GetExtNames(self, apis, exts): 478 def _GetExtNames(self, apis, exts):
419 return [model.UnixName(os.path.splitext(api)[0]) for api in apis 479 return [model.UnixName(os.path.splitext(api)[0]) for api in apis
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 return feature_data 537 return feature_data
478 538
479 def _GenerateHandlebarContext(self, handlebar_dict, path): 539 def _GenerateHandlebarContext(self, handlebar_dict, path):
480 handlebar_dict['permissions'] = self._GetFeatureData(path) 540 handlebar_dict['permissions'] = self._GetFeatureData(path)
481 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples) 541 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples)
482 return handlebar_dict 542 return handlebar_dict
483 543
484 def _GetAsSubdirectory(self, name): 544 def _GetAsSubdirectory(self, name):
485 if name.startswith('experimental_'): 545 if name.startswith('experimental_'):
486 parts = name[len('experimental_'):].split('_', 1) 546 parts = name[len('experimental_'):].split('_', 1)
487 parts[1] = 'experimental_%s' % parts[1] 547 if len(parts) > 1:
488 return '/'.join(parts) 548 parts[1] = 'experimental_%s' % parts[1]
549 return '/'.join(parts)
550 return '%s/%s' % (parts[0], name)
489 return name.replace('_', '/', 1) 551 return name.replace('_', '/', 1)
490 552
491 def get(self, key): 553 def get(self, key):
492 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'): 554 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'):
493 path, ext = os.path.splitext(key) 555 path, ext = os.path.splitext(key)
494 else: 556 else:
495 path = key 557 path = key
496 unix_name = model.UnixName(path) 558 unix_name = model.UnixName(path)
497 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path) 559 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path)
498 names = self._names_cache.GetFromFileListing(self._base_path) 560 names = self._names_cache.GetFromFileListing(self._base_path)
499 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names: 561 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names:
500 unix_name = self._GetAsSubdirectory(unix_name) 562 unix_name = self._GetAsSubdirectory(unix_name)
501 563
502 if self._disable_refs: 564 if self._disable_refs:
503 cache, ext = ( 565 cache, ext = (
504 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else 566 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else
505 (self._json_cache_no_refs, '.json')) 567 (self._json_cache_no_refs, '.json'))
506 else: 568 else:
507 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else 569 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else
508 (self._json_cache, '.json')) 570 (self._json_cache, '.json'))
509 return self._GenerateHandlebarContext( 571 return self._GenerateHandlebarContext(
510 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)), 572 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)),
511 path) 573 path)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698