From df1b69944796caa6854049caf624d32c408c27d5 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sun, 9 Nov 2014 15:56:33 -0800 Subject: [PATCH 1/5] Issue #22823: Use set literals instead of creating a set from a list --- Doc/howto/logging-cookbook.rst | 2 +- Doc/library/pickle.rst | 2 +- Lib/_strptime.py | 4 ++-- Lib/asyncore.py | 6 +++--- Lib/ipaddress.py | 2 +- Lib/mailbox.py | 4 ++-- Lib/sre_compile.py | 8 ++++---- Lib/sre_parse.py | 4 ++-- Lib/statistics.py | 4 ++-- Parser/asdl.py | 3 +-- 10 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index e77e73077bf..7205566609d 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -1680,7 +1680,7 @@ as in the following complete example:: def main(): logging.basicConfig(level=logging.INFO, format='%(message)s') - logging.info(_('message 1', set_value=set([1, 2, 3]), snowman='\u2603')) + logging.info(_('message 1', set_value={1, 2, 3}, snowman='\u2603')) if __name__ == '__main__': main() diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst index 47356f9f0cf..4ce4d345af4 100644 --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -859,7 +859,7 @@ For the simplest code, use the :func:`dump` and :func:`load` functions. :: data = { 'a': [1, 2.0, 3, 4+6j], 'b': ("character string", b"byte string"), - 'c': set([None, True, False]) + 'c': {None, True, False} } with open('data.pickle', 'wb') as f: diff --git a/Lib/_strptime.py b/Lib/_strptime.py index 53bd34be806..42f23d3d54b 100644 --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -167,9 +167,9 @@ class LocaleTime(object): time.tzset() except AttributeError: pass - no_saving = frozenset(["utc", "gmt", time.tzname[0].lower()]) + no_saving = frozenset({"utc", "gmt", time.tzname[0].lower()}) if time.daylight: - has_saving = frozenset([time.tzname[1].lower()]) + has_saving = frozenset({time.tzname[1].lower()}) else: has_saving = frozenset() self.timezone = (no_saving, has_saving) diff --git a/Lib/asyncore.py b/Lib/asyncore.py index da24b3843b3..68efd45f858 100644 --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -57,8 +57,8 @@ from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ errorcode -_DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, - EBADF)) +_DISCONNECTED = frozenset({ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, + EBADF}) try: socket_map @@ -220,7 +220,7 @@ class dispatcher: connecting = False closing = False addr = None - ignore_log_types = frozenset(['warning']) + ignore_log_types = frozenset({'warning'}) def __init__(self, sock=None, map=None): if map is None: diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index ced9e7953bc..d15a1d923fc 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1088,7 +1088,7 @@ class _BaseV4: _DECIMAL_DIGITS = frozenset('0123456789') # the valid octets for host and netmasks. only useful for IPv4. - _valid_mask_octets = frozenset((255, 254, 252, 248, 240, 224, 192, 128, 0)) + _valid_mask_octets = frozenset({255, 254, 252, 248, 240, 224, 192, 128, 0}) _max_prefixlen = IPV4LENGTH # There are only a handful of valid v4 netmasks, so we cache them all diff --git a/Lib/mailbox.py b/Lib/mailbox.py index 2eee76cfe50..145b2040c9b 100644 --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -1230,8 +1230,8 @@ class MH(Mailbox): class Babyl(_singlefileMailbox): """An Rmail-style Babyl mailbox.""" - _special_labels = frozenset(('unseen', 'deleted', 'filed', 'answered', - 'forwarded', 'edited', 'resent')) + _special_labels = frozenset({'unseen', 'deleted', 'filed', 'answered', + 'forwarded', 'edited', 'resent'}) def __init__(self, path, factory=None, create=True): """Initialize a Babyl mailbox.""" diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py index 1b3e9f82e34..3b632ed9263 100644 --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -22,10 +22,10 @@ if _sre.CODESIZE == 2: else: MAXCODE = 0xFFFFFFFF -_LITERAL_CODES = set([LITERAL, NOT_LITERAL]) -_REPEATING_CODES = set([REPEAT, MIN_REPEAT, MAX_REPEAT]) -_SUCCESS_CODES = set([SUCCESS, FAILURE]) -_ASSERT_CODES = set([ASSERT, ASSERT_NOT]) +_LITERAL_CODES = {LITERAL, NOT_LITERAL} +_REPEATING_CODES = {REPEAT, MIN_REPEAT, MAX_REPEAT} +_SUCCESS_CODES = {SUCCESS, FAILURE} +_ASSERT_CODES = {ASSERT, ASSERT_NOT} def _compile(code, pattern, flags): # internal: compile a (sub)pattern diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py index edc3ff143ac..57b15e7be38 100644 --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -25,8 +25,8 @@ HEXDIGITS = frozenset("0123456789abcdefABCDEF") WHITESPACE = frozenset(" \t\n\r\v\f") -_REPEATCODES = frozenset((MIN_REPEAT, MAX_REPEAT)) -_UNITCODES = frozenset((ANY, RANGE, IN, LITERAL, NOT_LITERAL, CATEGORY)) +_REPEATCODES = frozenset({MIN_REPEAT, MAX_REPEAT}) +_UNITCODES = frozenset({ANY, RANGE, IN, LITERAL, NOT_LITERAL, CATEGORY}) ESCAPES = { r"\a": (LITERAL, ord("\a")), diff --git a/Lib/statistics.py b/Lib/statistics.py index 25a26d4aa71..3972ed2e5f7 100644 --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -150,7 +150,7 @@ def _sum(data, start=0): # We fail as soon as we reach a value that is not an int or the type of # the first value which is not an int. E.g. _sum([int, int, float, int]) # is okay, but sum([int, int, float, Fraction]) is not. - allowed_types = set([int, type(start)]) + allowed_types = {int, type(start)} n, d = _exact_ratio(start) partials = {d: n} # map {denominator: sum of numerators} # Micro-optimizations. @@ -168,7 +168,7 @@ def _sum(data, start=0): assert allowed_types.pop() is int T = int else: - T = (allowed_types - set([int])).pop() + T = (allowed_types - {int}).pop() if None in partials: assert issubclass(T, (float, Decimal)) assert not math.isfinite(partials[None]) diff --git a/Parser/asdl.py b/Parser/asdl.py index 4618416c57a..121cdab9520 100644 --- a/Parser/asdl.py +++ b/Parser/asdl.py @@ -33,8 +33,7 @@ __all__ = [ # See the EBNF at the top of the file to understand the logical connection # between the various node types. -builtin_types = set( - ['identifier', 'string', 'bytes', 'int', 'object', 'singleton']) +builtin_types = {'identifier', 'string', 'bytes', 'int', 'object', 'singleton'} class AST: def __repr__(self): From 86e9b6b16424ddbdd1a4a393cd295e95835b7ef2 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sun, 9 Nov 2014 17:20:56 -0800 Subject: [PATCH 2/5] Issue 22830: Clarify docs for functools.cmp_to_key(). --- Doc/library/functools.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 7fd7d5826b6..d87fa58dd70 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -21,8 +21,8 @@ The :mod:`functools` module defines the following functions: .. function:: cmp_to_key(func) - Transform an old-style comparison function to a key function. Used with - tools that accept key functions (such as :func:`sorted`, :func:`min`, + Transform an old-style comparison function to a :term:`key function`. Used + with tools that accept key functions (such as :func:`sorted`, :func:`min`, :func:`max`, :func:`heapq.nlargest`, :func:`heapq.nsmallest`, :func:`itertools.groupby`). This function is primarily used as a transition tool for programs being converted from Python 2 which supported the use of @@ -31,13 +31,14 @@ The :mod:`functools` module defines the following functions: A comparison function is any callable that accept two arguments, compares them, and returns a negative number for less-than, zero for equality, or a positive number for greater-than. A key function is a callable that accepts one - argument and returns another value indicating the position in the desired - collation sequence. + argument and returns another value to be used as the sort key. Example:: sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order + For sorting examples and a brief sorting tutorial, see :ref:`sortinghowto`. + .. versionadded:: 3.2 From b7299ddbc7b504220e67ee026e5587a346c0ce3a Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sun, 9 Nov 2014 20:22:01 -0500 Subject: [PATCH 3/5] Issue 20152, 22821: Port the fcntl module to Argument Clinic. Along the way, fix an argumrnt to fcntl.fcntl to be an int instead of a long. Thanks to Serhiy Storchaka for reviewing my Clinic patch and for writing the patch to fix the long/int issue. --- Modules/clinic/fcntlmodule.c.h | 188 ++++++++++++++ Modules/fcntlmodule.c | 432 +++++++++++++++++---------------- 2 files changed, 413 insertions(+), 207 deletions(-) create mode 100644 Modules/clinic/fcntlmodule.c.h diff --git a/Modules/clinic/fcntlmodule.c.h b/Modules/clinic/fcntlmodule.c.h new file mode 100644 index 00000000000..377e55d8c5c --- /dev/null +++ b/Modules/clinic/fcntlmodule.c.h @@ -0,0 +1,188 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(fcntl_fcntl__doc__, +"fcntl($module, fd, code, arg=None, /)\n" +"--\n" +"\n" +"Perform the operation `code` on file descriptor fd.\n" +"\n" +"The values used for `code` are operating system dependent, and are available\n" +"as constants in the fcntl module, using the same names as used in\n" +"the relevant C header files. The argument arg is optional, and\n" +"defaults to 0; it may be an int or a string. If arg is given as a string,\n" +"the return value of fcntl is a string of that length, containing the\n" +"resulting value put in the arg buffer by the operating system. The length\n" +"of the arg string is not allowed to exceed 1024 bytes. If the arg given\n" +"is an integer or if none is specified, the result value is an integer\n" +"corresponding to the return value of the fcntl call in the C code."); + +#define FCNTL_FCNTL_METHODDEF \ + {"fcntl", (PyCFunction)fcntl_fcntl, METH_VARARGS, fcntl_fcntl__doc__}, + +static PyObject * +fcntl_fcntl_impl(PyModuleDef *module, int fd, int code, PyObject *arg); + +static PyObject * +fcntl_fcntl(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + int code; + PyObject *arg = NULL; + + if (!PyArg_ParseTuple(args, + "O&i|O:fcntl", + conv_descriptor, &fd, &code, &arg)) + goto exit; + return_value = fcntl_fcntl_impl(module, fd, code, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(fcntl_ioctl__doc__, +"ioctl($module, fd, op, arg=None, mutate_flag=True, /)\n" +"--\n" +"\n" +"Perform the operation op on file descriptor fd.\n" +"\n" +"The values used for op are operating system dependent, and are available as\n" +"constants in the fcntl or termios library modules, using the same names as\n" +"used in the relevant C header files.\n" +"\n" +"The argument `arg` is optional, and defaults to 0; it may be an int or a\n" +"buffer containing character data (most likely a string or an array).\n" +"\n" +"If the argument is a mutable buffer (such as an array) and if the\n" +"mutate_flag argument (which is only allowed in this case) is true then the\n" +"buffer is (in effect) passed to the operating system and changes made by\n" +"the OS will be reflected in the contents of the buffer after the call has\n" +"returned. The return value is the integer returned by the ioctl system\n" +"call.\n" +"\n" +"If the argument is a mutable buffer and the mutable_flag argument is not\n" +"passed or is false, the behavior is as if a string had been passed. This\n" +"behavior will change in future releases of Python.\n" +"\n" +"If the argument is an immutable buffer (most likely a string) then a copy\n" +"of the buffer is passed to the operating system and the return value is a\n" +"string of the same length containing whatever the operating system put in\n" +"the buffer. The length of the arg buffer in this case is not allowed to\n" +"exceed 1024 bytes.\n" +"\n" +"If the arg given is an integer or if none is specified, the result value is\n" +"an integer corresponding to the return value of the ioctl call in the C\n" +"code."); + +#define FCNTL_IOCTL_METHODDEF \ + {"ioctl", (PyCFunction)fcntl_ioctl, METH_VARARGS, fcntl_ioctl__doc__}, + +static PyObject * +fcntl_ioctl_impl(PyModuleDef *module, int fd, unsigned int code, PyObject *ob_arg, int mutate_arg); + +static PyObject * +fcntl_ioctl(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + unsigned int code; + PyObject *ob_arg = NULL; + int mutate_arg = 1; + + if (!PyArg_ParseTuple(args, + "O&I|Op:ioctl", + conv_descriptor, &fd, &code, &ob_arg, &mutate_arg)) + goto exit; + return_value = fcntl_ioctl_impl(module, fd, code, ob_arg, mutate_arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(fcntl_flock__doc__, +"flock($module, fd, code, /)\n" +"--\n" +"\n" +"Perform the lock operation op on file descriptor fd.\n" +"\n" +"See the Unix manual page for flock(2) for details (On some systems, this\n" +"function is emulated using fcntl())."); + +#define FCNTL_FLOCK_METHODDEF \ + {"flock", (PyCFunction)fcntl_flock, METH_VARARGS, fcntl_flock__doc__}, + +static PyObject * +fcntl_flock_impl(PyModuleDef *module, int fd, int code); + +static PyObject * +fcntl_flock(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + int code; + + if (!PyArg_ParseTuple(args, + "O&i:flock", + conv_descriptor, &fd, &code)) + goto exit; + return_value = fcntl_flock_impl(module, fd, code); + +exit: + return return_value; +} + +PyDoc_STRVAR(fcntl_lockf__doc__, +"lockf($module, fd, code, lenobj=None, startobj=None, whence=0, /)\n" +"--\n" +"\n" +"A wrapper around the fcntl() locking calls.\n" +"\n" +"fd is the file descriptor of the file to lock or unlock, and operation is one\n" +"of the following values:\n" +"\n" +" LOCK_UN - unlock\n" +" LOCK_SH - acquire a shared lock\n" +" LOCK_EX - acquire an exclusive lock\n" +"\n" +"When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n" +"LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the\n" +"lock cannot be acquired, an IOError will be raised and the exception will\n" +"have an errno attribute set to EACCES or EAGAIN (depending on the operating\n" +"system -- for portability, check for either value).\n" +"\n" +"length is the number of bytes to lock, with the default meaning to lock to\n" +"EOF. start is the byte offset, relative to whence, to that the lock\n" +"starts. whence is as with fileobj.seek(), specifically:\n" +"\n" +" 0 - relative to the start of the file (SEEK_SET)\n" +" 1 - relative to the current buffer position (SEEK_CUR)\n" +" 2 - relative to the end of the file (SEEK_END)"); + +#define FCNTL_LOCKF_METHODDEF \ + {"lockf", (PyCFunction)fcntl_lockf, METH_VARARGS, fcntl_lockf__doc__}, + +static PyObject * +fcntl_lockf_impl(PyModuleDef *module, int fd, int code, PyObject *lenobj, PyObject *startobj, int whence); + +static PyObject * +fcntl_lockf(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + int code; + PyObject *lenobj = NULL; + PyObject *startobj = NULL; + int whence = 0; + + if (!PyArg_ParseTuple(args, + "O&i|OOi:lockf", + conv_descriptor, &fd, &code, &lenobj, &startobj, &whence)) + goto exit; + return_value = fcntl_lockf_impl(module, fd, code, lenobj, startobj, whence); + +exit: + return return_value; +} +/*[clinic end generated code: output=84bdde73a92f7c61 input=a9049054013a1b77]*/ diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c index 56e40212d1c..87662dd66ed 100644 --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -15,6 +15,12 @@ #include #endif +/*[clinic input] +output preset file +module fcntl +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c7356fdb126a904a]*/ + static int conv_descriptor(PyObject *object, int *target) { @@ -26,48 +32,72 @@ conv_descriptor(PyObject *object, int *target) return 1; } +/* Must come after conv_descriptor definition. */ +#include "clinic/fcntlmodule.c.h" -/* fcntl(fd, op, [arg]) */ +/*[clinic input] +fcntl.fcntl + + fd: object(type='int', converter='conv_descriptor') + code: int + arg: object = NULL + / + +Perform the operation `code` on file descriptor fd. + +The values used for `code` are operating system dependent, and are available +as constants in the fcntl module, using the same names as used in +the relevant C header files. The argument arg is optional, and +defaults to 0; it may be an int or a string. If arg is given as a string, +the return value of fcntl is a string of that length, containing the +resulting value put in the arg buffer by the operating system. The length +of the arg string is not allowed to exceed 1024 bytes. If the arg given +is an integer or if none is specified, the result value is an integer +corresponding to the return value of the fcntl call in the C code. +[clinic start generated code]*/ static PyObject * -fcntl_fcntl(PyObject *self, PyObject *args) +fcntl_fcntl_impl(PyModuleDef *module, int fd, int code, PyObject *arg) +/*[clinic end generated code: output=afc5bfa74a03ef0d input=4850c13a41e86930]*/ { - int fd; - int code; - long arg; + int int_arg = 0; int ret; char *str; Py_ssize_t len; char buf[1024]; - if (PyArg_ParseTuple(args, "O&is#:fcntl", - conv_descriptor, &fd, &code, &str, &len)) { - if ((size_t)len > sizeof buf) { - PyErr_SetString(PyExc_ValueError, - "fcntl string arg too long"); - return NULL; + if (arg != NULL) { + int parse_result; + + if (PyArg_Parse(arg, "s#", &str, &len)) { + if ((size_t)len > sizeof buf) { + PyErr_SetString(PyExc_ValueError, + "fcntl string arg too long"); + return NULL; + } + memcpy(buf, str, len); + Py_BEGIN_ALLOW_THREADS + ret = fcntl(fd, code, buf); + Py_END_ALLOW_THREADS + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyBytes_FromStringAndSize(buf, len); } - memcpy(buf, str, len); - Py_BEGIN_ALLOW_THREADS - ret = fcntl(fd, code, buf); - Py_END_ALLOW_THREADS - if (ret < 0) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; + + PyErr_Clear(); + parse_result = PyArg_Parse(arg, + "l;fcntl requires a file or file descriptor," + " an integer and optionally a third integer or a string", + &int_arg); + if (!parse_result) { + return NULL; } - return PyBytes_FromStringAndSize(buf, len); } - PyErr_Clear(); - arg = 0; - if (!PyArg_ParseTuple(args, - "O&i|l;fcntl requires a file or file descriptor," - " an integer and optionally a third integer or a string", - conv_descriptor, &fd, &code, &arg)) { - return NULL; - } Py_BEGIN_ALLOW_THREADS - ret = fcntl(fd, code, arg); + ret = fcntl(fd, code, int_arg); Py_END_ALLOW_THREADS if (ret < 0) { PyErr_SetFromErrno(PyExc_IOError); @@ -76,29 +106,53 @@ fcntl_fcntl(PyObject *self, PyObject *args) return PyLong_FromLong((long)ret); } -PyDoc_STRVAR(fcntl_doc, -"fcntl(fd, op, [arg])\n\ -\n\ -Perform the operation op on file descriptor fd. The values used\n\ -for op are operating system dependent, and are available\n\ -as constants in the fcntl module, using the same names as used in\n\ -the relevant C header files. The argument arg is optional, and\n\ -defaults to 0; it may be an int or a string. If arg is given as a string,\n\ -the return value of fcntl is a string of that length, containing the\n\ -resulting value put in the arg buffer by the operating system. The length\n\ -of the arg string is not allowed to exceed 1024 bytes. If the arg given\n\ -is an integer or if none is specified, the result value is an integer\n\ -corresponding to the return value of the fcntl call in the C code."); +/*[clinic input] +fcntl.ioctl -/* ioctl(fd, op, [arg]) */ + fd: object(type='int', converter='conv_descriptor') + op as code: unsigned_int(bitwise=True) + arg as ob_arg: object = NULL + mutate_flag as mutate_arg: bool = True + / + +Perform the operation op on file descriptor fd. + +The values used for op are operating system dependent, and are available as +constants in the fcntl or termios library modules, using the same names as +used in the relevant C header files. + +The argument `arg` is optional, and defaults to 0; it may be an int or a +buffer containing character data (most likely a string or an array). + +If the argument is a mutable buffer (such as an array) and if the +mutate_flag argument (which is only allowed in this case) is true then the +buffer is (in effect) passed to the operating system and changes made by +the OS will be reflected in the contents of the buffer after the call has +returned. The return value is the integer returned by the ioctl system +call. + +If the argument is a mutable buffer and the mutable_flag argument is not +passed or is false, the behavior is as if a string had been passed. This +behavior will change in future releases of Python. + +If the argument is an immutable buffer (most likely a string) then a copy +of the buffer is passed to the operating system and the return value is a +string of the same length containing whatever the operating system put in +the buffer. The length of the arg buffer in this case is not allowed to +exceed 1024 bytes. + +If the arg given is an integer or if none is specified, the result value is +an integer corresponding to the return value of the ioctl call in the C +code. +[clinic start generated code]*/ static PyObject * -fcntl_ioctl(PyObject *self, PyObject *args) +fcntl_ioctl_impl(PyModuleDef *module, int fd, unsigned int code, PyObject *ob_arg, int mutate_arg) +/*[clinic end generated code: output=ad47738c118622bf input=a55a6ee8e494c449]*/ { #define IOCTL_BUFSZ 1024 - int fd; - /* In PyArg_ParseTuple below, we use the unsigned non-checked 'I' + /* We use the unsigned non-checked 'I' format for the 'code' parameter because Python turns 0x8000000 into either a large positive number (PyLong or PyInt on 64-bit platforms) or a negative number on others (32-bit PyInt) @@ -111,101 +165,98 @@ fcntl_ioctl(PyObject *self, PyObject *args) in their unsigned long ioctl codes this will break and need special casing based on the platform being built on. */ - unsigned int code; - int arg; + int arg = 0; int ret; Py_buffer pstr; char *str; Py_ssize_t len; - int mutate_arg = 1; char buf[IOCTL_BUFSZ+1]; /* argument plus NUL byte */ - if (PyArg_ParseTuple(args, "O&Iw*|i:ioctl", - conv_descriptor, &fd, &code, - &pstr, &mutate_arg)) { - char *arg; - str = pstr.buf; - len = pstr.len; + if (ob_arg != NULL) { + if (PyArg_Parse(ob_arg, "w*:ioctl", &pstr)) { + char *arg; + str = pstr.buf; + len = pstr.len; - if (mutate_arg) { - if (len <= IOCTL_BUFSZ) { - memcpy(buf, str, len); - buf[len] = '\0'; - arg = buf; + if (mutate_arg) { + if (len <= IOCTL_BUFSZ) { + memcpy(buf, str, len); + buf[len] = '\0'; + arg = buf; + } + else { + arg = str; + } } else { - arg = str; + if (len > IOCTL_BUFSZ) { + PyBuffer_Release(&pstr); + PyErr_SetString(PyExc_ValueError, + "ioctl string arg too long"); + return NULL; + } + else { + memcpy(buf, str, len); + buf[len] = '\0'; + arg = buf; + } + } + if (buf == arg) { + Py_BEGIN_ALLOW_THREADS /* think array.resize() */ + ret = ioctl(fd, code, arg); + Py_END_ALLOW_THREADS + } + else { + ret = ioctl(fd, code, arg); + } + if (mutate_arg && (len <= IOCTL_BUFSZ)) { + memcpy(str, buf, len); + } + PyBuffer_Release(&pstr); /* No further access to str below this point */ + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + if (mutate_arg) { + return PyLong_FromLong(ret); + } + else { + return PyBytes_FromStringAndSize(buf, len); } } - else { + + PyErr_Clear(); + if (PyArg_Parse(ob_arg, "s*:ioctl", &pstr)) { + str = pstr.buf; + len = pstr.len; if (len > IOCTL_BUFSZ) { PyBuffer_Release(&pstr); PyErr_SetString(PyExc_ValueError, - "ioctl string arg too long"); + "ioctl string arg too long"); return NULL; } - else { - memcpy(buf, str, len); - buf[len] = '\0'; - arg = buf; - } - } - if (buf == arg) { - Py_BEGIN_ALLOW_THREADS /* think array.resize() */ - ret = ioctl(fd, code, arg); + memcpy(buf, str, len); + buf[len] = '\0'; + Py_BEGIN_ALLOW_THREADS + ret = ioctl(fd, code, buf); Py_END_ALLOW_THREADS - } - else { - ret = ioctl(fd, code, arg); - } - if (mutate_arg && (len <= IOCTL_BUFSZ)) { - memcpy(str, buf, len); - } - PyBuffer_Release(&pstr); /* No further access to str below this point */ - if (ret < 0) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - if (mutate_arg) { - return PyLong_FromLong(ret); - } - else { + if (ret < 0) { + PyBuffer_Release(&pstr); + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + PyBuffer_Release(&pstr); return PyBytes_FromStringAndSize(buf, len); } - } - PyErr_Clear(); - if (PyArg_ParseTuple(args, "O&Is*:ioctl", - conv_descriptor, &fd, &code, &pstr)) { - str = pstr.buf; - len = pstr.len; - if (len > IOCTL_BUFSZ) { - PyBuffer_Release(&pstr); - PyErr_SetString(PyExc_ValueError, - "ioctl string arg too long"); - return NULL; + PyErr_Clear(); + if (!PyArg_Parse(ob_arg, + "i;ioctl requires a file or file descriptor," + " an integer and optionally an integer or buffer argument", + &arg)) { + return NULL; } - memcpy(buf, str, len); - buf[len] = '\0'; - Py_BEGIN_ALLOW_THREADS - ret = ioctl(fd, code, buf); - Py_END_ALLOW_THREADS - if (ret < 0) { - PyBuffer_Release(&pstr); - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - PyBuffer_Release(&pstr); - return PyBytes_FromStringAndSize(buf, len); - } - - PyErr_Clear(); - arg = 0; - if (!PyArg_ParseTuple(args, - "O&I|i;ioctl requires a file or file descriptor," - " an integer and optionally an integer or buffer argument", - conv_descriptor, &fd, &code, &arg)) { - return NULL; + // Fall-through to outside the 'if' statement. } Py_BEGIN_ALLOW_THREADS ret = ioctl(fd, code, arg); @@ -218,52 +269,25 @@ fcntl_ioctl(PyObject *self, PyObject *args) #undef IOCTL_BUFSZ } -PyDoc_STRVAR(ioctl_doc, -"ioctl(fd, op[, arg[, mutate_flag]])\n\ -\n\ -Perform the operation op on file descriptor fd. The values used for op\n\ -are operating system dependent, and are available as constants in the\n\ -fcntl or termios library modules, using the same names as used in the\n\ -relevant C header files.\n\ -\n\ -The argument arg is optional, and defaults to 0; it may be an int or a\n\ -buffer containing character data (most likely a string or an array). \n\ -\n\ -If the argument is a mutable buffer (such as an array) and if the\n\ -mutate_flag argument (which is only allowed in this case) is true then the\n\ -buffer is (in effect) passed to the operating system and changes made by\n\ -the OS will be reflected in the contents of the buffer after the call has\n\ -returned. The return value is the integer returned by the ioctl system\n\ -call.\n\ -\n\ -If the argument is a mutable buffer and the mutable_flag argument is not\n\ -passed or is false, the behavior is as if a string had been passed. This\n\ -behavior will change in future releases of Python.\n\ -\n\ -If the argument is an immutable buffer (most likely a string) then a copy\n\ -of the buffer is passed to the operating system and the return value is a\n\ -string of the same length containing whatever the operating system put in\n\ -the buffer. The length of the arg buffer in this case is not allowed to\n\ -exceed 1024 bytes.\n\ -\n\ -If the arg given is an integer or if none is specified, the result value is\n\ -an integer corresponding to the return value of the ioctl call in the C\n\ -code."); +/*[clinic input] +fcntl.flock + fd: object(type='int', converter='conv_descriptor') + code: int + / -/* flock(fd, operation) */ +Perform the lock operation op on file descriptor fd. + +See the Unix manual page for flock(2) for details (On some systems, this +function is emulated using fcntl()). +[clinic start generated code]*/ static PyObject * -fcntl_flock(PyObject *self, PyObject *args) +fcntl_flock_impl(PyModuleDef *module, int fd, int code) +/*[clinic end generated code: output=c9035133a7dbfc96 input=b762aa9448d05e43]*/ { - int fd; - int code; int ret; - if (!PyArg_ParseTuple(args, "O&i:flock", - conv_descriptor, &fd, &code)) - return NULL; - #ifdef HAVE_FLOCK Py_BEGIN_ALLOW_THREADS ret = flock(fd, code); @@ -299,29 +323,49 @@ fcntl_flock(PyObject *self, PyObject *args) PyErr_SetFromErrno(PyExc_IOError); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyDoc_STRVAR(flock_doc, -"flock(fd, operation)\n\ -\n\ -Perform the lock operation op on file descriptor fd. See the Unix \n\ -manual page for flock(2) for details. (On some systems, this function is\n\ -emulated using fcntl().)"); +/*[clinic input] +fcntl.lockf + + fd: object(type='int', converter='conv_descriptor') + code: int + lenobj: object = NULL + startobj: object = NULL + whence: int = 0 + / + +A wrapper around the fcntl() locking calls. + +fd is the file descriptor of the file to lock or unlock, and operation is one +of the following values: + + LOCK_UN - unlock + LOCK_SH - acquire a shared lock + LOCK_EX - acquire an exclusive lock + +When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with +LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the +lock cannot be acquired, an IOError will be raised and the exception will +have an errno attribute set to EACCES or EAGAIN (depending on the operating +system -- for portability, check for either value). + +length is the number of bytes to lock, with the default meaning to lock to +EOF. start is the byte offset, relative to whence, to that the lock +starts. whence is as with fileobj.seek(), specifically: + + 0 - relative to the start of the file (SEEK_SET) + 1 - relative to the current buffer position (SEEK_CUR) + 2 - relative to the end of the file (SEEK_END) +[clinic start generated code]*/ -/* lockf(fd, operation) */ static PyObject * -fcntl_lockf(PyObject *self, PyObject *args) +fcntl_lockf_impl(PyModuleDef *module, int fd, int code, PyObject *lenobj, PyObject *startobj, int whence) +/*[clinic end generated code: output=5536df2892bf3ce9 input=44856fa06db36184]*/ { - int fd, code, ret, whence = 0; - PyObject *lenobj = NULL, *startobj = NULL; - - if (!PyArg_ParseTuple(args, "O&i|OOi:lockf", - conv_descriptor, &fd, &code, - &lenobj, &startobj, &whence)) - return NULL; + int ret; #ifndef LOCK_SH #define LOCK_SH 1 /* shared lock */ @@ -374,43 +418,17 @@ fcntl_lockf(PyObject *self, PyObject *args) PyErr_SetFromErrno(PyExc_IOError); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyDoc_STRVAR(lockf_doc, -"lockf (fd, operation, length=0, start=0, whence=0)\n\ -\n\ -This is essentially a wrapper around the fcntl() locking calls. fd is the\n\ -file descriptor of the file to lock or unlock, and operation is one of the\n\ -following values:\n\ -\n\ - LOCK_UN - unlock\n\ - LOCK_SH - acquire a shared lock\n\ - LOCK_EX - acquire an exclusive lock\n\ -\n\ -When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n\ -LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the\n\ -lock cannot be acquired, an IOError will be raised and the exception will\n\ -have an errno attribute set to EACCES or EAGAIN (depending on the operating\n\ -system -- for portability, check for either value).\n\ -\n\ -length is the number of bytes to lock, with the default meaning to lock to\n\ -EOF. start is the byte offset, relative to whence, to that the lock\n\ -starts. whence is as with fileobj.seek(), specifically:\n\ -\n\ - 0 - relative to the start of the file (SEEK_SET)\n\ - 1 - relative to the current buffer position (SEEK_CUR)\n\ - 2 - relative to the end of the file (SEEK_END)"); - /* List of functions */ static PyMethodDef fcntl_methods[] = { - {"fcntl", fcntl_fcntl, METH_VARARGS, fcntl_doc}, - {"ioctl", fcntl_ioctl, METH_VARARGS, ioctl_doc}, - {"flock", fcntl_flock, METH_VARARGS, flock_doc}, - {"lockf", fcntl_lockf, METH_VARARGS, lockf_doc}, - {NULL, NULL} /* sentinel */ + FCNTL_FCNTL_METHODDEF + FCNTL_IOCTL_METHODDEF + FCNTL_FLOCK_METHODDEF + FCNTL_LOCKF_METHODDEF + {NULL, NULL} /* sentinel */ }; From ffd842e1d6736d48d45e741e2006a181c9ad4272 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sun, 9 Nov 2014 22:30:36 -0800 Subject: [PATCH 4/5] Issue #22824: Updated reprlib output format for sets to use set literals. --- Doc/tutorial/stdlib2.rst | 2 +- Lib/reprlib.py | 8 ++++++-- Lib/test/test_reprlib.py | 44 ++++++++++++++++++++++++---------------- Misc/NEWS | 3 +++ 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/Doc/tutorial/stdlib2.rst b/Doc/tutorial/stdlib2.rst index 497c5842a19..f7d2a0ac2aa 100644 --- a/Doc/tutorial/stdlib2.rst +++ b/Doc/tutorial/stdlib2.rst @@ -18,7 +18,7 @@ abbreviated displays of large or deeply nested containers:: >>> import reprlib >>> reprlib.repr(set('supercalifragilisticexpialidocious')) - "set(['a', 'c', 'd', 'e', 'f', 'g', ...])" + "{'a', 'c', 'd', 'e', 'f', 'g', ...}" The :mod:`pprint` module offers more sophisticated control over printing both built-in and user defined objects in a way that is readable by the interpreter. diff --git a/Lib/reprlib.py b/Lib/reprlib.py index b7fda23bd8f..5eb5ca35269 100644 --- a/Lib/reprlib.py +++ b/Lib/reprlib.py @@ -87,12 +87,16 @@ class Repr: return self._repr_iterable(x, level, header, '])', self.maxarray) def repr_set(self, x, level): + if not x: + return 'set()' x = _possibly_sorted(x) - return self._repr_iterable(x, level, 'set([', '])', self.maxset) + return self._repr_iterable(x, level, '{', '}', self.maxset) def repr_frozenset(self, x, level): + if not x: + return 'frozenset()' x = _possibly_sorted(x) - return self._repr_iterable(x, level, 'frozenset([', '])', + return self._repr_iterable(x, level, 'frozenset({', '})', self.maxfrozenset) def repr_deque(self, x, level): diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py index d65494a8562..83f38cdc403 100644 --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -10,7 +10,7 @@ import importlib import importlib.util import unittest -from test.support import run_unittest, create_empty_file, verbose +from test.support import create_empty_file, verbose from reprlib import repr as r # Don't shadow builtin repr from reprlib import Repr from reprlib import recursive_repr @@ -70,18 +70,18 @@ class ReprTests(unittest.TestCase): eq(r([1, 2, 3, 4, 5, 6, 7]), "[1, 2, 3, 4, 5, 6, ...]") # Sets give up after 6 as well - eq(r(set([])), "set([])") - eq(r(set([1])), "set([1])") - eq(r(set([1, 2, 3])), "set([1, 2, 3])") - eq(r(set([1, 2, 3, 4, 5, 6])), "set([1, 2, 3, 4, 5, 6])") - eq(r(set([1, 2, 3, 4, 5, 6, 7])), "set([1, 2, 3, 4, 5, 6, ...])") + eq(r(set([])), "set()") + eq(r(set([1])), "{1}") + eq(r(set([1, 2, 3])), "{1, 2, 3}") + eq(r(set([1, 2, 3, 4, 5, 6])), "{1, 2, 3, 4, 5, 6}") + eq(r(set([1, 2, 3, 4, 5, 6, 7])), "{1, 2, 3, 4, 5, 6, ...}") # Frozensets give up after 6 as well - eq(r(frozenset([])), "frozenset([])") - eq(r(frozenset([1])), "frozenset([1])") - eq(r(frozenset([1, 2, 3])), "frozenset([1, 2, 3])") - eq(r(frozenset([1, 2, 3, 4, 5, 6])), "frozenset([1, 2, 3, 4, 5, 6])") - eq(r(frozenset([1, 2, 3, 4, 5, 6, 7])), "frozenset([1, 2, 3, 4, 5, 6, ...])") + eq(r(frozenset([])), "frozenset()") + eq(r(frozenset([1])), "frozenset({1})") + eq(r(frozenset([1, 2, 3])), "frozenset({1, 2, 3})") + eq(r(frozenset([1, 2, 3, 4, 5, 6])), "frozenset({1, 2, 3, 4, 5, 6})") + eq(r(frozenset([1, 2, 3, 4, 5, 6, 7])), "frozenset({1, 2, 3, 4, 5, 6, ...})") # collections.deque after 6 eq(r(deque([1, 2, 3, 4, 5, 6, 7])), "deque([1, 2, 3, 4, 5, 6, ...])") @@ -103,6 +103,20 @@ class ReprTests(unittest.TestCase): eq(r(array('i', [1, 2, 3, 4, 5, 6])), "array('i', [1, 2, 3, 4, 5, ...])") + def test_set_literal(self): + eq = self.assertEqual + eq(r({1}), "{1}") + eq(r({1, 2, 3}), "{1, 2, 3}") + eq(r({1, 2, 3, 4, 5, 6}), "{1, 2, 3, 4, 5, 6}") + eq(r({1, 2, 3, 4, 5, 6, 7}), "{1, 2, 3, 4, 5, 6, ...}") + + def test_frozenset(self): + eq = self.assertEqual + eq(r(frozenset({1})), "frozenset({1})") + eq(r(frozenset({1, 2, 3})), "frozenset({1, 2, 3})") + eq(r(frozenset({1, 2, 3, 4, 5, 6})), "frozenset({1, 2, 3, 4, 5, 6})") + eq(r(frozenset({1, 2, 3, 4, 5, 6, 7})), "frozenset({1, 2, 3, 4, 5, 6, ...})") + def test_numbers(self): eq = self.assertEqual eq(r(123), repr(123)) @@ -373,11 +387,5 @@ class TestRecursiveRepr(unittest.TestCase): m.append(m) self.assertEqual(repr(m), '') -def test_main(): - run_unittest(ReprTests) - run_unittest(LongReprTest) - run_unittest(TestRecursiveRepr) - - if __name__ == "__main__": - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS index 0727b17debf..914f4671baf 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -186,6 +186,9 @@ Library - Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions. +- Issue #22824: Updated reprlib output format for sets to use set literals. + Patch contributed by Berker Peksag. + - Issue #22406: Fixed the uu_codec codec incorrectly ported to 3.x. Based on patch by Martin Panter. From 39e4c4d873927b902c53aeb0e2e15c12d2678e1b Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Mon, 10 Nov 2014 09:56:54 +0200 Subject: [PATCH 5/5] Issue #21650: Add an `--sort-keys` option to json.tool CLI. --- Doc/library/json.rst | 11 +++++++++++ Doc/whatsnew/3.5.rst | 8 ++++++++ Lib/json/tool.py | 12 ++++++++++-- Lib/test/test_json/test_tool.py | 33 ++++++++++++++++++++++++++++++++- Misc/NEWS | 2 ++ 5 files changed, 63 insertions(+), 3 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst index cff0c727c95..edbc5e0bd5a 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -567,6 +567,7 @@ the last name-value pair for a given name:: The *object_pairs_hook* parameter can be used to alter this behavior. .. highlight:: bash +.. module:: json.tool .. _json-commandline: @@ -586,6 +587,10 @@ specified, :attr:`sys.stdin` and :attr:`sys.stdout` will be used respectively:: $ echo '{1.2:3.4}' | python -m json.tool Expecting property name enclosed in double quotes: line 1 column 2 (char 1) +.. versionchanged:: 3.5 + The output is now in the same order as the input. Use the + :option:`--sort-keys` option to sort the output of dictionaries + alphabetically by key. Command line options ^^^^^^^^^^^^^^^^^^^^ @@ -613,6 +618,12 @@ Command line options Write the output of the *infile* to the given *outfile*. Otherwise, write it to :attr:`sys.stdout`. +.. cmdoption:: --sort-keys + + Sort the output of dictionaries alphabetically by key. + + .. versionadded:: 3.5 + .. cmdoption:: -h, --help Show the help message. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 51fcb593d43..502ac44030b 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -211,6 +211,14 @@ ipaddress network objects from existing addresses. (Contributed by Peter Moody and Antoine Pitrou in :issue:`16531`.) +json +---- + +* The output of :mod:`json.tool` command line interface is now in the same + order as the input. Use the :option:`--sort-keys` option to sort the output + of dictionaries alphabetically by key. (Contributed by Berker Peksag in + :issue:`21650`.) + os -- diff --git a/Lib/json/tool.py b/Lib/json/tool.py index cd57e4f5ae0..4f3182c0c1e 100644 --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -11,6 +11,7 @@ Usage:: """ import argparse +import collections import json import sys @@ -24,17 +25,24 @@ def main(): help='a JSON file to be validated or pretty-printed') parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'), help='write the output of infile to outfile') + parser.add_argument('--sort-keys', action='store_true', default=False, + help='sort the output of dictionaries alphabetically by key') options = parser.parse_args() infile = options.infile or sys.stdin outfile = options.outfile or sys.stdout + sort_keys = options.sort_keys with infile: try: - obj = json.load(infile) + if sort_keys: + obj = json.load(infile) + else: + obj = json.load(infile, + object_pairs_hook=collections.OrderedDict) except ValueError as e: raise SystemExit(e) with outfile: - json.dump(obj, outfile, sort_keys=True, indent=4) + json.dump(obj, outfile, sort_keys=sort_keys, indent=4) outfile.write('\n') diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 5484a8a7ca1..bd63e2b3111 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -6,6 +6,7 @@ import subprocess from test import support from test.script_helper import assert_python_ok + class TestTool(unittest.TestCase): data = """ @@ -15,7 +16,7 @@ class TestTool(unittest.TestCase): :"yes"} ] """ - expect = textwrap.dedent("""\ + expect_without_sort_keys = textwrap.dedent("""\ [ [ "blorpie" @@ -37,6 +38,28 @@ class TestTool(unittest.TestCase): ] """) + expect = textwrap.dedent("""\ + [ + [ + "blorpie" + ], + [ + "whoops" + ], + [], + "d-shtaeou", + "d-nthiouh", + "i-vhbjkhnth", + { + "nifty": 87 + }, + { + "morefield": false, + "field": "yes" + } + ] + """) + def test_stdin_stdout(self): with subprocess.Popen( (sys.executable, '-m', 'json.tool'), @@ -75,3 +98,11 @@ class TestTool(unittest.TestCase): self.assertEqual(rc, 0) self.assertTrue(out.startswith(b'usage: ')) self.assertEqual(err, b'') + + def test_sort_keys_flag(self): + infile = self._create_infile() + rc, out, err = assert_python_ok('-m', 'json.tool', '--sort-keys', infile) + self.assertEqual(rc, 0) + self.assertEqual(out.splitlines(), + self.expect_without_sort_keys.encode().splitlines()) + self.assertEqual(err, b'') diff --git a/Misc/NEWS b/Misc/NEWS index 914f4671baf..53040b26499 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,8 @@ Core and Builtins Library ------- +- Issue #21650: Add an `--sort-keys` option to json.tool CLI. + - Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions.