1# Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================== 15"""This pip smoke test verifies dependency files exist in the pip package. 16 17This script runs bazel queries to see what python files are required by the 18tests and ensures they are in the pip package superset. 19""" 20 21from __future__ import absolute_import 22from __future__ import division 23from __future__ import print_function 24 25import os 26import subprocess 27 28os.chdir(os.path.abspath(os.path.join(os.path.dirname(__file__), "../../.."))) 29 30PIP_PACKAGE_QUERY_EXPRESSION = ( 31 "deps(//tensorflow/tools/pip_package:build_pip_package)") 32 33# List of file paths containing BUILD files that should not be included for the 34# pip smoke test. 35BUILD_DENYLIST = [ 36 "tensorflow/lite", 37 "tensorflow/compiler/mlir/lite", 38 "tensorflow/python/kernel_tests/signal", 39 "tensorflow/examples", 40 "tensorflow/tools/android", 41 "tensorflow/python/eager/benchmarks", 42] 43 44def GetBuild(dir_base): 45 """Get the list of BUILD file all targets recursively startind at dir_base.""" 46 items = [] 47 for root, _, files in os.walk(dir_base): 48 for name in files: 49 if (name == "BUILD" and not any(x in root for x in BUILD_DENYLIST)): 50 items.append("//" + root + ":all") 51 return items 52 53 54def BuildPyTestDependencies(): 55 python_targets = GetBuild("tensorflow/python") 56 tensorflow_targets = GetBuild("tensorflow") 57 # Build list of test targets, 58 # python - attr(manual|pno_pip) 59 targets = " + ".join(python_targets) 60 targets += ' - attr(tags, "manual|no_pip", %s)' % " + ".join( 61 tensorflow_targets) 62 query_kind = "kind(py_test, %s)" % targets 63 # Skip benchmarks etc. 64 query_filter = 'filter("^((?!benchmark).)*$", %s)' % query_kind 65 # Get the dependencies 66 query_deps = "deps(%s, 1)" % query_filter 67 68 return python_targets, query_deps 69 70 71PYTHON_TARGETS, PY_TEST_QUERY_EXPRESSION = BuildPyTestDependencies() 72 73# TODO(amitpatankar): Clean up denylist. 74# List of dependencies that should not included in the pip package. 75DEPENDENCY_DENYLIST = [ 76 "//tensorflow/python:extra_py_tests_deps", 77 "//tensorflow/cc/saved_model:saved_model_test_files", 78 "//tensorflow/cc/saved_model:saved_model_half_plus_two", 79 "//tensorflow:no_tensorflow_py_deps", 80 "//tensorflow/tools/pip_package:win_pip_package_marker", 81 "//tensorflow/python:mixed_precision", 82 "//tensorflow/python:test_ops_2", 83 "//tensorflow/python:tf_optimizer", 84 "//tensorflow/python:compare_test_proto_py", 85 "//tensorflow/core:image_testdata", 86 "//tensorflow/core/lib/lmdb:lmdb_testdata", 87 "//tensorflow/core/lib/lmdb/testdata:lmdb_testdata", 88 "//tensorflow/core/kernels/cloud:bigquery_reader_ops", 89 "//tensorflow/python/debug:grpc_tensorflow_server.par", 90 "//tensorflow/python/feature_column:vocabulary_testdata", 91 "//tensorflow/python:framework/test_file_system.so", 92 "//tensorflow/python/util:nest_test_main_lib", 93 # lite 94 "//tensorflow/lite/experimental/examples/lstm:rnn_cell", 95 "//tensorflow/lite/experimental/examples/lstm:rnn_cell.py", 96 "//tensorflow/lite/experimental/examples/lstm:unidirectional_sequence_lstm_test", # pylint:disable=line-too-long 97 "//tensorflow/lite/experimental/examples/lstm:unidirectional_sequence_lstm_test.py", # pylint:disable=line-too-long 98 "//tensorflow/lite/python:interpreter", 99 "//tensorflow/lite/python:interpreter_test", 100 "//tensorflow/lite/python:interpreter.py", 101 "//tensorflow/lite/python:interpreter_test.py", 102] 103 104 105def main(): 106 """This script runs the pip smoke test. 107 108 Raises: 109 RuntimeError: If any dependencies for py_tests exist in subSet 110 111 Prerequisites: 112 1. Bazel is installed. 113 2. Running in github repo of tensorflow. 114 3. Configure has been run. 115 116 """ 117 118 # pip_package_dependencies_list is the list of included files in pip packages 119 pip_package_dependencies = subprocess.check_output( 120 ["bazel", "cquery", PIP_PACKAGE_QUERY_EXPRESSION]) 121 if isinstance(pip_package_dependencies, bytes): 122 pip_package_dependencies = pip_package_dependencies.decode("utf-8") 123 pip_package_dependencies_list = pip_package_dependencies.strip().split("\n") 124 pip_package_dependencies_list = [ 125 x.split()[0] for x in pip_package_dependencies_list 126 ] 127 print("Pip package superset size: %d" % len(pip_package_dependencies_list)) 128 129 # tf_py_test_dependencies is the list of dependencies for all python 130 # tests in tensorflow 131 tf_py_test_dependencies = subprocess.check_output( 132 ["bazel", "cquery", PY_TEST_QUERY_EXPRESSION]) 133 if isinstance(tf_py_test_dependencies, bytes): 134 tf_py_test_dependencies = tf_py_test_dependencies.decode("utf-8") 135 tf_py_test_dependencies_list = tf_py_test_dependencies.strip().split("\n") 136 tf_py_test_dependencies_list = [ 137 x.split()[0] for x in tf_py_test_dependencies.strip().split("\n") 138 ] 139 print("Pytest dependency subset size: %d" % len(tf_py_test_dependencies_list)) 140 141 missing_dependencies = [] 142 # File extensions and endings to ignore 143 ignore_extensions = [ 144 "_test", "_test.py", "_test_gpu", "_test_gpu.py", "_test_lib" 145 ] 146 147 ignored_files_count = 0 148 denylisted_dependencies_count = len(DEPENDENCY_DENYLIST) 149 # Compare dependencies 150 for dependency in tf_py_test_dependencies_list: 151 if dependency and dependency.startswith("//tensorflow"): 152 ignore = False 153 # Ignore extensions 154 if any(dependency.endswith(ext) for ext in ignore_extensions): 155 ignore = True 156 ignored_files_count += 1 157 158 # Check if the dependency is in the pip package, the dependency denylist, 159 # or should be ignored because of its file extension. 160 if not (ignore or dependency in pip_package_dependencies_list or 161 dependency in DEPENDENCY_DENYLIST): 162 missing_dependencies.append(dependency) 163 164 print("Ignored files count: %d" % ignored_files_count) 165 print("Denylisted dependencies count: %d" % denylisted_dependencies_count) 166 if missing_dependencies: 167 print("Missing the following dependencies from pip_packages:") 168 for missing_dependency in missing_dependencies: 169 print("\nMissing dependency: %s " % missing_dependency) 170 print("Affected Tests:") 171 rdep_query = ("rdeps(kind(py_test, %s), %s)" % 172 (" + ".join(PYTHON_TARGETS), missing_dependency)) 173 affected_tests = subprocess.check_output(["bazel", "cquery", rdep_query]) 174 affected_tests_list = affected_tests.split("\n")[:-2] 175 print("\n".join(affected_tests_list)) 176 177 raise RuntimeError(""" 178 One or more added test dependencies are not in the pip package. 179If these test dependencies need to be in TensorFlow pip package, please add them to //tensorflow/tools/pip_package/BUILD. 180Else add no_pip tag to the test.""") 181 182 else: 183 print("TEST PASSED") 184 185 186if __name__ == "__main__": 187 main() 188