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

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

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