Add a recursive import before running doctest.

This allows all code files are checked, including things that are not implicitly imported by `import tensorflow`

This also:

- Fixes some broken doctests that were hiding in the docs
- switches StructuredTensor's __repr__ to print one item per line.

PiperOrigin-RevId: 314261531
Change-Id: I9ef7c344e40c5e03fd441105327e70a0ab4fdedc
This commit is contained in:
Mark Daoust 2020-06-01 21:09:25 -07:00 committed by TensorFlower Gardener
parent 9fbf5e5d50
commit cae9671a88
5 changed files with 81 additions and 48 deletions

View File

@ -60,7 +60,6 @@ class StructuredTensor(composite_tensor.CompositeTensor):
### Examples
```python
>>> # A scalar StructuredTensor describing a single person.
>>> s1 = StructuredTensor.from_pyval(
... {"age": 82, "nicknames": ["Bob", "Bobby"]})
@ -78,7 +77,7 @@ class StructuredTensor(composite_tensor.CompositeTensor):
TensorShape([3])
>>> s2[0]["age"]
<tf.Tensor: shape=(), dtype=int32, numpy=12>
```
### Field Paths
@ -156,18 +155,19 @@ class StructuredTensor(composite_tensor.CompositeTensor):
Examples:
>>> StructuredTensor.from_fields({'x': 1, 'y': [1, 2, 3]})
<StructuredTensor(fields={
x: tf.Tensor(1, shape=(), dtype=int32),
y: tf.Tensor([1 2 3], shape=(3,), dtype=int32)},
shape=())>
<StructuredTensor(
fields={
"x": tf.Tensor(1, shape=(), dtype=int32),
"y": tf.Tensor([1 2 3], shape=(3,), dtype=int32)},
shape=())>
>>> StructuredTensor.from_fields({'foo': [1, 2], 'bar': [3, 4]},
... shape=[2])
<StructuredTensor(fields={
bar: tf.Tensor([3 4], shape=(2,), dtype=int32),
foo: tf.Tensor([1 2], shape=(2,), dtype=int32)},
shape=(2,))>
<StructuredTensor(
fields={
"bar": tf.Tensor([3 4], shape=(2,), dtype=int32),
"foo": tf.Tensor([1 2], shape=(2,), dtype=int32)},
shape=(2,))>
"""
shape = tensor_shape.as_shape(shape)
rank = shape.rank
@ -437,9 +437,15 @@ class StructuredTensor(composite_tensor.CompositeTensor):
return self._fields[key[rank]].__getitem__(key[:rank] + key[rank + 1:])
def __repr__(self):
return '<StructuredTensor(fields={%s}, shape=%s)>' % (', '.join(
'"%s": %s' % (k, v)
for k, v in sorted(self._fields.items())), self._shape)
fields = sorted(self._fields.items())
fields = ((k, str(v).replace('\n', '\n ')) for k, v in fields)
fields = ('"{}": {}'.format(k, v) for k, v in fields)
dict_repr = ',\n '.join(fields)
return (
'<StructuredTensor(\n'
' fields={\n'
' %s},\n'
' shape=%s)>' % (dict_repr, self._shape))
#=============================================================================
# Conversion
@ -506,10 +512,11 @@ class StructuredTensor(composite_tensor.CompositeTensor):
>>> StructuredTensor.from_pyval(
... {'a': [1, 2, 3], 'b': [[4, 5], [6, 7]]})
<StructuredTensor(fields={
a: tf.Tensor([1 2 3], shape=(3,), dtype=int32),
b: <tf.RaggedTensor [[4, 5], [6, 7]]>},
shape=())>
<StructuredTensor(
fields={
"a": tf.Tensor([1 2 3], shape=(3,), dtype=int32),
"b": <tf.RaggedTensor [[4, 5], [6, 7]]>},
shape=())>
Note that `StructuredTensor.from_pyval(pyval).to_pyval() == pyval`.
@ -639,9 +646,10 @@ class StructuredTensor(composite_tensor.CompositeTensor):
... [{'foo': 12}, {'foo': 33}, {'foo': 99}])
>>> partition = RowPartition.from_row_lengths([2, 0, 1])
>>> st.partition_outer_dimension(partition)
<StructuredTensor(fields={
foo: <tf.RaggedTensor [[12, 33], [], [99]]>},
shape=(3, None))>
<StructuredTensor(
fields={
"foo": <tf.RaggedTensor [[12, 33], [], [99]]>},
shape=(3, None))>
Args:
row_partition: A `RowPartition`.
@ -664,9 +672,10 @@ class StructuredTensor(composite_tensor.CompositeTensor):
>>> st = StructuredTensor.from_pyval(
... [[{'foo': 12}, {'foo': 33}], [], [{'foo': 99}]])
>>> st.merge_dims(0, 1)
<StructuredTensor(fields={
foo: tf.Tensor([12 33 99], shape=(3,), dtype=int32)},
shape=(3,))>
<StructuredTensor(
fields={
"foo": tf.Tensor([12 33 99], shape=(3,), dtype=int32)},
shape=(3,))>
Args:
outer_axis: `int`: The first dimension in the range of dimensions to
@ -1071,16 +1080,17 @@ def _partition_outer_dimension(value, row_partition):
Examples:
>>> partition = row_partition.RowPartition.from_row_lengths([2, 0, 1])
>>> partition = RowPartition.from_row_lengths([2, 0, 1])
>>> _partition_outer_dimension(tf.constant([1, 2, 3]), partition)
<tf.RaggedTensor [[1, 2], [], [3]]>
>>> struct_value = StructuredTensor.from_pyval(
... [{'x': 1}, {'x': 2}, {'x': 3}])
>>> _partition_outer_dimension(struct_value, partition)
<StructuredTensor(fields={
x: <tf.RaggedTensor [[1, 2], [], [3]]>},
shape=(3, None))>
<StructuredTensor(
fields={
"x": <tf.RaggedTensor [[1, 2], [], [3]]>},
shape=(3, None))>
Args:
value: Tensor, RaggedTensor, or StructuredTensor

View File

@ -18,6 +18,8 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import textwrap
from absl.testing import parameterized
import numpy as np
@ -929,17 +931,25 @@ class StructuredTensorTest(test_util.TensorFlowTestCase,
def testRepr(self):
st = StructuredTensor.from_pyval({"a": 5, "b": {"c": [1, 2, 3]}})
if context.executing_eagerly():
expected = ("<StructuredTensor(fields={"
'"a": tf.Tensor(5, shape=(), dtype=int32), '
'"b": <StructuredTensor(fields={'
'"c": tf.Tensor([1 2 3], shape=(3,), dtype=int32)}, '
"shape=())>}, shape=())>")
expected = textwrap.dedent("""
<StructuredTensor(
fields={
"a": tf.Tensor(5, shape=(), dtype=int32),
"b": <StructuredTensor(
fields={
"c": tf.Tensor([1 2 3], shape=(3,), dtype=int32)},
shape=())>},
shape=())>""")[1:]
else:
expected = ("<StructuredTensor(fields={"
'"a": Tensor("Const:0", shape=(), dtype=int32), '
'"b": <StructuredTensor(fields={'
'"c": Tensor("RaggedConstant/Const:0", shape=(3,), '
"dtype=int32)}, shape=())>}, shape=())>")
expected = textwrap.dedent("""
<StructuredTensor(
fields={
"a": Tensor("Const:0", shape=(), dtype=int32),
"b": <StructuredTensor(
fields={
"c": Tensor("RaggedConstant/Const:0", shape=(3,), dtype=int32)},
shape=())>},
shape=())>""")[1:]
self.assertEqual(repr(st), expected)
def testPartitionOuterDimension2DDenseField(self):

View File

@ -21,9 +21,11 @@ or that should be permanently associated with the training session.
You can use this just like the logging module:
>>> tensorboard_logging.set_summary_writer(summary_writer)
>>> tensorboard_logging.info("my %s", "message")
>>> tensorboard_logging.log(tensorboard_logging.WARN, "something")
```
tensorboard_logging.set_summary_writer(summary_writer)
tensorboard_logging.info("my %s", "message")
tensorboard_logging.log(tensorboard_logging.WARN, "something")
```
"""
from __future__ import absolute_import

