Commit 3343f273 authored by Juan Antonio Navarro Perez's avatar Juan Antonio Navarro Perez Committed by Commit Bot

[tools/perf] Provide mechanism to deal with unsatisfied dependencies

Some external module dependencies, notably numpy and pandas, are
required by some command line perf tools to work properly. And these
are normally satisfied by the vpython environment.

However vpython is not always available, e.g. on ChromeOs, so we
provide a mechanism to safely dismiss the respective import errors
and skip tests that cannot be run due to the lack of these modules.

Doing in this in preparation for the migration of soundwave out
of catapult/experimental and into tools/perf; since that includes
many other tests that also depend on these external modules.

TBR=achuith@chromium.org

Bug: 922030
Bug: 921762
Change-Id: I162e8e232484a5f9c8f919426ad86c6d0ad2e428
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1494887Reviewed-by: default avatarJuan Antonio Navarro Pérez <perezju@chromium.org>
Commit-Queue: Juan Antonio Navarro Pérez <perezju@chromium.org>
Cr-Commit-Position: refs/heads/master@{#637648}
parent f53e5e91
...@@ -4,11 +4,8 @@ ...@@ -4,11 +4,8 @@
import fnmatch import fnmatch
import numpy # pylint: disable=import-error from core.external_modules import numpy
try: from core.external_modules import pandas
import pandas # pylint: disable=import-error
except ImportError:
pass
SECONDS_IN_A_DAY = 60 * 60 * 24 SECONDS_IN_A_DAY = 60 * 60 * 24
......
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
import unittest import unittest
from telemetry import decorators
from cli_tools.flakiness_cli import analysis from cli_tools.flakiness_cli import analysis
from cli_tools.flakiness_cli import frames from cli_tools.flakiness_cli import frames
from core.external_modules import pandas
@unittest.skipIf(pandas is None, 'pandas not available')
class TestAnalysis(unittest.TestCase): class TestAnalysis(unittest.TestCase):
@decorators.Disabled('chromeos') # crbug.com/921762
def testFilterBy(self): def testFilterBy(self):
builders = frames.pandas.DataFrame.from_records([ builders = frames.pandas.DataFrame.from_records([
['chromium.perf', 'my-mac-bot', 'common_tests'], ['chromium.perf', 'my-mac-bot', 'common_tests'],
......
...@@ -7,10 +7,7 @@ ...@@ -7,10 +7,7 @@
import datetime import datetime
import os import os
try: from core.external_modules import pandas
import pandas # pylint: disable=import-error
except ImportError:
pass
CACHE_DIR = os.path.abspath(os.path.join( CACHE_DIR = os.path.abspath(os.path.join(
......
...@@ -10,12 +10,12 @@ import unittest ...@@ -10,12 +10,12 @@ import unittest
import mock import mock
from telemetry import decorators
from cli_tools.flakiness_cli import frames from cli_tools.flakiness_cli import frames
from core.external_modules import pandas
@unittest.skipIf(pandas is None, 'pandas not available')
class TestDataFrames(unittest.TestCase): class TestDataFrames(unittest.TestCase):
@decorators.Disabled('chromeos') # crbug.com/921762
def testBuildersDataFrame(self): def testBuildersDataFrame(self):
sample_data = { sample_data = {
'masters': [ 'masters': [
...@@ -109,7 +109,6 @@ class TestDataFrames(unittest.TestCase): ...@@ -109,7 +109,6 @@ class TestDataFrames(unittest.TestCase):
self.assertItemsEqual( self.assertItemsEqual(
list(frames._IterTestResults(tests_dict)), expected) list(frames._IterTestResults(tests_dict)), expected)
@decorators.Disabled('chromeos') # crbug.com/921762
def testTestResultsDataFrame(self): def testTestResultsDataFrame(self):
data = { data = {
'android-bot': { 'android-bot': {
...@@ -154,7 +153,6 @@ class TestDataFrames(unittest.TestCase): ...@@ -154,7 +153,6 @@ class TestDataFrames(unittest.TestCase):
self.assertEqual(len(selection), 1) self.assertEqual(len(selection), 1)
self.assertTrue(selection.iloc[0]['result'], 'N') self.assertTrue(selection.iloc[0]['result'], 'N')
@decorators.Disabled('chromeos') # crbug.com/921762
def testTestResultsDataFrame_empty(self): def testTestResultsDataFrame_empty(self):
data = { data = {
'android-bot': { 'android-bot': {
...@@ -181,7 +179,6 @@ class TestDataFrames(unittest.TestCase): ...@@ -181,7 +179,6 @@ class TestDataFrames(unittest.TestCase):
with self.assertRaises(AssertionError): with self.assertRaises(AssertionError):
frames.TestResultsDataFrame(data) frames.TestResultsDataFrame(data)
@decorators.Disabled('chromeos') # crbug.com/921762
def testGetWithCache(self): def testGetWithCache(self):
def make_frame_1(): def make_frame_1():
# test_2 was failing. # test_2 was failing.
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
import argparse import argparse
from cli_tools.flakiness_cli import analysis from cli_tools.flakiness_cli import analysis
from cli_tools.flakiness_cli import core from cli_tools.flakiness_cli import cached_api
def Main(): def Main():
...@@ -32,7 +32,7 @@ def Main(): ...@@ -32,7 +32,7 @@ def Main():
' with flakiness above this level.') ' with flakiness above this level.')
args = parser.parse_args() args = parser.parse_args()
configs = core.GetBuilders() configs = cached_api.GetBuilders()
configs = analysis.FilterBy(configs, master=args.master, configs = analysis.FilterBy(configs, master=args.master,
builder=args.builder, test_type=args.test_type) builder=args.builder, test_type=args.test_type)
if configs.empty: if configs.empty:
...@@ -40,7 +40,7 @@ def Main(): ...@@ -40,7 +40,7 @@ def Main():
dfs = [] dfs = []
for row in configs.itertuples(): for row in configs.itertuples():
df = core.GetTestResults(row.master, row.builder, row.test_type) df = cached_api.GetTestResults(row.master, row.builder, row.test_type)
df = analysis.FilterBy(df, test_suite=args.test_suite) df = analysis.FilterBy(df, test_suite=args.test_suite)
if df.empty: if df.empty:
continue continue
......
# Copyright 2019 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.
"""Allow importing external modules which may be missing in some platforms.
These modules are normally provided by the vpython environment manager. But
some platforms, e.g. CromeOs, do not have access to this facility.
To be safe, instead of e.g.:
import pandas
clients should do:
from core.external_modules import pandas
Tests that require pandas to work can be skipped as follows:
from core.external_modules import pandas
@unittest.skipIf(pandas is None, 'pandas not available')
class TestsForMyModule(unittest.TestCase):
def testSomeBehavior(self):
# test some behavior that requires pandas module.
Finally, scripts that to work properly require any of these external
dependencies should call:
from core import external_modules
if __name__ == '__main__':
external_modules.RequireModules()
# the rest of your script here.
to exit early with a suitable error message if the dependencies are not
satisfied.
"""
import sys
try:
import numpy # pylint: disable=import-error
except ImportError:
numpy = None
try:
import pandas # pylint: disable=import-error
except ImportError:
pandas = None
def RequireModules():
if numpy is None or pandas is None:
sys.exit(
'ERROR: Some required python modules are not available.\n\n'
'Make sure to run this script using vpython or ensure that '
'module dependencies listed in src/.vpython are satisfied.')
...@@ -6,8 +6,11 @@ ...@@ -6,8 +6,11 @@
"""This tool provides a command line interface for the flakiness dashboard.""" """This tool provides a command line interface for the flakiness dashboard."""
import sys import sys
from core import external_modules
from cli_tools import flakiness_cli from cli_tools import flakiness_cli
if __name__ == '__main__': if __name__ == '__main__':
external_modules.RequireModules()
sys.exit(flakiness_cli.Main()) sys.exit(flakiness_cli.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