Commit bf19d169 authored by Martin Panter's avatar Martin Panter

Issue #23738: Document and test actual keyword parameter names

Also fix signature because os.utime(..., ns=None) is not allowed.
parent 5558d4f2
...@@ -59,7 +59,7 @@ The :mod:`binascii` module defines the following functions: ...@@ -59,7 +59,7 @@ The :mod:`binascii` module defines the following functions:
should be at most 57 to adhere to the base64 standard. should be at most 57 to adhere to the base64 standard.
.. function:: a2b_qp(string, header=False) .. function:: a2b_qp(data, header=False)
Convert a block of quoted-printable data back to binary and return the binary Convert a block of quoted-printable data back to binary and return the binary
data. More than one line may be passed at a time. If the optional argument data. More than one line may be passed at a time. If the optional argument
......
...@@ -863,9 +863,9 @@ as internal buffering of data. ...@@ -863,9 +863,9 @@ as internal buffering of data.
:data:`os.SEEK_HOLE` or :data:`os.SEEK_DATA`. :data:`os.SEEK_HOLE` or :data:`os.SEEK_DATA`.
.. function:: open(file, flags, mode=0o777, *, dir_fd=None) .. function:: open(path, flags, mode=0o777, *, dir_fd=None)
Open the file *file* and set various flags according to *flags* and possibly Open the file *path* and set various flags according to *flags* and possibly
its mode according to *mode*. When computing *mode*, the current umask value its mode according to *mode*. When computing *mode*, the current umask value
is first masked out. Return the file descriptor for the newly opened file. is first masked out. Return the file descriptor for the newly opened file.
The new file descriptor is :ref:`non-inheritable <fd_inheritance>`. The new file descriptor is :ref:`non-inheritable <fd_inheritance>`.
...@@ -1071,10 +1071,10 @@ or `the MSDN <http://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Window ...@@ -1071,10 +1071,10 @@ or `the MSDN <http://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Window
:meth:`~file.read` or :meth:`~file.readline` methods. :meth:`~file.read` or :meth:`~file.readline` methods.
.. function:: sendfile(out, in, offset, nbytes) .. function:: sendfile(out, in, offset, count)
sendfile(out, in, offset, nbytes, headers=None, trailers=None, flags=0) sendfile(out, in, offset, count, headers=None, trailers=None, flags=0)
Copy *nbytes* bytes from file descriptor *in* to file descriptor *out* Copy *count* bytes from file descriptor *in* to file descriptor *out*
starting at *offset*. starting at *offset*.
Return the number of bytes sent. When EOF is reached return 0. Return the number of bytes sent. When EOF is reached return 0.
...@@ -1088,7 +1088,7 @@ or `the MSDN <http://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Window ...@@ -1088,7 +1088,7 @@ or `the MSDN <http://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Window
*trailers* are arbitrary sequences of buffers that are written before and *trailers* are arbitrary sequences of buffers that are written before and
after the data from *in* is written. It returns the same as the first case. after the data from *in* is written. It returns the same as the first case.
On Mac OS X and FreeBSD, a value of 0 for *nbytes* specifies to send until On Mac OS X and FreeBSD, a value of 0 for *count* specifies to send until
the end of *in* is reached. the end of *in* is reached.
All platforms support sockets as *out* file descriptor, and some platforms All platforms support sockets as *out* file descriptor, and some platforms
...@@ -1683,10 +1683,10 @@ features: ...@@ -1683,10 +1683,10 @@ features:
The *dir_fd* argument. The *dir_fd* argument.
.. function:: mknod(filename, mode=0o600, device=0, *, dir_fd=None) .. function:: mknod(path, mode=0o600, device=0, *, dir_fd=None)
Create a filesystem node (file, device special file or named pipe) named Create a filesystem node (file, device special file or named pipe) named
*filename*. *mode* specifies both the permissions to use and the type of node *path*. *mode* specifies both the permissions to use and the type of node
to be created, being combined (bitwise OR) with one of ``stat.S_IFREG``, to be created, being combined (bitwise OR) with one of ``stat.S_IFREG``,
``stat.S_IFCHR``, ``stat.S_IFBLK``, and ``stat.S_IFIFO`` (those constants are ``stat.S_IFCHR``, ``stat.S_IFBLK``, and ``stat.S_IFIFO`` (those constants are
available in :mod:`stat`). For ``stat.S_IFCHR`` and ``stat.S_IFBLK``, available in :mod:`stat`). For ``stat.S_IFCHR`` and ``stat.S_IFBLK``,
...@@ -2210,9 +2210,9 @@ features: ...@@ -2210,9 +2210,9 @@ features:
.. versionadded:: 3.3 .. versionadded:: 3.3
.. function:: symlink(source, link_name, target_is_directory=False, *, dir_fd=None) .. function:: symlink(src, dst, target_is_directory=False, *, dir_fd=None)
Create a symbolic link pointing to *source* named *link_name*. Create a symbolic link pointing to *src* named *dst*.
On Windows, a symlink represents either a file or a directory, and does not On Windows, a symlink represents either a file or a directory, and does not
morph to the target dynamically. If the target is present, the type of the morph to the target dynamically. If the target is present, the type of the
...@@ -2282,20 +2282,20 @@ features: ...@@ -2282,20 +2282,20 @@ features:
The *dir_fd* parameter. The *dir_fd* parameter.
.. function:: utime(path, times=None, *, ns=None, dir_fd=None, follow_symlinks=True) .. function:: utime(path, times=None, *[, ns], dir_fd=None, follow_symlinks=True)
Set the access and modified times of the file specified by *path*. Set the access and modified times of the file specified by *path*.
:func:`utime` takes two optional parameters, *times* and *ns*. :func:`utime` takes two optional parameters, *times* and *ns*.
These specify the times set on *path* and are used as follows: These specify the times set on *path* and are used as follows:
- If *ns* is not ``None``, - If *ns* is specified,
it must be a 2-tuple of the form ``(atime_ns, mtime_ns)`` it must be a 2-tuple of the form ``(atime_ns, mtime_ns)``
where each member is an int expressing nanoseconds. where each member is an int expressing nanoseconds.
- If *times* is not ``None``, - If *times* is not ``None``,
it must be a 2-tuple of the form ``(atime, mtime)`` it must be a 2-tuple of the form ``(atime, mtime)``
where each member is an int or float expressing seconds. where each member is an int or float expressing seconds.
- If *times* and *ns* are both ``None``, - If *times* is ``None`` and *ns* is unspecified,
this is equivalent to specifying ``ns=(atime_ns, mtime_ns)`` this is equivalent to specifying ``ns=(atime_ns, mtime_ns)``
where both times are the current time. where both times are the current time.
...@@ -2846,9 +2846,10 @@ written in Python, such as a mail server's external command delivery program. ...@@ -2846,9 +2846,10 @@ written in Python, such as a mail server's external command delivery program.
Availability: Unix. Availability: Unix.
.. function:: popen(command, mode='r', buffering=-1) .. function:: popen(cmd, mode='r', buffering=-1)
Open a pipe to or from *command*. The return value is an open file object Open a pipe to or from command *cmd*.
The return value is an open file object
connected to the pipe, which can be read or written depending on whether *mode* connected to the pipe, which can be read or written depending on whether *mode*
is ``'r'`` (default) or ``'w'``. The *buffering* argument has the same meaning as is ``'r'`` (default) or ``'w'``. The *buffering* argument has the same meaning as
the corresponding argument to the built-in :func:`open` function. The the corresponding argument to the built-in :func:`open` function. The
......
...@@ -58,7 +58,7 @@ The available exception and functions in this module are: ...@@ -58,7 +58,7 @@ The available exception and functions in this module are:
Raises the :exc:`error` exception if any error occurs. Raises the :exc:`error` exception if any error occurs.
.. function:: compressobj(level=-1, method=DEFLATED, wbits=15, memlevel=8, strategy=Z_DEFAULT_STRATEGY[, zdict]) .. function:: compressobj(level=-1, method=DEFLATED, wbits=15, memLevel=8, strategy=Z_DEFAULT_STRATEGY[, zdict])
Returns a compression object, to be used for compressing data streams that won't Returns a compression object, to be used for compressing data streams that won't
fit into memory at once. fit into memory at once.
...@@ -75,9 +75,9 @@ The available exception and functions in this module are: ...@@ -75,9 +75,9 @@ The available exception and functions in this module are:
should be an integer from ``8`` to ``15``. Higher values give better should be an integer from ``8`` to ``15``. Higher values give better
compression, but use more memory. compression, but use more memory.
*memlevel* controls the amount of memory used for internal compression state. The *memLevel* argument controls the amount of memory used for the
Valid values range from ``1`` to ``9``. Higher values using more memory, internal compression state. Valid values range from ``1`` to ``9``.
but are faster and produce smaller output. Higher values use more memory, but are faster and produce smaller output.
*strategy* is used to tune the compression algorithm. Possible values are *strategy* is used to tune the compression algorithm. Possible values are
``Z_DEFAULT_STRATEGY``, ``Z_FILTERED``, and ``Z_HUFFMAN_ONLY``. ``Z_DEFAULT_STRATEGY``, ``Z_FILTERED``, and ``Z_HUFFMAN_ONLY``.
......
...@@ -179,6 +179,8 @@ class BinASCIITest(unittest.TestCase): ...@@ -179,6 +179,8 @@ class BinASCIITest(unittest.TestCase):
self.assertEqual(binascii.unhexlify(self.type2test(t)), u) self.assertEqual(binascii.unhexlify(self.type2test(t)), u)
def test_qp(self): def test_qp(self):
binascii.a2b_qp(data=b"", header=False) # Keyword arguments allowed
# A test for SF bug 534347 (segfaults without the proper fix) # A test for SF bug 534347 (segfaults without the proper fix)
try: try:
binascii.a2b_qp(b"", **{1:1}) binascii.a2b_qp(b"", **{1:1})
...@@ -186,6 +188,7 @@ class BinASCIITest(unittest.TestCase): ...@@ -186,6 +188,7 @@ class BinASCIITest(unittest.TestCase):
pass pass
else: else:
self.fail("binascii.a2b_qp(**{1:1}) didn't raise TypeError") self.fail("binascii.a2b_qp(**{1:1}) didn't raise TypeError")
self.assertEqual(binascii.a2b_qp(b"= "), b"= ") self.assertEqual(binascii.a2b_qp(b"= "), b"= ")
self.assertEqual(binascii.a2b_qp(b"=="), b"=") self.assertEqual(binascii.a2b_qp(b"=="), b"=")
self.assertEqual(binascii.a2b_qp(b"=AX"), b"=AX") self.assertEqual(binascii.a2b_qp(b"=AX"), b"=AX")
......
...@@ -58,7 +58,7 @@ HAVE_WHEEL_GROUP = sys.platform.startswith('freebsd') and os.getgid() == 0 ...@@ -58,7 +58,7 @@ HAVE_WHEEL_GROUP = sys.platform.startswith('freebsd') and os.getgid() == 0
# Tests creating TESTFN # Tests creating TESTFN
class FileTests(unittest.TestCase): class FileTests(unittest.TestCase):
def setUp(self): def setUp(self):
if os.path.exists(support.TESTFN): if os.path.lexists(support.TESTFN):
os.unlink(support.TESTFN) os.unlink(support.TESTFN)
tearDown = setUp tearDown = setUp
...@@ -162,6 +162,19 @@ class FileTests(unittest.TestCase): ...@@ -162,6 +162,19 @@ class FileTests(unittest.TestCase):
with open(TESTFN2, 'r') as f: with open(TESTFN2, 'r') as f:
self.assertEqual(f.read(), "1") self.assertEqual(f.read(), "1")
def test_open_keywords(self):
f = os.open(path=__file__, flags=os.O_RDONLY, mode=0o777,
dir_fd=None)
os.close(f)
def test_symlink_keywords(self):
symlink = support.get_attribute(os, "symlink")
try:
symlink(src='target', dst=support.TESTFN,
target_is_directory=False, dir_fd=None)
except (NotImplementedError, OSError):
pass # No OS support or unprivileged user
# Test attributes on return values from os.*stat* family. # Test attributes on return values from os.*stat* family.
class StatAttributeTests(unittest.TestCase): class StatAttributeTests(unittest.TestCase):
...@@ -2151,6 +2164,14 @@ class TestSendfile(unittest.TestCase): ...@@ -2151,6 +2164,14 @@ class TestSendfile(unittest.TestCase):
os.sendfile(self.sockno, self.fileno, -1, 4096) os.sendfile(self.sockno, self.fileno, -1, 4096)
self.assertEqual(cm.exception.errno, errno.EINVAL) self.assertEqual(cm.exception.errno, errno.EINVAL)
def test_keywords(self):
# Keyword arguments should be supported
os.sendfile(out=self.sockno, offset=0, count=4096,
**{'in': self.fileno})
if self.SUPPORT_HEADERS_TRAILERS:
os.sendfile(self.sockno, self.fileno, offset=0, count=4096,
headers=None, trailers=None, flags=0)
# --- headers / trailers tests # --- headers / trailers tests
@requires_headers_trailers @requires_headers_trailers
......
...@@ -57,6 +57,10 @@ class PopenTest(unittest.TestCase): ...@@ -57,6 +57,10 @@ class PopenTest(unittest.TestCase):
with os.popen("echo hello") as f: with os.popen("echo hello") as f:
self.assertEqual(list(f), ["hello\n"]) self.assertEqual(list(f), ["hello\n"])
def test_keywords(self):
with os.popen(cmd="exit 0", mode="w", buffering=-1):
pass
def test_main(): def test_main():
support.run_unittest(PopenTest) support.run_unittest(PopenTest)
......
...@@ -443,6 +443,14 @@ class PosixTester(unittest.TestCase): ...@@ -443,6 +443,14 @@ class PosixTester(unittest.TestCase):
else: else:
self.assertTrue(stat.S_ISFIFO(posix.stat(support.TESTFN).st_mode)) self.assertTrue(stat.S_ISFIFO(posix.stat(support.TESTFN).st_mode))
# Keyword arguments are also supported
support.unlink(support.TESTFN)
try:
posix.mknod(path=support.TESTFN, mode=mode, device=0,
dir_fd=None)
except OSError as e:
self.assertIn(e.errno, (errno.EPERM, errno.EINVAL))
@unittest.skipUnless(hasattr(posix, 'stat'), 'test needs posix.stat()') @unittest.skipUnless(hasattr(posix, 'stat'), 'test needs posix.stat()')
@unittest.skipUnless(hasattr(posix, 'makedev'), 'test needs posix.makedev()') @unittest.skipUnless(hasattr(posix, 'makedev'), 'test needs posix.makedev()')
def test_makedev(self): def test_makedev(self):
......
...@@ -222,9 +222,9 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase): ...@@ -222,9 +222,9 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase):
level = 2 level = 2
method = zlib.DEFLATED method = zlib.DEFLATED
wbits = -12 wbits = -12
memlevel = 9 memLevel = 9
strategy = zlib.Z_FILTERED strategy = zlib.Z_FILTERED
co = zlib.compressobj(level, method, wbits, memlevel, strategy) co = zlib.compressobj(level, method, wbits, memLevel, strategy)
x1 = co.compress(HAMLET_SCENE) x1 = co.compress(HAMLET_SCENE)
x2 = co.flush() x2 = co.flush()
dco = zlib.decompressobj(wbits) dco = zlib.decompressobj(wbits)
...@@ -232,6 +232,10 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase): ...@@ -232,6 +232,10 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase):
y2 = dco.flush() y2 = dco.flush()
self.assertEqual(HAMLET_SCENE, y1 + y2) self.assertEqual(HAMLET_SCENE, y1 + y2)
# keyword arguments should also be supported
zlib.compressobj(level=level, method=method, wbits=wbits,
memLevel=memLevel, strategy=strategy, zdict=b"")
def test_compressincremental(self): def test_compressincremental(self):
# compress object in steps, decompress object as one-shot # compress object in steps, decompress object as one-shot
data = HAMLET_SCENE * 128 data = HAMLET_SCENE * 128
......
...@@ -4695,7 +4695,7 @@ posix_uname(PyObject *self, PyObject *noargs) ...@@ -4695,7 +4695,7 @@ posix_uname(PyObject *self, PyObject *noargs)
PyDoc_STRVAR(posix_utime__doc__, PyDoc_STRVAR(posix_utime__doc__,
"utime(path, times=None, *, ns=None, dir_fd=None, follow_symlinks=True)\n\ "utime(path, times=None, *[, ns], dir_fd=None, follow_symlinks=True)\n\
Set the access and modified time of path.\n\ Set the access and modified time of path.\n\
\n\ \n\
path may always be specified as a string.\n\ path may always be specified as a string.\n\
...@@ -4704,10 +4704,10 @@ On some platforms, path may also be specified as an open file descriptor.\n\ ...@@ -4704,10 +4704,10 @@ On some platforms, path may also be specified as an open file descriptor.\n\
\n\ \n\
If times is not None, it must be a tuple (atime, mtime);\n\ If times is not None, it must be a tuple (atime, mtime);\n\
atime and mtime should be expressed as float seconds since the epoch.\n\ atime and mtime should be expressed as float seconds since the epoch.\n\
If ns is not None, it must be a tuple (atime_ns, mtime_ns);\n\ If ns is specified, it must be a tuple (atime_ns, mtime_ns);\n\
atime_ns and mtime_ns should be expressed as integer nanoseconds\n\ atime_ns and mtime_ns should be expressed as integer nanoseconds\n\
since the epoch.\n\ since the epoch.\n\
If both times and ns are None, utime uses the current time.\n\ If times is None and ns is unspecified, utime uses the current time.\n\
Specifying tuples for both times and ns is an error.\n\ Specifying tuples for both times and ns is an error.\n\
\n\ \n\
If dir_fd is not None, it should be a file descriptor open to a directory,\n\ If dir_fd is not None, it should be a file descriptor open to a directory,\n\
...@@ -8245,10 +8245,10 @@ posix_write(PyObject *self, PyObject *args) ...@@ -8245,10 +8245,10 @@ posix_write(PyObject *self, PyObject *args)
#ifdef HAVE_SENDFILE #ifdef HAVE_SENDFILE
PyDoc_STRVAR(posix_sendfile__doc__, PyDoc_STRVAR(posix_sendfile__doc__,
"sendfile(out, in, offset, nbytes) -> byteswritten\n\ "sendfile(out, in, offset, count) -> byteswritten\n\
sendfile(out, in, offset, nbytes, headers=None, trailers=None, flags=0)\n\ sendfile(out, in, offset, count, headers=None, trailers=None, flags=0)\n\
-> byteswritten\n\ -> byteswritten\n\
Copy nbytes bytes from file descriptor in to file descriptor out."); Copy count bytes from file descriptor in to file descriptor out.");
static PyObject * static PyObject *
posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict) posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
...@@ -8266,6 +8266,7 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict) ...@@ -8266,6 +8266,7 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
off_t sbytes; off_t sbytes;
struct sf_hdtr sf; struct sf_hdtr sf;
int flags = 0; int flags = 0;
/* Beware that "in" clashes with Python's own "in" operator keyword */
static char *keywords[] = {"out", "in", static char *keywords[] = {"out", "in",
"offset", "count", "offset", "count",
"headers", "trailers", "flags", NULL}; "headers", "trailers", "flags", NULL};
...@@ -8655,9 +8656,9 @@ exit: ...@@ -8655,9 +8656,9 @@ exit:
#if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) #if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV)
PyDoc_STRVAR(posix_mknod__doc__, PyDoc_STRVAR(posix_mknod__doc__,
"mknod(filename, mode=0o600, device=0, *, dir_fd=None)\n\n\ "mknod(path, mode=0o600, device=0, *, dir_fd=None)\n\n\
Create a filesystem node (file, device special file or named pipe)\n\ Create a filesystem node (file, device special file or named pipe)\n\
named filename. mode specifies both the permissions to use and the\n\ named path. mode specifies both the permissions to use and the\n\
type of node to be created, being combined (bitwise OR) with one of\n\ type of node to be created, being combined (bitwise OR) with one of\n\
S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. For S_IFCHR and S_IFBLK,\n\ S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. For S_IFCHR and S_IFBLK,\n\
device defines the newly created device special file (probably using\n\ device defines the newly created device special file (probably using\n\
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment