diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -301,6 +301,10 @@ .. versionadded:: 3.1 The ``SEEK_*`` constants. + .. versionadded:: 3.2 + Some Operating Systems can support aditional values, like + :const:`os.SEEK_HOLE` or :const:`os.SEEK_DATA`. + .. method:: seekable() Return ``True`` if the stream supports random access. If ``False``, diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -716,6 +716,10 @@ Parameters to the :func:`lseek` function. Their values are 0, 1, and 2, respectively. Availability: Windows, Unix. + .. versionadded:: 3.2 + Some Operating Systems can support aditional values, like + :const:`os.SEEK_HOLE` or :const:`os.SEEK_DATA`. + .. function:: open(file, flags[, mode]) diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -110,6 +110,7 @@ # Python uses fixed values for the SEEK_ constants; they are mapped # to native constants if necessary in posixmodule.c +# Other possible SEEK values are directly imported from posixmodule.c SEEK_SET = 0 SEEK_CUR = 1 SEEK_END = 2 diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -637,13 +637,6 @@ # this test. Else, write it. pass - def test_invalid_args(self): - rawio = self.MockRawIO() - bufio = self.tp(rawio) - # Invalid whence - self.assertRaises(ValueError, bufio.seek, 0, -1) - self.assertRaises(ValueError, bufio.seek, 0, 3) - def test_override_destructor(self): tp = self.tp record = [] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -290,6 +290,8 @@ - Issue #9377: Use Unicode API for gethostname on Windows. +- Issue #10142: Support for SEEK_HOLE/SEEK_DATA (for example, under ZFS). + - Issue #10143: Update "os.pathconf" values. - Issue #6518: Support context manager protcol for ossaudiodev types. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1018,11 +1018,6 @@ if (!PyArg_ParseTuple(args, "O|i:seek", &targetobj, &whence)) { return NULL; } - if (whence < 0 || whence > 2) { - PyErr_Format(PyExc_ValueError, - "whence must be between 0 and 2, not %d", whence); - return NULL; - } CHECK_CLOSED(self, "seek of closed file") @@ -1030,7 +1025,11 @@ if (target == -1 && PyErr_Occurred()) return NULL; - if (whence != 2 && self->readable) { + /* SEEK_SET and SEEK_CUR are special because we could seek inside the + buffer. Other whence values must be managed without this optimization. + Some Operating Systems can provide additional values, like + SEEK_HOLE/SEEK_DATA. */ + if (((whence == 0) || (whence == 1)) && self->readable) { Py_off_t current, avail; /* Check if seeking leaves us inside the current buffer, so as to return quickly if possible. Also, we needn't take the diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8151,6 +8151,13 @@ if (ins(d, "O_EXLOCK", (long)O_EXLOCK)) return -1; #endif +#ifdef SEEK_HOLE /* ZFS */ + if (ins(d, "SEEK_HOLE", (long)SEEK_HOLE)) return -1; +#endif +#ifdef SEEK_DATA /* ZFS */ + if (ins(d, "SEEK_DATA", (long)SEEK_DATA)) return -1; +#endif + /* MS Windows */ #ifdef O_NOINHERIT /* Don't inherit in child processes. */