View File

@ -39,7 +39,6 @@ py_test(
deps = [
":tf_doctest_lib",
"//tensorflow:tensorflow_py",
"//tensorflow/python/keras/preprocessing",
"//third_party/py/numpy",
],
)

View File

@ -19,16 +19,17 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import importlib
import os
import pkgutil
import sys
from absl import flags
from absl.testing import absltest
import numpy as np
import tensorflow.compat.v2 as tf
from tensorflow.python.keras import preprocessing
import tensorflow.python as tf_root
from tensorflow.tools.docs import tf_doctest_lib
# We put doctest after absltest so that it picks up the unittest monkeypatch.
@ -37,9 +38,6 @@ import doctest # pylint: disable=g-bad-import-order
tf.compat.v1.enable_v2_behavior()
# Inject keras.preprocessing files into `tf.keras.preprocessing` namespace.
tf.keras.preprocessing = preprocessing
FLAGS = flags.FLAGS
flags.DEFINE_list('module', [], 'A list of specific module to run doctest on.')
@ -56,6 +54,20 @@ flags.mark_flags_as_mutual_exclusive(['list', 'file'])
PACKAGE = 'tensorflow.python.'
def recursive_import(root):
"""Recursively imports all the sub-modules under a root package.
Args:
root: A python package.
"""
for _, name, _ in pkgutil.walk_packages(
root.__path__, prefix=root.__name__ + '.'):
try:
importlib.import_module(name)
except (AttributeError, ImportError):
pass
def find_modules():
"""Finds all the modules in the core package imported.
@ -166,6 +178,6 @@ def load_tests(unused_loader, tests, unused_ignore):
))
return tests
if __name__ == '__main__':
recursive_import(tf_root)
absltest.main()