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

Side by Side Diff: tools/telemetry/telemetry/core/discover.py

Issue 1263063003: Revert of Create classes_util API, change discover to return a list instead of a dict. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 4 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 2012 The Chromium Authors. All rights reserved. 1 # Copyright 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 fnmatch 5 import fnmatch
6 import inspect 6 import inspect
7 import os 7 import os
8 import re 8 import re
9 9
10 from telemetry import decorators
11 from telemetry.internal.util import camel_case
10 from telemetry.internal.util import classes as classes_module 12 from telemetry.internal.util import classes as classes_module
11 13
12 14
15 @decorators.Cache
13 def DiscoverModules(start_dir, top_level_dir, pattern='*'): 16 def DiscoverModules(start_dir, top_level_dir, pattern='*'):
14 """Discover all modules in |start_dir| which match |pattern|. 17 """Discover all modules in |start_dir| which match |pattern|.
15 18
16 Args: 19 Args:
17 start_dir: The directory to recursively search. 20 start_dir: The directory to recursively search.
18 top_level_dir: The top level of the package, for importing. 21 top_level_dir: The top level of the package, for importing.
19 pattern: Unix shell-style pattern for filtering the filenames to import. 22 pattern: Unix shell-style pattern for filtering the filenames to import.
20 23
21 Returns: 24 Returns:
22 list of modules. 25 list of modules.
(...skipping 16 matching lines...) Expand all
39 # Find the module. 42 # Find the module.
40 module_rel_path = os.path.relpath(os.path.join(dir_path, filename), 43 module_rel_path = os.path.relpath(os.path.join(dir_path, filename),
41 top_level_dir) 44 top_level_dir)
42 module_name = re.sub(r'[/\\]', '.', os.path.splitext(module_rel_path)[0]) 45 module_name = re.sub(r'[/\\]', '.', os.path.splitext(module_rel_path)[0])
43 46
44 # Import the module. 47 # Import the module.
45 module = __import__(module_name, fromlist=[True]) 48 module = __import__(module_name, fromlist=[True])
46 modules.append(module) 49 modules.append(module)
47 return modules 50 return modules
48 51
52
53 # TODO(dtu): Normalize all discoverable classes to have corresponding module
54 # and class names, then always index by class name.
55 @decorators.Cache
49 def DiscoverClasses(start_dir, top_level_dir, base_class, pattern='*', 56 def DiscoverClasses(start_dir, top_level_dir, base_class, pattern='*',
50 one_class_per_module=False, directly_constructable=False): 57 index_by_class_name=True, directly_constructable=False):
51 """Discover all classes in |start_dir| which subclass |base_class|. 58 """Discover all classes in |start_dir| which subclass |base_class|.
52 59
53 Base classes that contain subclasses are ignored by default. 60 Base classes that contain subclasses are ignored by default.
54 61
55 Args: 62 Args:
56 start_dir: The directory to recursively search. 63 start_dir: The directory to recursively search.
57 top_level_dir: The top level of the package, for importing. 64 top_level_dir: The top level of the package, for importing.
58 base_class: The base class to search for. 65 base_class: The base class to search for.
59 pattern: Unix shell-style pattern for filtering the filenames to import. 66 pattern: Unix shell-style pattern for filtering the filenames to import.
60 one_class_per_module: If True, will only include the first class found in 67 index_by_class_name: If True, use class name converted to
61 each module. 68 lowercase_with_underscores instead of module name in return dict keys.
62 directly_constructable: If True, will only return classes that can be 69 directly_constructable: If True, will only return classes that can be
63 constructed without arguments 70 constructed without arguments
64 71
65 Returns: A list of classes. 72 Returns:
73 dict of {module_name: class} or {underscored_class_name: class}
66 """ 74 """
67 modules = DiscoverModules(start_dir, top_level_dir, pattern) 75 modules = DiscoverModules(start_dir, top_level_dir, pattern)
68 classes = [] 76 classes = {}
69 for module in modules: 77 for module in modules:
70 classes.extend(DiscoverClassesInModule( 78 new_classes = DiscoverClassesInModule(
71 module, base_class, one_class_per_module, directly_constructable)) 79 module, base_class, index_by_class_name, directly_constructable)
80 classes = dict(classes.items() + new_classes.items())
72 return classes 81 return classes
73 82
74 def DiscoverClassesInModule(module, base_class, one_class_per_module=False, 83 @decorators.Cache
84 def DiscoverClassesInModule(module, base_class, index_by_class_name=False,
75 directly_constructable=False): 85 directly_constructable=False):
76 """Discover all classes in |module| which subclass |base_class|. 86 """Discover all classes in |module| which subclass |base_class|.
77 87
78 Base classes that contain subclasses are ignored by default. 88 Base classes that contain subclasses are ignored by default.
79 89
80 Args: 90 Args:
81 module: The module to search. 91 module: The module to search.
82 base_class: The base class to search for. 92 base_class: The base class to search for.
83 one_class_per_module: If True, will only include the first class found in 93 index_by_class_name: If True, use class name converted to
84 each module. 94 lowercase_with_underscores instead of module name in return dict keys.
85 95
86 Returns: A list of classes. 96 Returns:
97 dict of {module_name: class} or {underscored_class_name: class}
87 """ 98 """
88 classes = [] 99 classes = {}
89 for _, obj in inspect.getmembers(module): 100 for _, obj in inspect.getmembers(module):
90 # Ensure object is a class. 101 # Ensure object is a class.
91 if not inspect.isclass(obj): 102 if not inspect.isclass(obj):
92 continue 103 continue
93 # Include only subclasses of base_class. 104 # Include only subclasses of base_class.
94 if not issubclass(obj, base_class): 105 if not issubclass(obj, base_class):
95 continue 106 continue
96 # Exclude the base_class itself. 107 # Exclude the base_class itself.
97 if obj is base_class: 108 if obj is base_class:
98 continue 109 continue
99 # Exclude protected or private classes. 110 # Exclude protected or private classes.
100 if obj.__name__.startswith('_'): 111 if obj.__name__.startswith('_'):
101 continue 112 continue
102 # Include only the module in which the class is defined. 113 # Include only the module in which the class is defined.
103 # If a class is imported by another module, exclude those duplicates. 114 # If a class is imported by another module, exclude those duplicates.
104 if obj.__module__ != module.__name__: 115 if obj.__module__ != module.__name__:
105 continue 116 continue
106 117
118 if index_by_class_name:
119 key_name = camel_case.ToUnderscore(obj.__name__)
120 else:
121 key_name = module.__name__.split('.')[-1]
107 if (not directly_constructable or 122 if (not directly_constructable or
108 classes_module.IsDirectlyConstructable(obj)): 123 classes_module.IsDirectlyConstructable(obj)):
109 classes.append(obj) 124 classes[key_name] = obj
110 if one_class_per_module: 125
111 return classes
112 return classes 126 return classes
113 127
114 128
115 _counter = [0] 129 _counter = [0]
116 def _GetUniqueModuleName(): 130 def _GetUniqueModuleName():
117 _counter[0] += 1 131 _counter[0] += 1
118 return "module_" + str(_counter[0]) 132 return "module_" + str(_counter[0])
OLDNEW
« no previous file with comments | « tools/telemetry/telemetry/benchmark_runner.py ('k') | tools/telemetry/telemetry/core/discover_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698