diff --git a/tensorflow/python/lib/io/file_io.py b/tensorflow/python/lib/io/file_io.py index ace03e3d1b1..7a91bbd3e01 100644 --- a/tensorflow/python/lib/io/file_io.py +++ b/tensorflow/python/lib/io/file_io.py @@ -27,6 +27,7 @@ import uuid from tensorflow.python import pywrap_tensorflow from tensorflow.python.framework import errors from tensorflow.python.util import compat +from tensorflow.python.util import deprecation class FileIO(object): @@ -121,11 +122,51 @@ class FileIO(object): return self._prepare_value( pywrap_tensorflow.ReadFromStream(self._read_buf, length, status)) - def seek(self, position): - """Seeks to the position in the file.""" + @deprecation.deprecated_args( + None, + "position is deprecated in favor of the offset argument.", + "position") + def seek(self, offset=None, whence=0, position=None): + # TODO(jhseu): Delete later. Used to omit `position` from docs. + # pylint: disable=g-doc-args + """Seeks to the offset in the file. + + Args: + offset: The byte count relative to the whence argument. + whence: Valid values for whence are: + 0: start of the file (default) + 1: relative to the current position of the file + 2: relative to the end of file. offset is usually negative. + """ + # pylint: enable=g-doc-args self._preread_check() + # We needed to make offset a keyword argument for backwards-compatibility. + # This check exists so that we can convert back to having offset be a + # positional argument. + # TODO(jhseu): Make `offset` a positional argument after `position` is + # deprecated. + if offset is None and position is None: + raise TypeError("seek(): offset argument required") + if offset is not None and position is not None: + raise TypeError("seek(): offset and position may not be set " + "simultaneously.") + + if position is not None: + offset = position + with errors.raise_exception_on_not_ok_status() as status: - ret_status = self._read_buf.Seek(position) + if whence == 0: + pass + elif whence == 1: + offset += self.tell() + elif whence == 2: + offset += self.size() + else: + raise errors.InvalidArgumentError( + None, None, + "Invalid whence argument: {}. Valid values are 0, 1, or 2." + .format(whence)) + ret_status = self._read_buf.Seek(offset) pywrap_tensorflow.Set_TF_Status_from_Status(status, ret_status) def readline(self): diff --git a/tensorflow/python/lib/io/file_io_test.py b/tensorflow/python/lib/io/file_io_test.py index 72931217d9a..9ad04508555 100644 --- a/tensorflow/python/lib/io/file_io_test.py +++ b/tensorflow/python/lib/io/file_io_test.py @@ -392,6 +392,40 @@ class FileIoTest(test.TestCase): with self.assertRaises(errors.InvalidArgumentError): f.seek(-1) + with self.assertRaises(TypeError): + f.seek() + + # TODO(jhseu): Delete after position deprecation. + with self.assertRaises(TypeError): + f.seek(offset=0, position=0) + f.seek(position=9) + self.assertEqual(9, f.tell()) + self.assertEqual("testing2\n", f.readline()) + + def testSeekFromWhat(self): + file_path = os.path.join(self._base_dir, "temp_file") + with file_io.FileIO(file_path, mode="r+") as f: + f.write("testing1\ntesting2\ntesting3\n\ntesting5") + self.assertEqual("testing1\n", f.readline()) + self.assertEqual(9, f.tell()) + + # Seek to 18 + f.seek(9, 1) + self.assertEqual(18, f.tell()) + self.assertEqual("testing3\n", f.readline()) + + # Seek back to 9 + f.seek(9, 0) + self.assertEqual(9, f.tell()) + self.assertEqual("testing2\n", f.readline()) + + f.seek(-f.size(), 2) + self.assertEqual(0, f.tell()) + self.assertEqual("testing1\n", f.readline()) + + with self.assertRaises(errors.InvalidArgumentError): + f.seek(0, 3) + def testReadingIterator(self): file_path = os.path.join(self._base_dir, "temp_file") data = ["testing1\n", "testing2\n", "testing3\n", "\n", "testing5"] diff --git a/tensorflow/tools/api/golden/tensorflow.gfile.-fast-g-file.pbtxt b/tensorflow/tools/api/golden/tensorflow.gfile.-fast-g-file.pbtxt index 41497dc8699..4c0a0b2ea0d 100644 --- a/tensorflow/tools/api/golden/tensorflow.gfile.-fast-g-file.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.gfile.-fast-g-file.pbtxt @@ -41,7 +41,7 @@ tf_class { } member_method { name: "seek" - argspec: "args=[\'self\', \'position\'], varargs=None, keywords=None, defaults=None" + argspec: "args=[], varargs=args, keywords=kwargs, defaults=None" } member_method { name: "size" diff --git a/tensorflow/tools/api/golden/tensorflow.gfile.-g-file.pbtxt b/tensorflow/tools/api/golden/tensorflow.gfile.-g-file.pbtxt index bab0f279b24..85d81c4fcbc 100644 --- a/tensorflow/tools/api/golden/tensorflow.gfile.-g-file.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.gfile.-g-file.pbtxt @@ -41,7 +41,7 @@ tf_class { } member_method { name: "seek" - argspec: "args=[\'self\', \'position\'], varargs=None, keywords=None, defaults=None" + argspec: "args=[], varargs=args, keywords=kwargs, defaults=None" } member_method { name: "size" diff --git a/tensorflow/tools/api/golden/tensorflow.gfile.-open.pbtxt b/tensorflow/tools/api/golden/tensorflow.gfile.-open.pbtxt index 86e577c19a8..13f9c203e85 100644 --- a/tensorflow/tools/api/golden/tensorflow.gfile.-open.pbtxt +++ b/tensorflow/tools/api/golden/tensorflow.gfile.-open.pbtxt @@ -41,7 +41,7 @@ tf_class { } member_method { name: "seek" - argspec: "args=[\'self\', \'position\'], varargs=None, keywords=None, defaults=None" + argspec: "args=[], varargs=args, keywords=kwargs, defaults=None" } member_method { name: "size"