chore: import upstream snapshot with attribution
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:14:16 +08:00
commit 8a852e4b4e
36502 changed files with 9277225 additions and 0 deletions
@@ -0,0 +1,7 @@
Golden file update requested!
All test failures have been skipped, see the logs for detected diffs.
This test is now going to write new golden files.
Make sure to package the updates together with your change.
You will need an explicit API approval. This may take longer than a normal
review.
+75
View File
@@ -0,0 +1,75 @@
# TensorFlow API backwards compatibility tests.
load(
"//tensorflow:tensorflow.bzl",
"py_test",
"tf_cc_binary",
)
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:license"],
default_visibility = ["//tensorflow/tools/api:__subpackages__"],
licenses = ["notice"],
)
exports_files([
"README.txt",
"API_UPDATE_WARNING.txt",
])
py_test(
name = "api_compatibility_test",
srcs = ["api_compatibility_test.py"],
data = [
":API_UPDATE_WARNING.txt",
":README.txt",
"//tensorflow/tools/api/golden:api_golden_v1",
"//tensorflow/tools/api/golden:api_golden_v2",
"//third_party/py/numpy/tf_numpy_api:api_golden",
],
strict_deps = True,
tags = [
"no_mac", # b/198669105
"no_oss", # Runs explicitly in OSS
"no_pip",
"no_rocm",
"no_windows", # Bugs due to some paths.
],
deps = [
# copybara:uncomment #"//third_party/py/google/protobuf:use_fast_cpp_protos",
"//tensorflow:tensorflow_py",
"//tensorflow/python/lib/io:file_io",
"//tensorflow/python/platform:client_testlib",
"//tensorflow/python/platform:resource_loader",
"//tensorflow/python/platform:tf_logging",
"//tensorflow/tools/api/lib:api_objects_proto_py",
"//tensorflow/tools/api/lib:python_object_to_proto_visitor",
"//tensorflow/tools/common:public_api",
"//tensorflow/tools/common:traverse",
],
)
py_test(
name = "module_test",
srcs = ["module_test.py"],
strict_deps = True,
tags = [
"no_windows", # Failing due to missing API symbols.
],
deps = [
# copybara:uncomment "//third_party/py/google/protobuf:use_fast_cpp_protos",
"//tensorflow:tensorflow_py",
"//tensorflow/python:tf2",
"//tensorflow/python/platform:client_testlib",
],
)
tf_cc_binary(
name = "convert_from_multiline",
srcs = ["convert_from_multiline.cc"],
deps = [
"//tensorflow/core:lib",
"//tensorflow/core:op_gen_lib",
"@com_google_absl//absl/status",
],
)
+12
View File
@@ -0,0 +1,12 @@
TensorFlow API backwards compatibility test
This test ensures all changes to the public API of TensorFlow are intended.
If this test fails, it means a change has been made to the public API. Backwards
incompatible changes are not allowed. You can run the test as follows to update
test goldens and package them with your change.
$ bazel run tensorflow/tools/api/tests:api_compatibility_test \
# -- --update_goldens True
You will need an API approval to make changes to the public TensorFlow API. This
includes additions to the API.
@@ -0,0 +1,553 @@
# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ==============================================================================
"""TensorFlow API compatibility tests.
This test ensures all changes to the public API of TensorFlow are intended.
If this test fails, it means a change has been made to the public API. Backwards
incompatible changes are not allowed. You can run the test with
"--update_goldens" flag set to "true" to update goldens when making changes to
the public TF python API.
"""
import argparse
import os
import re
import sys
import tensorflow as tf
from google.protobuf import message
from google.protobuf import text_format
from tensorflow.python.lib.io import file_io
from tensorflow.python.platform import resource_loader
from tensorflow.python.platform import test
from tensorflow.python.platform import tf_logging as logging
from tensorflow.tools.api.lib import api_objects_pb2
from tensorflow.tools.api.lib import python_object_to_proto_visitor
from tensorflow.tools.common import public_api
from tensorflow.tools.common import traverse
# pylint: disable=g-import-not-at-top,unused-import
_TENSORBOARD_AVAILABLE = True
try:
import tensorboard as _tb
except ImportError:
_TENSORBOARD_AVAILABLE = False
# pylint: enable=g-import-not-at-top,unused-import
# FLAGS defined at the bottom:
FLAGS = None
# DEFINE_boolean, update_goldens, default False:
_UPDATE_GOLDENS_HELP = """
Update stored golden files if API is updated. WARNING: All API changes
have to be authorized by TensorFlow leads.
"""
# DEFINE_boolean, only_test_core_api, default False:
_ONLY_TEST_CORE_API_HELP = """
Some TF APIs are being moved outside of the tensorflow/ directory. There is
no guarantee which versions of these APIs will be present when running this
test. Therefore, do not error out on API changes in non-core TF code
if this flag is set.
"""
# DEFINE_boolean, verbose_diffs, default True:
_VERBOSE_DIFFS_HELP = """
If set to true, print line by line diffs on all libraries. If set to
false, only print which libraries have differences.
"""
# Initialized with _InitPathConstants function below.
_API_GOLDEN_FOLDER_V1 = None
_API_GOLDEN_FOLDER_V2 = None
def _InitPathConstants():
global _API_GOLDEN_FOLDER_V1
global _API_GOLDEN_FOLDER_V2
root_golden_path_v2 = os.path.join(resource_loader.get_data_files_path(),
'..', 'golden', 'v2', 'tensorflow.pbtxt')
if FLAGS.update_goldens:
root_golden_path_v2 = os.path.realpath(root_golden_path_v2)
# Get API directories based on the root golden file. This way
# we make sure to resolve symbolic links before creating new files.
_API_GOLDEN_FOLDER_V2 = os.path.dirname(root_golden_path_v2)
_API_GOLDEN_FOLDER_V1 = os.path.normpath(
os.path.join(_API_GOLDEN_FOLDER_V2, '..', 'v1'))
_TEST_README_FILE = resource_loader.get_path_to_datafile('README.txt')
_UPDATE_WARNING_FILE = resource_loader.get_path_to_datafile(
'API_UPDATE_WARNING.txt')
_NON_CORE_PACKAGES = ['keras']
_V1_APIS_FROM_KERAS = ['layers', 'nn.rnn_cell']
_V2_APIS_FROM_KERAS = ['initializers', 'losses', 'metrics', 'optimizers']
def _KeyToFilePath(key, api_version):
"""From a given key, construct a filepath.
Filepath will be inside golden folder for api_version.
Args:
key: a string used to determine the file path
api_version: a number indicating the tensorflow API version, e.g. 1 or 2.
Returns:
A string of file path to the pbtxt file which describes the public API
"""
def _ReplaceCapsWithDash(matchobj):
match = matchobj.group(0)
return '-%s' % (match.lower())
case_insensitive_key = re.sub('([A-Z]{1})', _ReplaceCapsWithDash, key)
api_folder = (
_API_GOLDEN_FOLDER_V2 if api_version == 2 else _API_GOLDEN_FOLDER_V1)
if key.startswith('tensorflow.experimental.numpy'):
# Jumps up one more level in order to let Copybara find the
# 'tensorflow/third_party' string to replace
api_folder = os.path.join(
api_folder, '..', '..', '..', '..', '../third_party',
'py', 'numpy', 'tf_numpy_api')
api_folder = os.path.normpath(api_folder)
return os.path.join(api_folder, '%s.pbtxt' % case_insensitive_key)
def _FileNameToKey(filename):
"""From a given filename, construct a key we use for api objects."""
def _ReplaceDashWithCaps(matchobj):
match = matchobj.group(0)
return match[1].upper()
base_filename = os.path.basename(filename)
base_filename_without_ext = os.path.splitext(base_filename)[0]
api_object_key = re.sub('((-[a-z]){1})', _ReplaceDashWithCaps,
base_filename_without_ext)
return api_object_key
def _VerifyNoSubclassOfMessageVisitor(path, parent, unused_children):
"""A Visitor that crashes on subclasses of generated proto classes."""
# If the traversed object is a proto Message class
if not (isinstance(parent, type) and issubclass(parent, message.Message)):
return
if parent is message.Message:
return
# Check that it is a direct subclass of Message.
if message.Message not in parent.__bases__:
raise NotImplementedError(
'Object tf.%s is a subclass of a generated proto Message. '
'They are not yet supported by the API tools.' % path)
def _FilterNonCoreGoldenFiles(golden_file_list):
"""Filter out non-core API pbtxt files."""
return _FilterGoldenFilesByPrefix(golden_file_list, _NON_CORE_PACKAGES)
def _FilterV1KerasRelatedGoldenFiles(golden_file_list):
return _FilterGoldenFilesByPrefix(golden_file_list, _V1_APIS_FROM_KERAS)
def _FilterV2KerasRelatedGoldenFiles(golden_file_list):
return _FilterGoldenFilesByPrefix(golden_file_list, _V2_APIS_FROM_KERAS)
def _FilterGoldenFilesByPrefix(golden_file_list, package_prefixes):
filtered_file_list = []
filtered_package_prefixes = ['tensorflow.%s.' % p for p in package_prefixes]
for f in golden_file_list:
if any(
os.path.basename(f).startswith(pre)
for pre in filtered_package_prefixes):
continue
filtered_file_list.append(f)
return filtered_file_list
def _GetModuleOrClass(api_object):
if api_object.HasField('tf_module'):
return api_object.tf_module
if api_object.HasField('tf_class'):
return api_object.tf_class
return None
def _FilterGoldenProtoDict(golden_proto_dict, omit_golden_symbols_map):
"""Filter out golden proto dict symbols that should be omitted."""
if not omit_golden_symbols_map:
return golden_proto_dict
filtered_proto_dict = dict(golden_proto_dict)
for key, symbol_list in omit_golden_symbols_map.items():
api_object = api_objects_pb2.TFAPIObject()
api_object.CopyFrom(filtered_proto_dict[key])
filtered_proto_dict[key] = api_object
module_or_class = _GetModuleOrClass(api_object)
if module_or_class is not None:
if 'is_instance' in symbol_list:
del module_or_class.is_instance[:]
for members in (module_or_class.member, module_or_class.member_method):
filtered_members = [m for m in members if m.name not in symbol_list]
# Two steps because protobuf repeated fields disallow slice assignment.
del members[:]
members.extend(filtered_members)
return filtered_proto_dict
def _GetTFNumpyGoldenPattern(api_version):
return os.path.join(resource_loader.get_root_dir_with_all_resources(),
_KeyToFilePath('tensorflow.experimental.numpy*',
api_version))
class ApiCompatibilityTest(test.TestCase):
def __init__(self, *args, **kwargs):
super(ApiCompatibilityTest, self).__init__(*args, **kwargs)
golden_update_warning_filename = os.path.join(
resource_loader.get_root_dir_with_all_resources(), _UPDATE_WARNING_FILE)
self._update_golden_warning = file_io.read_file_to_string(
golden_update_warning_filename)
test_readme_filename = os.path.join(
resource_loader.get_root_dir_with_all_resources(), _TEST_README_FILE)
self._test_readme_message = file_io.read_file_to_string(
test_readme_filename)
def _AssertProtoDictEquals(self,
expected_dict,
actual_dict,
verbose=False,
update_goldens=False,
additional_missing_object_message='',
api_version=2,
actual_dict_for_update=None):
"""Diff given dicts of protobufs and report differences a readable way.
Args:
expected_dict: a dict of TFAPIObject protos constructed from golden files.
actual_dict: a dict of TFAPIObject protos constructed by reading from the
TF package linked to the test.
verbose: Whether to log the full diffs, or simply report which files were
different.
update_goldens: Whether to update goldens when there are diffs found.
additional_missing_object_message: Message to print when a symbol is
missing.
api_version: TensorFlow API version to test.
actual_dict_for_update: Optional unfiltered actual protos to write when
update_goldens is true.
"""
if actual_dict_for_update is None:
actual_dict_for_update = actual_dict
diffs = []
verbose_diffs = []
expected_keys = set(expected_dict.keys())
actual_keys = set(actual_dict.keys())
only_in_expected = expected_keys - actual_keys
only_in_actual = actual_keys - expected_keys
all_keys = expected_keys | actual_keys
# This will be populated below.
updated_keys = []
for key in all_keys:
diff_message = ''
verbose_diff_message = ''
# First check if the key is not found in one or the other.
if key in only_in_expected:
diff_message = 'Object %s expected but not found (removed). %s' % (
key, additional_missing_object_message)
verbose_diff_message = diff_message
elif key in only_in_actual:
diff_message = 'New object %s found (added).' % key
verbose_diff_message = diff_message
else:
# Do not truncate diff
self.maxDiff = None # pylint: disable=invalid-name
# Now we can run an actual proto diff.
try:
self.assertProtoEquals(expected_dict[key], actual_dict[key])
except AssertionError as e:
updated_keys.append(key)
diff_message = 'Change detected in python object: %s.' % key
verbose_diff_message = str(e)
# All difference cases covered above. If any difference found, add to the
# list.
if diff_message:
diffs.append(diff_message)
verbose_diffs.append(verbose_diff_message)
# If diffs are found, handle them based on flags.
if diffs:
diff_count = len(diffs)
logging.error(self._test_readme_message)
logging.error('%d differences found between API and golden.', diff_count)
if update_goldens:
# Write files if requested.
logging.warning(self._update_golden_warning)
# If the keys are only in expected, some objects are deleted.
# Remove files.
for key in only_in_expected:
filepath = _KeyToFilePath(key, api_version)
file_io.delete_file(filepath)
# If the files are only in actual (current library), these are new
# modules. Write them to files. Also record all updates in files.
for key in only_in_actual | set(updated_keys):
filepath = _KeyToFilePath(key, api_version)
file_io.write_string_to_file(
filepath, text_format.MessageToString(
actual_dict_for_update[key]))
else:
# Include the actual differences to help debugging.
for d, verbose_d in zip(diffs, verbose_diffs):
logging.error(' %s', d)
logging.error(' %s', verbose_d)
# Fail if we cannot fix the test by updating goldens.
self.fail('%d differences found between API and golden.' % diff_count)
else:
logging.info('No differences found between API and golden.')
def testNoSubclassOfMessage(self):
visitor = public_api.PublicAPIVisitor(_VerifyNoSubclassOfMessageVisitor)
visitor.do_not_descend_map['tf'].append('contrib')
# visitor.do_not_descend_map['tf'].append('keras')
# Skip compat.v1 and compat.v2 since they are validated in separate tests.
visitor.private_map['tf.compat'] = ['v1', 'v2']
traverse.traverse(tf, visitor)
def testNoSubclassOfMessageV1(self):
if not hasattr(tf.compat, 'v1'):
return
visitor = public_api.PublicAPIVisitor(_VerifyNoSubclassOfMessageVisitor)
visitor.do_not_descend_map['tf'].append('contrib')
if FLAGS.only_test_core_api:
visitor.do_not_descend_map['tf'].extend(_NON_CORE_PACKAGES)
visitor.private_map['tf.compat'] = ['v1', 'v2']
traverse.traverse(tf.compat.v1, visitor)
def testNoSubclassOfMessageV2(self):
if not hasattr(tf.compat, 'v2'):
return
visitor = public_api.PublicAPIVisitor(_VerifyNoSubclassOfMessageVisitor)
visitor.do_not_descend_map['tf'].append('contrib')
if FLAGS.only_test_core_api:
visitor.do_not_descend_map['tf'].extend(_NON_CORE_PACKAGES)
visitor.private_map['tf.compat'] = ['v1', 'v2']
traverse.traverse(tf.compat.v2, visitor)
def _checkBackwardsCompatibility(self,
root,
golden_file_patterns,
api_version,
additional_private_map=None,
omit_golden_symbols_map=None):
# Extract all API stuff.
visitor = python_object_to_proto_visitor.PythonObjectToProtoVisitor()
public_api_visitor = public_api.PublicAPIVisitor(visitor)
public_api_visitor.private_map['tf'].append('contrib')
if api_version == 2:
public_api_visitor.private_map['tf'].append('enable_v2_behavior')
public_api_visitor.do_not_descend_map['tf.GPUOptions'] = ['Experimental']
# Do not descend into these numpy classes because their signatures may be
# different between internal and OSS.
public_api_visitor.do_not_descend_map['tf.experimental.numpy'] = [
'bool_', 'complex_', 'complex128', 'complex64', 'float_', 'float16',
'float32', 'float64', 'inexact', 'int_', 'int16', 'int32', 'int64',
'int8', 'object_', 'string_', 'uint16', 'uint32', 'uint64', 'uint8',
'unicode_', 'iinfo']
public_api_visitor.do_not_descend_map['tf'].append('keras')
if FLAGS.only_test_core_api:
public_api_visitor.do_not_descend_map['tf'].extend(_NON_CORE_PACKAGES)
if api_version == 2:
public_api_visitor.do_not_descend_map['tf'].extend(_V2_APIS_FROM_KERAS)
else:
public_api_visitor.do_not_descend_map['tf'].extend(['layers'])
public_api_visitor.do_not_descend_map['tf.nn'] = ['rnn_cell']
if additional_private_map:
public_api_visitor.private_map.update(additional_private_map)
traverse.traverse(root, public_api_visitor)
proto_dict = visitor.GetProtos()
# Read all golden files.
golden_file_list = file_io.get_matching_files(golden_file_patterns)
if FLAGS.only_test_core_api:
golden_file_list = _FilterNonCoreGoldenFiles(golden_file_list)
if api_version == 2:
golden_file_list = _FilterV2KerasRelatedGoldenFiles(golden_file_list)
else:
golden_file_list = _FilterV1KerasRelatedGoldenFiles(golden_file_list)
def _ReadFileToProto(filename):
"""Read a filename, create a protobuf from its contents."""
ret_val = api_objects_pb2.TFAPIObject()
text_format.Merge(file_io.read_file_to_string(filename), ret_val)
return ret_val
golden_proto_dict = {
_FileNameToKey(filename): _ReadFileToProto(filename)
for filename in golden_file_list
}
golden_proto_dict = _FilterGoldenProtoDict(golden_proto_dict,
omit_golden_symbols_map)
filtered_proto_dict = _FilterGoldenProtoDict(proto_dict,
omit_golden_symbols_map)
# Diff them. Do not fail if called with update.
# If the test is run to update goldens, only report diffs but do not fail.
self._AssertProtoDictEquals(
golden_proto_dict,
filtered_proto_dict,
verbose=FLAGS.verbose_diffs,
update_goldens=FLAGS.update_goldens,
api_version=api_version,
actual_dict_for_update=proto_dict)
def testAPIBackwardsCompatibility(self):
api_version = 1
if hasattr(tf, '_major_api_version') and tf._major_api_version == 2:
api_version = 2
golden_file_patterns = [
os.path.join(resource_loader.get_root_dir_with_all_resources(),
_KeyToFilePath('*', api_version)),
_GetTFNumpyGoldenPattern(api_version)]
omit_golden_symbols_map = {}
if (api_version == 2 and FLAGS.only_test_core_api and
not _TENSORBOARD_AVAILABLE):
# In TF 2.0 these summary symbols are imported from TensorBoard.
omit_golden_symbols_map['tensorflow.summary'] = [
'audio', 'histogram', 'image', 'scalar', 'text'
]
omit_golden_symbols_map.update(
self._ignored_is_instance_types(['tensorflow.__internal__.FuncGraph'])
)
self._checkBackwardsCompatibility(
tf,
golden_file_patterns,
api_version,
# Skip compat.v1 and compat.v2 since they are validated
# in separate tests.
additional_private_map={'tf.compat': ['v1', 'v2']},
omit_golden_symbols_map=omit_golden_symbols_map)
# Check that V2 API does not have contrib
self.assertTrue(api_version == 1 or not hasattr(tf, 'contrib'))
def testAPIBackwardsCompatibilityV1(self):
api_version = 1
golden_file_patterns = os.path.join(
resource_loader.get_root_dir_with_all_resources(),
_KeyToFilePath('*', api_version))
omit_golden_symbols_map = {'tensorflow': ['pywrap_tensorflow']}
omit_golden_symbols_map.update(
self._ignored_is_instance_types(['tensorflow.python_io.TFRecordWriter'])
)
# In OSS we have a different version of ABSL.
omit_golden_symbols_map['tensorflow.logging'] = ['log_if']
self._checkBackwardsCompatibility(
tf.compat.v1,
golden_file_patterns,
api_version,
additional_private_map={
'tf': ['pywrap_tensorflow'],
'tf.compat': ['v1', 'v2'],
},
omit_golden_symbols_map=omit_golden_symbols_map)
def testAPIBackwardsCompatibilityV2(self):
api_version = 2
golden_file_patterns = [
os.path.join(resource_loader.get_root_dir_with_all_resources(),
_KeyToFilePath('*', api_version)),
_GetTFNumpyGoldenPattern(api_version)]
omit_golden_symbols_map = {}
if FLAGS.only_test_core_api and not _TENSORBOARD_AVAILABLE:
# In TF 2.0 these summary symbols are imported from TensorBoard.
omit_golden_symbols_map['tensorflow.summary'] = [
'audio', 'histogram', 'image', 'scalar', 'text'
]
omit_golden_symbols_map.update(
self._ignored_is_instance_types(['tensorflow.__internal__.FuncGraph'])
)
self._checkBackwardsCompatibility(
tf.compat.v2,
golden_file_patterns,
api_version,
additional_private_map={'tf.compat': ['v1', 'v2']},
omit_golden_symbols_map=omit_golden_symbols_map)
def _ignored_is_instance_types(self, extra_types=None):
# In case a new type is defined within a pywrap_<module_name>.so library,
# it will end up having proper type and location in distributed OSS wheel
# package eventually, but that conversion happens after this test is ran.
#
# Making this test depend on wheel itself also breaks because wheels use
# _upb as underlying protobuf implementation while internal TF uses cpp
# implementation (resulting in different is_instance values for protobuf
# metadata types in golden pbtxt depending on which protobuf implementation
# is being used during test execution). The cpp implementation is not even
# included anymore in protobuf oss wheels.
#
# We end up in a situation when we cannot make this test pass internally and
# externally on the same set of golden expected .pbtxt inputs. It is rare
# and minor discrepancy, so just ignore the is_instance checks for the few
# problematic types, they are guaraneed to have proper types in final wheel
# anyway.
ignored_is_instance_types = [
'tensorflow.DType',
'tensorflow.dtypes.DType',
'tensorflow.__internal__.SymbolicTensor',
'tensorflow.Graph',
'tensorflow.Operation',
'tensorflow.io.TFRecordWriter'
] + extra_types if extra_types else []
return {k: 'is_instance' for k in ignored_is_instance_types}
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
'--update_goldens', type=bool, default=False, help=_UPDATE_GOLDENS_HELP)
parser.add_argument(
'--only_test_core_api',
type=bool,
default=True, # only_test_core_api default value
help=_ONLY_TEST_CORE_API_HELP)
parser.add_argument(
'--verbose_diffs', type=bool, default=True, help=_VERBOSE_DIFFS_HELP)
FLAGS, unparsed = parser.parse_known_args()
_InitPathConstants()
# Now update argv, so that unittest library does not get confused.
sys.argv = [sys.argv[0]] + unparsed
test.main()
@@ -0,0 +1,68 @@
/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Converts all *.pbtxt files in a directory from Multiline to proto format.
#include <iostream>
#include <string>
#include <vector>
#include "absl/status/status.h"
#include "tensorflow/core/framework/op_gen_lib.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
namespace tensorflow {
namespace {
constexpr char kApiDefFilePattern[] = "*.pbtxt";
absl::Status ConvertFilesFromMultiline(const std::string& input_dir,
const std::string& output_dir) {
Env* env = Env::Default();
const std::string file_pattern = io::JoinPath(input_dir, kApiDefFilePattern);
std::vector<std::string> matching_paths;
TF_CHECK_OK(env->GetMatchingPaths(file_pattern, &matching_paths));
if (!env->IsDirectory(output_dir).ok()) {
TF_RETURN_IF_ERROR(env->CreateDir(output_dir));
}
for (const auto& path : matching_paths) {
std::string contents;
TF_RETURN_IF_ERROR(tensorflow::ReadFileToString(env, path, &contents));
contents = tensorflow::PBTxtFromMultiline(contents);
std::string output_path = io::JoinPath(output_dir, io::Basename(path));
// Write contents to output_path
TF_RETURN_IF_ERROR(
tensorflow::WriteStringToFile(env, output_path, contents));
}
return absl::OkStatus();
}
} // namespace
} // namespace tensorflow
int main(int argc, char* argv[]) {
tensorflow::port::InitMain(argv[0], &argc, &argv);
const std::string usage =
"Usage: convert_from_multiline input_dir output_dir";
if (argc != 3) {
std::cerr << usage << std::endl;
return -1;
}
TF_CHECK_OK(tensorflow::ConvertFilesFromMultiline(argv[1], argv[2]));
return 0;
}
+82
View File
@@ -0,0 +1,82 @@
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ==============================================================================
"""Smoke tests for tensorflow module."""
import importlib.util
import tensorflow as tf # pylint: disable=g-direct-tensorflow-import
from tensorflow.python import tf2
from tensorflow.python.platform import test
class ModuleTest(test.TestCase):
def testCanLoadWithPkgutil(self):
out = importlib.util.find_spec('tensorflow')
self.assertIsNotNone(out)
def testDocString(self):
self.assertIn('TensorFlow', tf.__doc__)
self.assertNotIn('Wrapper', tf.__doc__)
def testDict(self):
# Check that a few modules are in __dict__.
# pylint: disable=pointless-statement
tf.nn
tf.keras
tf.image
# pylint: enable=pointless-statement
self.assertIn('nn', tf.__dict__)
self.assertIn('keras', tf.__dict__)
self.assertIn('image', tf.__dict__)
def testName(self):
self.assertEqual('tensorflow', tf.__name__)
def testBuiltInName(self):
# range is a built-in name in Python. Just checking that
# tf.range works fine.
if tf2.enabled():
self.assertEqual(
'tf.Tensor([1 2 3 4 5 6 7 8 9], shape=(9,), dtype=int32)',
str(tf.range(1, 10)))
else:
self.assertEqual('Tensor("range:0", shape=(9,), dtype=int32)',
str(tf.range(1, 10)))
def testCompatV2HasCompatV1(self):
# pylint: disable=pointless-statement
tf.compat.v2.compat.v1.keras
# pylint: enable=pointless-statement
def testSummaryMerged(self):
# pylint: disable=pointless-statement
tf.summary.image
# If we use v2 API, check for create_file_writer,
# otherwise check for FileWriter.
if hasattr(tf, '_major_api_version') and tf._major_api_version == 2:
tf.summary.create_file_writer
else:
tf.compat.v1.summary.FileWriter
# pylint: enable=pointless-statement
def testPythonModuleIsHidden(self):
self.assertNotIn('python', dir(tf))
if __name__ == '__main__':
test.main()