| Index: telemetry/telemetry/core/discover.py
|
| diff --git a/telemetry/telemetry/core/discover.py b/telemetry/telemetry/core/discover.py
|
| index 7e7e4306ef33c717d0ec88cf14c98761f8ce4c22..91a59a02457b782f2ecf8ee7b0bcaaa9270dba64 100644
|
| --- a/telemetry/telemetry/core/discover.py
|
| +++ b/telemetry/telemetry/core/discover.py
|
| @@ -1,190 +1,10 @@
|
| -# Copyright 2012 The Chromium Authors. All rights reserved.
|
| +# Copyright 2017 The Chromium Authors. All rights reserved.
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| -import fnmatch
|
| -import inspect
|
| -import os
|
| -import re
|
| -import sys
|
| +"""Shim for discover; will be removed once #3612 is fixed."""
|
|
|
| -from py_utils import camel_case
|
| +from py_utils import discover
|
|
|
| -
|
| -def DiscoverModules(start_dir, top_level_dir, pattern='*'):
|
| - """Discover all modules in |start_dir| which match |pattern|.
|
| -
|
| - Args:
|
| - start_dir: The directory to recursively search.
|
| - top_level_dir: The top level of the package, for importing.
|
| - pattern: Unix shell-style pattern for filtering the filenames to import.
|
| -
|
| - Returns:
|
| - list of modules.
|
| - """
|
| - # start_dir and top_level_dir must be consistent with each other.
|
| - start_dir = os.path.realpath(start_dir)
|
| - top_level_dir = os.path.realpath(top_level_dir)
|
| -
|
| - modules = []
|
| - sub_paths = list(os.walk(start_dir))
|
| - # We sort the directories & file paths to ensure a deterministic ordering when
|
| - # traversing |top_level_dir|.
|
| - sub_paths.sort(key=lambda paths_tuple: paths_tuple[0])
|
| - for dir_path, _, filenames in sub_paths:
|
| - # Sort the directories to walk recursively by the directory path.
|
| - filenames.sort()
|
| - for filename in filenames:
|
| - # Filter out unwanted filenames.
|
| - if filename.startswith('.') or filename.startswith('_'):
|
| - continue
|
| - if os.path.splitext(filename)[1] != '.py':
|
| - continue
|
| - if not fnmatch.fnmatch(filename, pattern):
|
| - continue
|
| -
|
| - # Find the module.
|
| - module_rel_path = os.path.relpath(
|
| - os.path.join(dir_path, filename), top_level_dir)
|
| - module_name = re.sub(r'[/\\]', '.', os.path.splitext(module_rel_path)[0])
|
| -
|
| - # Import the module.
|
| - try:
|
| - # Make sure that top_level_dir is the first path in the sys.path in case
|
| - # there are naming conflict in module parts.
|
| - original_sys_path = sys.path[:]
|
| - sys.path.insert(0, top_level_dir)
|
| - module = __import__(module_name, fromlist=[True])
|
| - modules.append(module)
|
| - finally:
|
| - sys.path = original_sys_path
|
| - return modules
|
| -
|
| -
|
| -def AssertNoKeyConflicts(classes_by_key_1, classes_by_key_2):
|
| - for k in classes_by_key_1:
|
| - if k in classes_by_key_2:
|
| - assert classes_by_key_1[k] is classes_by_key_2[k], (
|
| - 'Found conflicting classes for the same key: '
|
| - 'key=%s, class_1=%s, class_2=%s' % (
|
| - k, classes_by_key_1[k], classes_by_key_2[k]))
|
| -
|
| -
|
| -# TODO(dtu): Normalize all discoverable classes to have corresponding module
|
| -# and class names, then always index by class name.
|
| -def DiscoverClasses(start_dir,
|
| - top_level_dir,
|
| - base_class,
|
| - pattern='*',
|
| - index_by_class_name=True,
|
| - directly_constructable=False):
|
| - """Discover all classes in |start_dir| which subclass |base_class|.
|
| -
|
| - Base classes that contain subclasses are ignored by default.
|
| -
|
| - Args:
|
| - start_dir: The directory to recursively search.
|
| - top_level_dir: The top level of the package, for importing.
|
| - base_class: The base class to search for.
|
| - pattern: Unix shell-style pattern for filtering the filenames to import.
|
| - index_by_class_name: If True, use class name converted to
|
| - lowercase_with_underscores instead of module name in return dict keys.
|
| - directly_constructable: If True, will only return classes that can be
|
| - constructed without arguments
|
| -
|
| - Returns:
|
| - dict of {module_name: class} or {underscored_class_name: class}
|
| - """
|
| - modules = DiscoverModules(start_dir, top_level_dir, pattern)
|
| - classes = {}
|
| - for module in modules:
|
| - new_classes = DiscoverClassesInModule(
|
| - module, base_class, index_by_class_name, directly_constructable)
|
| - # TODO(nednguyen): we should remove index_by_class_name once
|
| - # benchmark_smoke_unittest in chromium/src/tools/perf no longer relied
|
| - # naming collisions to reduce the number of smoked benchmark tests.
|
| - # crbug.com/548652
|
| - if index_by_class_name:
|
| - AssertNoKeyConflicts(classes, new_classes)
|
| - classes = dict(classes.items() + new_classes.items())
|
| - return classes
|
| -
|
| -
|
| -# TODO(nednguyen): we should remove index_by_class_name once
|
| -# benchmark_smoke_unittest in chromium/src/tools/perf no longer relied
|
| -# naming collisions to reduce the number of smoked benchmark tests.
|
| -# crbug.com/548652
|
| -def DiscoverClassesInModule(module,
|
| - base_class,
|
| - index_by_class_name=False,
|
| - directly_constructable=False):
|
| - """Discover all classes in |module| which subclass |base_class|.
|
| -
|
| - Base classes that contain subclasses are ignored by default.
|
| -
|
| - Args:
|
| - module: The module to search.
|
| - base_class: The base class to search for.
|
| - index_by_class_name: If True, use class name converted to
|
| - lowercase_with_underscores instead of module name in return dict keys.
|
| -
|
| - Returns:
|
| - dict of {module_name: class} or {underscored_class_name: class}
|
| - """
|
| - classes = {}
|
| - for _, obj in inspect.getmembers(module):
|
| - # Ensure object is a class.
|
| - if not inspect.isclass(obj):
|
| - continue
|
| - # Include only subclasses of base_class.
|
| - if not issubclass(obj, base_class):
|
| - continue
|
| - # Exclude the base_class itself.
|
| - if obj is base_class:
|
| - continue
|
| - # Exclude protected or private classes.
|
| - if obj.__name__.startswith('_'):
|
| - continue
|
| - # Include only the module in which the class is defined.
|
| - # If a class is imported by another module, exclude those duplicates.
|
| - if obj.__module__ != module.__name__:
|
| - continue
|
| -
|
| - if index_by_class_name:
|
| - key_name = camel_case.ToUnderscore(obj.__name__)
|
| - else:
|
| - key_name = module.__name__.split('.')[-1]
|
| - if not directly_constructable or IsDirectlyConstructable(obj):
|
| - if key_name in classes and index_by_class_name:
|
| - assert classes[key_name] is obj, (
|
| - 'Duplicate key_name with different objs detected: '
|
| - 'key=%s, obj1=%s, obj2=%s' % (key_name, classes[key_name], obj))
|
| - else:
|
| - classes[key_name] = obj
|
| -
|
| - return classes
|
| -
|
| -
|
| -def IsDirectlyConstructable(cls):
|
| - """Returns True if instance of |cls| can be construct without arguments."""
|
| - assert inspect.isclass(cls)
|
| - if not hasattr(cls, '__init__'):
|
| - # Case |class A: pass|.
|
| - return True
|
| - if cls.__init__ is object.__init__:
|
| - # Case |class A(object): pass|.
|
| - return True
|
| - # Case |class (object):| with |__init__| other than |object.__init__|.
|
| - args, _, _, defaults = inspect.getargspec(cls.__init__)
|
| - if defaults is None:
|
| - defaults = ()
|
| - # Return true if |self| is only arg without a default.
|
| - return len(args) == len(defaults) + 1
|
| -
|
| -
|
| -_counter = [0]
|
| -
|
| -
|
| -def _GetUniqueModuleName():
|
| - _counter[0] += 1
|
| - return "module_" + str(_counter[0])
|
| +DiscoverClasses = discover.DiscoverClasses
|
| +DiscoverClassesInModule = discover.DiscoverClassesInModule
|
|
|