From 4ad78ab766469d401dd41b028464100940f1f553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Sat, 14 May 2011 22:43:44 +0200 Subject: pprint usage example rethought. --- Doc/library/pprint.rst | 129 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 99 insertions(+), 30 deletions(-) diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index d1d1bae..7bebd8c 100644 --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -188,36 +188,105 @@ are converted to strings. The default implementation uses the internals of the .. _pprint-example: -pprint Example --------------- +Example +------- -This example demonstrates several uses of the :func:`pprint` function and its parameters. +To demonstrate several uses of the :func:`pprint` function and its parameters, +let's fetch information about a package from PyPI:: + >>> import json >>> import pprint - >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', - ... ('parrot', ('fresh fruit',)))))))) - >>> stuff = ['a' * 10, tup, ['a' * 30, 'b' * 30], ['c' * 20, 'd' * 20]] - >>> pprint.pprint(stuff) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, depth=3) - ['aaaaaaaaaa', - ('spam', ('eggs', (...))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - >>> pprint.pprint(stuff, width=60) - ['aaaaaaaaaa', - ('spam', - ('eggs', - ('lumberjack', - ('knights', - ('ni', ('dead', ('parrot', ('fresh fruit',)))))))), - ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'], - ['cccccccccccccccccccc', 'dddddddddddddddddddd']] - + >>> from urllib.request import urlopen + >>> with urlopen('http://pypi.python.org/pypi/configparser/json') as url: + ... http_info = url.info() + ... raw_data = url.read().decode(http_info.get_content_charset()) + >>> package_data = json.loads(raw_data) + >>> result = {'headers': http_info.items(), 'body': package_data} + +In its basic form, :func:`pprint` shows the whole object:: + + >>> pprint.pprint(result) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': ['Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules'], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{'comment_text': '', + 'downloads': 47, + 'filename': 'configparser-3.2.0r3.tar.gz', + 'has_sig': False, + 'md5_digest': '8500fd87c61ac0de328fc996fce69b96', + 'packagetype': 'sdist', + 'python_version': 'source', + 'size': 32281, + 'upload_time': '2011-05-10T16:28:50', + 'url': 'http://pypi.python.org/packages/source/c/configparser/configparser-3.2.0r3.tar.gz'}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +The result can be limited to a certain *depth* (ellipsis is used for deeper +contents):: + + >>> pprint.pprint(result, depth=3) + {'body': {'info': {'_pypi_hidden': False, + '_pypi_ordering': 12, + 'classifiers': [...], + 'download_url': 'UNKNOWN', + 'home_page': 'http://docs.python.org/py3k/library/configparser.html', + 'keywords': 'configparser ini parsing conf cfg configuration file', + 'license': 'MIT', + 'name': 'configparser', + 'package_url': 'http://pypi.python.org/pypi/configparser', + 'platform': 'any', + 'release_url': 'http://pypi.python.org/pypi/configparser/3.2.0r3', + 'requires_python': None, + 'stable_version': None, + 'summary': 'This library brings the updated configparser from Python 3.2+ to Python 2.6-2.7.', + 'version': '3.2.0r3'}, + 'urls': [{...}]}, + 'headers': [('Date', 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', 'chunked'), + ('Content-Type', 'application/json; charset="UTF-8"')]} + +Additionally, maximum *width* can be suggested. If a long object cannot be +split, the specified width will be exceeded:: + + >>> pprint.pprint(result['headers'], width=30) + [('Date', + 'Sat, 14 May 2011 12:48:52 GMT'), + ('Server', + 'Apache/2.2.16 (Debian)'), + ('Content-Disposition', + 'inline'), + ('Connection', 'close'), + ('Transfer-Encoding', + 'chunked'), + ('Content-Type', + 'application/json; charset="UTF-8"')] -- cgit v0.12 From 154bdf92fce957f331a57a54e3cdcaeefeba25ff Mon Sep 17 00:00:00 2001 From: Nadeem Vawda Date: Sat, 14 May 2011 23:07:36 +0200 Subject: Fix memory leaks in zlib.compress() and .decompress(). Also, make sure that test_zlib tests decompress() for overly-large inputs. --- Lib/test/test_zlib.py | 1 + Modules/zlibmodule.c | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index 852857b..48d9f58 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -193,6 +193,7 @@ class CompressTestCase(BaseCompressTestCase, unittest.TestCase): data = b'x' * size try: self.assertRaises(OverflowError, zlib.compress, data, 1) + self.assertRaises(OverflowError, zlib.decompress, data) finally: data = None diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index 969db4a..fa07739 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -116,7 +116,7 @@ PyZlib_compress(PyObject *self, PyObject *args) { PyObject *ReturnVal = NULL; Py_buffer pinput; - Byte *input, *output; + Byte *input, *output = NULL; unsigned int length; int level=Z_DEFAULT_COMPRESSION, err; z_stream zst; @@ -127,20 +127,19 @@ PyZlib_compress(PyObject *self, PyObject *args) if (pinput.len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, - "size does not fit in an unsigned int"); - return NULL; + "Size does not fit in an unsigned int"); + goto error; } - length = pinput.len; input = pinput.buf; + length = pinput.len; zst.avail_out = length + length/1000 + 12 + 1; output = (Byte*)malloc(zst.avail_out); if (output == NULL) { - PyBuffer_Release(&pinput); PyErr_SetString(PyExc_MemoryError, "Can't allocate memory to compress data"); - return NULL; + goto error; } /* Past the point of no return. From here on out, we need to make sure @@ -203,7 +202,7 @@ PyDoc_STRVAR(decompress__doc__, static PyObject * PyZlib_decompress(PyObject *self, PyObject *args) { - PyObject *result_str; + PyObject *result_str = NULL; Py_buffer pinput; Byte *input; unsigned int length; @@ -218,11 +217,11 @@ PyZlib_decompress(PyObject *self, PyObject *args) if (pinput.len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, - "size does not fit in an unsigned int"); - return NULL; + "Size does not fit in an unsigned int"); + goto error; } - length = pinput.len; input = pinput.buf; + length = pinput.len; if (r_strlen <= 0) r_strlen = 1; @@ -230,10 +229,8 @@ PyZlib_decompress(PyObject *self, PyObject *args) zst.avail_in = length; zst.avail_out = r_strlen; - if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) { - PyBuffer_Release(&pinput); - return NULL; - } + if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) + goto error; zst.zalloc = (alloc_func)NULL; zst.zfree = (free_func)Z_NULL; -- cgit v0.12