diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst index 8b812c173b5953..e5afa174413541 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -728,16 +728,18 @@ Finally, we compare the two: >>> from pprint import pprint >>> pprint(result) - [' 1. Beautiful is better than ugly.\n', - '- 2. Explicit is better than implicit.\n', - '- 3. Simple is better than complex.\n', - '+ 3. Simple is better than complex.\n', - '? ++\n', - '- 4. Complex is better than complicated.\n', - '? ^ ---- ^\n', - '+ 4. Complicated is better than complex.\n', - '? ++++ ^ ^\n', - '+ 5. Flat is better than nested.\n'] + [ + ' 1. Beautiful is better than ugly.\n', + '- 2. Explicit is better than implicit.\n', + '- 3. Simple is better than complex.\n', + '+ 3. Simple is better than complex.\n', + '? ++\n', + '- 4. Complex is better than complicated.\n', + '? ^ ---- ^\n', + '+ 4. Complicated is better than complex.\n', + '? ++++ ^ ^\n', + '+ 5. Flat is better than nested.\n', + ] As a single multi-line string it looks like this: diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index 4f043fbb3a46df..0bdbe8c2e2bc97 100644 --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -17,7 +17,7 @@ objects which are not representable as Python literals. The formatted representation keeps objects on a single line if it can, and breaks them onto multiple lines if they don't fit within the allowed width, -adjustable by the *width* parameter defaulting to 80 characters. +adjustable by the *width* parameter defaulting to 88 characters. .. versionchanged:: 3.9 Added support for pretty-printing :class:`types.SimpleNamespace`. @@ -30,9 +30,8 @@ adjustable by the *width* parameter defaulting to 80 characters. Functions --------- -.. function:: pp(object, stream=None, indent=1, width=80, depth=None, *, \ - compact=False, expand=False, sort_dicts=False, \ - underscore_numbers=False) +.. function:: pp(object, stream=None, indent=4, width=88, depth=None, *, \ + compact=False, sort_dicts=False, underscore_numbers=False) Prints the formatted representation of *object*, followed by a newline. This function may be used in the interactive interpreter @@ -67,16 +66,11 @@ Functions :param bool compact: Control the way long :term:`sequences ` are formatted. If ``False`` (the default), - each item of a sequence will be formatted on a separate line, - otherwise as many items as will fit within the *width* - will be formatted on each output line. - Incompatible with *expand*. - - :param bool expand: - If ``True``, opening parentheses and brackets will be followed by a newline and the following content will be indented by one level, similar to - pretty-printed JSON. Incompatible with *compact*. + pretty-printed JSON. + If ``True``, as many items as will fit within the *width* + will be formatted on each output line. :param bool sort_dicts: If ``True``, dictionaries will be formatted with @@ -91,32 +85,25 @@ Functions >>> import pprint >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] >>> stuff.insert(0, stuff) - >>> pprint.pp(stuff) - [, - 'spam', - 'eggs', - 'lumberjack', - 'knights', - 'ni'] + >>> pprint.pp(stuff, width=100) + [, 'spam', 'eggs', 'lumberjack', 'knights', 'ni'] .. versionadded:: 3.8 -.. function:: pprint(object, stream=None, indent=1, width=80, depth=None, *, \ - compact=False, expand=False, sort_dicts=True, \ - underscore_numbers=False) +.. function:: pprint(object, stream=None, indent=4, width=88, depth=None, *, \ + compact=False, sort_dicts=True, underscore_numbers=False) Alias for :func:`~pprint.pp` with *sort_dicts* set to ``True`` by default, which would automatically sort the dictionaries' keys, you might want to use :func:`~pprint.pp` instead where it is ``False`` by default. -.. function:: pformat(object, indent=1, width=80, depth=None, *, \ - compact=False, expand=False, sort_dicts=True, \ - underscore_numbers=False) +.. function:: pformat(object, indent=4, width=88, depth=None, *, \ + compact=False, sort_dicts=True, underscore_numbers=False) Return the formatted representation of *object* as a string. *indent*, - *width*, *depth*, *compact*, *expand*, *sort_dicts* and *underscore_numbers* are + *width*, *depth*, *compact*, *sort_dicts* and *underscore_numbers* are passed to the :class:`PrettyPrinter` constructor as formatting parameters and their meanings are as described in the documentation above. @@ -154,13 +141,13 @@ Functions .. _prettyprinter-objects: -PrettyPrinter Objects +PrettyPrinter objects --------------------- .. index:: single: ...; placeholder -.. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, \ - compact=False, expand=False, sort_dicts=True, \ +.. class:: PrettyPrinter(indent=4, width=88, depth=None, stream=None, *, \ + compact=False, sort_dicts=True, \ underscore_numbers=False) Construct a :class:`PrettyPrinter` instance. @@ -171,21 +158,23 @@ PrettyPrinter Objects >>> import pprint >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] >>> stuff.insert(0, stuff[:]) - >>> pp = pprint.PrettyPrinter(indent=4) + >>> pp = pprint.PrettyPrinter() >>> pp.pprint(stuff) - [ ['spam', 'eggs', 'lumberjack', 'knights', 'ni'], + [ + ['spam', 'eggs', 'lumberjack', 'knights', 'ni'], 'spam', 'eggs', 'lumberjack', 'knights', - 'ni'] - >>> pp = pprint.PrettyPrinter(width=41, compact=True) + 'ni', + ] + >>> pp = pprint.PrettyPrinter(indent=1, width=41, compact=True) >>> pp.pprint(stuff) [['spam', 'eggs', 'lumberjack', 'knights', 'ni'], 'spam', 'eggs', 'lumberjack', 'knights', 'ni'] - >>> pp = pprint.PrettyPrinter(width=41, expand=True, indent=3) + >>> pp = pprint.PrettyPrinter(width=41, indent=3) >>> pp.pprint(stuff) [ [ @@ -220,8 +209,12 @@ PrettyPrinter Objects .. versionchanged:: 3.11 No longer attempts to write to :data:`!sys.stdout` if it is ``None``. - .. versionchanged:: 3.15 - Added the *expand* parameter. + .. versionchanged:: next + Changed default *indent* from 1 to 4 + and default *width* from 80 to 88. + The default ``compact=False`` layout is now similar to + pretty-printed JSON, with opening parentheses and brackets + followed by a newline and the contents indented by one level. :class:`PrettyPrinter` instances have the following methods: @@ -298,219 +291,144 @@ let's fetch information about a project from `PyPI `_:: In its basic form, :func:`~pprint.pp` shows the whole object:: >>> pprint.pp(project_info) - {'author': 'The Python Packaging Authority', - 'author_email': 'pypa-dev@googlegroups.com', - 'bugtrack_url': None, - 'classifiers': ['Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Topic :: Software Development :: Build Tools'], - 'description': 'A sample Python project\n' - '=======================\n' - '\n' - 'This is the description file for the project.\n' - '\n' - 'The file should use UTF-8 encoding and be written using ' - 'ReStructured Text. It\n' - 'will be used to generate the project webpage on PyPI, and ' - 'should be written for\n' - 'that purpose.\n' - '\n' - 'Typical contents for this file would include an overview of ' - 'the project, basic\n' - 'usage examples, etc. Generally, including the project ' - 'changelog in here is not\n' - 'a good idea, although a simple "What\'s New" section for the ' - 'most recent version\n' - 'may be appropriate.', - 'description_content_type': None, - 'docs_url': None, - 'download_url': 'UNKNOWN', - 'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1}, - 'home_page': 'https://github.com/pypa/sampleproject', - 'keywords': 'sample setuptools development', - 'license': 'MIT', - 'maintainer': None, - 'maintainer_email': None, - 'name': 'sampleproject', - 'package_url': 'https://pypi.org/project/sampleproject/', - 'platform': 'UNKNOWN', - 'project_url': 'https://pypi.org/project/sampleproject/', - 'project_urls': {'Download': 'UNKNOWN', - 'Homepage': 'https://github.com/pypa/sampleproject'}, - 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', - 'requires_dist': None, - 'requires_python': None, - 'summary': 'A sample Python project', - 'version': '1.2.0'} + { + 'author': 'The Python Packaging Authority', + 'author_email': 'pypa-dev@googlegroups.com', + 'bugtrack_url': None, + 'classifiers': [ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Topic :: Software Development :: Build Tools', + ], + 'description': 'A sample Python project\n' + '=======================\n' + '\n' + 'This is the description file for the project.\n' + '\n' + 'The file should use UTF-8 encoding and be written using ReStructured Text. It\n' + 'will be used to generate the project webpage on PyPI, and should be written for\n' + 'that purpose.\n' + '\n' + 'Typical contents for this file would include an overview of the project, basic\n' + 'usage examples, etc. Generally, including the project changelog in here is not\n' + 'a good idea, although a simple "What\'s New" section for the most recent version\n' + 'may be appropriate.', + 'description_content_type': None, + 'docs_url': None, + 'download_url': 'UNKNOWN', + 'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1}, + 'home_page': 'https://github.com/pypa/sampleproject', + 'keywords': 'sample setuptools development', + 'license': 'MIT', + 'maintainer': None, + 'maintainer_email': None, + 'name': 'sampleproject', + 'package_url': 'https://pypi.org/project/sampleproject/', + 'platform': 'UNKNOWN', + 'project_url': 'https://pypi.org/project/sampleproject/', + 'project_urls': {'Download': 'UNKNOWN', 'Homepage': 'https://github.com/pypa/sampleproject'}, + 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', + 'requires_dist': None, + 'requires_python': None, + 'summary': 'A sample Python project', + 'version': '1.2.0', + } The result can be limited to a certain *depth* (ellipsis is used for deeper contents):: >>> pprint.pp(project_info, depth=1) - {'author': 'The Python Packaging Authority', - 'author_email': 'pypa-dev@googlegroups.com', - 'bugtrack_url': None, - 'classifiers': [...], - 'description': 'A sample Python project\n' - '=======================\n' - '\n' - 'This is the description file for the project.\n' - '\n' - 'The file should use UTF-8 encoding and be written using ' - 'ReStructured Text. It\n' - 'will be used to generate the project webpage on PyPI, and ' - 'should be written for\n' - 'that purpose.\n' - '\n' - 'Typical contents for this file would include an overview of ' - 'the project, basic\n' - 'usage examples, etc. Generally, including the project ' - 'changelog in here is not\n' - 'a good idea, although a simple "What\'s New" section for the ' - 'most recent version\n' - 'may be appropriate.', - 'description_content_type': None, - 'docs_url': None, - 'download_url': 'UNKNOWN', - 'downloads': {...}, - 'home_page': 'https://github.com/pypa/sampleproject', - 'keywords': 'sample setuptools development', - 'license': 'MIT', - 'maintainer': None, - 'maintainer_email': None, - 'name': 'sampleproject', - 'package_url': 'https://pypi.org/project/sampleproject/', - 'platform': 'UNKNOWN', - 'project_url': 'https://pypi.org/project/sampleproject/', - 'project_urls': {...}, - 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', - 'requires_dist': None, - 'requires_python': None, - 'summary': 'A sample Python project', - 'version': '1.2.0'} + { + 'author': 'The Python Packaging Authority', + 'author_email': 'pypa-dev@googlegroups.com', + 'bugtrack_url': None, + 'classifiers': [...], + 'description': 'A sample Python project\n' + '=======================\n' + '\n' + 'This is the description file for the project.\n' + '\n' + 'The file should use UTF-8 encoding and be written using ReStructured Text. It\n' + 'will be used to generate the project webpage on PyPI, and should be written for\n' + 'that purpose.\n' + '\n' + 'Typical contents for this file would include an overview of the project, basic\n' + 'usage examples, etc. Generally, including the project changelog in here is not\n' + 'a good idea, although a simple "What\'s New" section for the most recent version\n' + 'may be appropriate.', + 'description_content_type': None, + 'docs_url': None, + 'download_url': 'UNKNOWN', + 'downloads': {...}, + 'home_page': 'https://github.com/pypa/sampleproject', + 'keywords': 'sample setuptools development', + 'license': 'MIT', + 'maintainer': None, + 'maintainer_email': None, + 'name': 'sampleproject', + 'package_url': 'https://pypi.org/project/sampleproject/', + 'platform': 'UNKNOWN', + 'project_url': 'https://pypi.org/project/sampleproject/', + 'project_urls': {...}, + 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', + 'requires_dist': None, + 'requires_python': None, + 'summary': 'A sample Python project', + 'version': '1.2.0', + } Additionally, maximum character *width* can be suggested. If a long object cannot be split, the specified width will be exceeded:: >>> pprint.pp(project_info, depth=1, width=60) - {'author': 'The Python Packaging Authority', - 'author_email': 'pypa-dev@googlegroups.com', - 'bugtrack_url': None, - 'classifiers': [...], - 'description': 'A sample Python project\n' - '=======================\n' - '\n' - 'This is the description file for the ' - 'project.\n' - '\n' - 'The file should use UTF-8 encoding and be ' - 'written using ReStructured Text. It\n' - 'will be used to generate the project ' - 'webpage on PyPI, and should be written ' - 'for\n' - 'that purpose.\n' - '\n' - 'Typical contents for this file would ' - 'include an overview of the project, ' - 'basic\n' - 'usage examples, etc. Generally, including ' - 'the project changelog in here is not\n' - 'a good idea, although a simple "What\'s ' - 'New" section for the most recent version\n' - 'may be appropriate.', - 'description_content_type': None, - 'docs_url': None, - 'download_url': 'UNKNOWN', - 'downloads': {...}, - 'home_page': 'https://github.com/pypa/sampleproject', - 'keywords': 'sample setuptools development', - 'license': 'MIT', - 'maintainer': None, - 'maintainer_email': None, - 'name': 'sampleproject', - 'package_url': 'https://pypi.org/project/sampleproject/', - 'platform': 'UNKNOWN', - 'project_url': 'https://pypi.org/project/sampleproject/', - 'project_urls': {...}, - 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', - 'requires_dist': None, - 'requires_python': None, - 'summary': 'A sample Python project', - 'version': '1.2.0'} - -Lastly, we can format like pretty-printed JSON with the *expand* parameter. -Best results are achieved with a higher *indent* value:: - - >>> pprint.pp(project_info, indent=4, expand=True) { - 'author': 'The Python Packaging Authority', - 'author_email': 'pypa-dev@googlegroups.com', - 'bugtrack_url': None, - 'classifiers': [ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Topic :: Software Development :: Build Tools', - ], - 'description': 'A sample Python project\n' - '=======================\n' - '\n' - 'This is the description file for the project.\n' - '\n' - 'The file should use UTF-8 encoding and be written using ReStructured ' - 'Text. It\n' - 'will be used to generate the project webpage on PyPI, and should be ' - 'written for\n' - 'that purpose.\n' - '\n' - 'Typical contents for this file would include an overview of the project, ' - 'basic\n' - 'usage examples, etc. Generally, including the project changelog in here ' - 'is not\n' - 'a good idea, although a simple "What\'s New" section for the most recent ' - 'version\n' - 'may be appropriate.', - 'description_content_type': None, - 'docs_url': None, - 'download_url': 'UNKNOWN', - 'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1}, - 'dynamic': None, - 'home_page': 'https://github.com/pypa/sampleproject', - 'keywords': 'sample setuptools development', - 'license': 'MIT', - 'license_expression': None, - 'license_files': None, - 'maintainer': None, - 'maintainer_email': None, - 'name': 'sampleproject', - 'package_url': 'https://pypi.org/project/sampleproject/', - 'platform': 'UNKNOWN', - 'project_url': 'https://pypi.org/project/sampleproject/', - 'project_urls': { - 'Download': 'UNKNOWN', - 'Homepage': 'https://github.com/pypa/sampleproject', - }, - 'provides_extra': None, - 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', - 'requires_dist': None, - 'requires_python': None, - 'summary': 'A sample Python project', - 'version': '1.2.0', - 'yanked': False, - 'yanked_reason': None, + 'author': 'The Python Packaging Authority', + 'author_email': 'pypa-dev@googlegroups.com', + 'bugtrack_url': None, + 'classifiers': [...], + 'description': 'A sample Python project\n' + '=======================\n' + '\n' + 'This is the description file for the project.\n' + '\n' + 'The file should use UTF-8 encoding and be written ' + 'using ReStructured Text. It\n' + 'will be used to generate the project webpage on PyPI, ' + 'and should be written for\n' + 'that purpose.\n' + '\n' + 'Typical contents for this file would include an ' + 'overview of the project, basic\n' + 'usage examples, etc. Generally, including the project ' + 'changelog in here is not\n' + 'a good idea, although a simple "What\'s New" section ' + 'for the most recent version\n' + 'may be appropriate.', + 'description_content_type': None, + 'docs_url': None, + 'download_url': 'UNKNOWN', + 'downloads': {...}, + 'home_page': 'https://github.com/pypa/sampleproject', + 'keywords': 'sample setuptools development', + 'license': 'MIT', + 'maintainer': None, + 'maintainer_email': None, + 'name': 'sampleproject', + 'package_url': 'https://pypi.org/project/sampleproject/', + 'platform': 'UNKNOWN', + 'project_url': 'https://pypi.org/project/sampleproject/', + 'project_urls': {...}, + 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/', + 'requires_dist': None, + 'requires_python': None, + 'summary': 'A sample Python project', + 'version': '1.2.0', } diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index f2c35d1897a77f..d9c736d27dcaec 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -2473,67 +2473,79 @@ Visual inspection shows that the certificate does identify the desired service (that is, the HTTPS host ``www.python.org``):: >>> pprint.pprint(cert) - {'OCSP': ('http://ocsp.digicert.com',), - 'caIssuers': ('http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt',), - 'crlDistributionPoints': ('http://crl3.digicert.com/sha2-ev-server-g1.crl', - 'http://crl4.digicert.com/sha2-ev-server-g1.crl'), - 'issuer': ((('countryName', 'US'),), - (('organizationName', 'DigiCert Inc'),), - (('organizationalUnitName', 'www.digicert.com'),), - (('commonName', 'DigiCert SHA2 Extended Validation Server CA'),)), - 'notAfter': 'Sep 9 12:00:00 2016 GMT', - 'notBefore': 'Sep 5 00:00:00 2014 GMT', - 'serialNumber': '01BB6F00122B177F36CAB49CEA8B6B26', - 'subject': ((('businessCategory', 'Private Organization'),), - (('1.3.6.1.4.1.311.60.2.1.3', 'US'),), - (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),), - (('serialNumber', '3359300'),), - (('streetAddress', '16 Allen Rd'),), - (('postalCode', '03894-4801'),), - (('countryName', 'US'),), - (('stateOrProvinceName', 'NH'),), - (('localityName', 'Wolfeboro'),), - (('organizationName', 'Python Software Foundation'),), - (('commonName', 'www.python.org'),)), - 'subjectAltName': (('DNS', 'www.python.org'), - ('DNS', 'python.org'), - ('DNS', 'pypi.org'), - ('DNS', 'docs.python.org'), - ('DNS', 'testpypi.org'), - ('DNS', 'bugs.python.org'), - ('DNS', 'wiki.python.org'), - ('DNS', 'hg.python.org'), - ('DNS', 'mail.python.org'), - ('DNS', 'packaging.python.org'), - ('DNS', 'pythonhosted.org'), - ('DNS', 'www.pythonhosted.org'), - ('DNS', 'test.pythonhosted.org'), - ('DNS', 'us.pycon.org'), - ('DNS', 'id.python.org')), - 'version': 3} + { + 'OCSP': ('http://ocsp.digicert.com',), + 'caIssuers': ('http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt',), + 'crlDistributionPoints': ( + 'http://crl3.digicert.com/sha2-ev-server-g1.crl', + 'http://crl4.digicert.com/sha2-ev-server-g1.crl', + ), + 'issuer': ( + (('countryName', 'US'),), + (('organizationName', 'DigiCert Inc'),), + (('organizationalUnitName', 'www.digicert.com'),), + (('commonName', 'DigiCert SHA2 Extended Validation Server CA'),), + ), + 'notAfter': 'Sep 9 12:00:00 2016 GMT', + 'notBefore': 'Sep 5 00:00:00 2014 GMT', + 'serialNumber': '01BB6F00122B177F36CAB49CEA8B6B26', + 'subject': ( + (('businessCategory', 'Private Organization'),), + (('1.3.6.1.4.1.311.60.2.1.3', 'US'),), + (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),), + (('serialNumber', '3359300'),), + (('streetAddress', '16 Allen Rd'),), + (('postalCode', '03894-4801'),), + (('countryName', 'US'),), + (('stateOrProvinceName', 'NH'),), + (('localityName', 'Wolfeboro'),), + (('organizationName', 'Python Software Foundation'),), + (('commonName', 'www.python.org'),), + ), + 'subjectAltName': ( + ('DNS', 'www.python.org'), + ('DNS', 'python.org'), + ('DNS', 'pypi.org'), + ('DNS', 'docs.python.org'), + ('DNS', 'testpypi.org'), + ('DNS', 'bugs.python.org'), + ('DNS', 'wiki.python.org'), + ('DNS', 'hg.python.org'), + ('DNS', 'mail.python.org'), + ('DNS', 'packaging.python.org'), + ('DNS', 'pythonhosted.org'), + ('DNS', 'www.pythonhosted.org'), + ('DNS', 'test.pythonhosted.org'), + ('DNS', 'us.pycon.org'), + ('DNS', 'id.python.org'), + ), + 'version': 3, + } Now the SSL channel is established and the certificate verified, you can proceed to talk with the server:: >>> conn.sendall(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n") >>> pprint.pprint(conn.recv(1024).split(b"\r\n")) - [b'HTTP/1.1 200 OK', - b'Date: Sat, 18 Oct 2014 18:27:20 GMT', - b'Server: nginx', - b'Content-Type: text/html; charset=utf-8', - b'X-Frame-Options: SAMEORIGIN', - b'Content-Length: 45679', - b'Accept-Ranges: bytes', - b'Via: 1.1 varnish', - b'Age: 2188', - b'X-Served-By: cache-lcy1134-LCY', - b'X-Cache: HIT', - b'X-Cache-Hits: 11', - b'Vary: Cookie', - b'Strict-Transport-Security: max-age=63072000; includeSubDomains', - b'Connection: close', - b'', - b''] + [ + b'HTTP/1.1 200 OK', + b'Date: Sat, 18 Oct 2014 18:27:20 GMT', + b'Server: nginx', + b'Content-Type: text/html; charset=utf-8', + b'X-Frame-Options: SAMEORIGIN', + b'Content-Length: 45679', + b'Accept-Ranges: bytes', + b'Via: 1.1 varnish', + b'Age: 2188', + b'X-Served-By: cache-lcy1134-LCY', + b'X-Cache: HIT', + b'X-Cache-Hits: 11', + b'Vary: Cookie', + b'Strict-Transport-Security: max-age=63072000; includeSubDomains', + b'Connection: close', + b'', + b'', + ] See the discussion of :ref:`ssl-security` below. diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 2ff1015af7a86e..5b9f9eec93aa28 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -2347,10 +2347,12 @@ chained call: >>> kall = call(1).method(arg='foo').other('bar')(2.0) >>> kall.call_list() - [call(1), - call().method(arg='foo'), - call().method().other('bar'), - call().method().other()(2.0)] + [ + call(1), + call().method(arg='foo'), + call().method().other('bar'), + call().method().other()(2.0), + ] >>> m.mock_calls == kall.call_list() True diff --git a/Doc/tutorial/stdlib2.rst b/Doc/tutorial/stdlib2.rst index 6c68ba01081379..2c3ec71cd3de39 100644 --- a/Doc/tutorial/stdlib2.rst +++ b/Doc/tutorial/stdlib2.rst @@ -30,11 +30,22 @@ and indentation to more clearly reveal data structure:: ... 'yellow'], 'blue']]] ... >>> pprint.pprint(t, width=30) - [[[['black', 'cyan'], - 'white', - ['green', 'red']], - [['magenta', 'yellow'], - 'blue']]] + [ + [ + [ + ['black', 'cyan'], + 'white', + ['green', 'red'], + ], + [ + [ + 'magenta', + 'yellow', + ], + 'blue', + ], + ], + ] The :mod:`textwrap` module formats paragraphs of text to fit a given screen width:: diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 90d24bf96afeb4..685c1333afb306 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1087,12 +1087,11 @@ pickletools pprint ------ -* Add an *expand* keyword argument for :func:`pprint.pprint`, - :func:`pprint.pformat`, :func:`pprint.pp`. If true, the output will be - formatted similar to pretty-printed :func:`json.dumps` when - *indent* is supplied. +* :mod:`pprint` now uses modern defaults: ``indent=4, width=88``, + and the default ``compact=False`` output is now formatted similar to + pretty-printed :func:`json.dumps`. (Contributed by Stefan Todoran, Semyon Moroz and Hugo van Kemenade in - :gh:`112632`.) + :gh:`112632` and :gh:`149189`.) * Add t-string support to :mod:`pprint`. (Contributed by Loïc Simon and Hugo van Kemenade in :gh:`134551`.) diff --git a/Lib/difflib.py b/Lib/difflib.py index 8f3cdaed9564d8..eb249e3e288923 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -559,15 +559,17 @@ def get_grouped_opcodes(self, n=3): >>> b[23:28] = [] # Make a deletion >>> b[30] += 'y' # Make another replacement >>> pprint(list(SequenceMatcher(None,a,b).get_grouped_opcodes())) - [[('equal', 5, 8, 5, 8), ('insert', 8, 8, 8, 9), ('equal', 8, 11, 9, 12)], - [('equal', 16, 19, 17, 20), - ('replace', 19, 20, 20, 21), - ('equal', 20, 22, 21, 23), - ('delete', 22, 27, 23, 23), - ('equal', 27, 30, 23, 26)], - [('equal', 31, 34, 27, 30), - ('replace', 34, 35, 30, 31), - ('equal', 35, 38, 31, 34)]] + [ + [('equal', 5, 8, 5, 8), ('insert', 8, 8, 8, 9), ('equal', 8, 11, 9, 12)], + [ + ('equal', 16, 19, 17, 20), + ('replace', 19, 20, 20, 21), + ('equal', 20, 22, 21, 23), + ('delete', 22, 27, 23, 23), + ('equal', 27, 30, 23, 26), + ], + [('equal', 31, 34, 27, 30), ('replace', 34, 35, 30, 31), ('equal', 35, 38, 31, 34)], + ] """ codes = self.get_opcodes() @@ -784,16 +786,18 @@ class Differ: >>> from pprint import pprint as _pprint >>> _pprint(result) - [' 1. Beautiful is better than ugly.\n', - '- 2. Explicit is better than implicit.\n', - '- 3. Simple is better than complex.\n', - '+ 3. Simple is better than complex.\n', - '? ++\n', - '- 4. Complex is better than complicated.\n', - '? ^ ---- ^\n', - '+ 4. Complicated is better than complex.\n', - '? ++++ ^ ^\n', - '+ 5. Flat is better than nested.\n'] + [ + ' 1. Beautiful is better than ugly.\n', + '- 2. Explicit is better than implicit.\n', + '- 3. Simple is better than complex.\n', + '+ 3. Simple is better than complex.\n', + '? ++\n', + '- 4. Complex is better than complicated.\n', + '? ^ ---- ^\n', + '+ 4. Complicated is better than complex.\n', + '? ++++ ^ ^\n', + '+ 5. Flat is better than nested.\n', + ] As a single multi-line string it looks like this: diff --git a/Lib/pprint.py b/Lib/pprint.py index 7355021998081d..1fd7e3ec95a073 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -43,23 +43,38 @@ "PrettyPrinter", "pp"] -def pprint(object, stream=None, indent=1, width=80, depth=None, *, - compact=False, expand=False, sort_dicts=True, - underscore_numbers=False): +def pprint( + object, + stream=None, + indent=4, + width=88, + depth=None, + *, + compact=False, + sort_dicts=True, + underscore_numbers=False, +): """Pretty-print a Python object to a stream [default is sys.stdout].""" printer = PrettyPrinter( stream=stream, indent=indent, width=width, depth=depth, - compact=compact, expand=expand, sort_dicts=sort_dicts, + compact=compact, sort_dicts=sort_dicts, underscore_numbers=underscore_numbers) printer.pprint(object) -def pformat(object, indent=1, width=80, depth=None, *, - compact=False, expand=False, sort_dicts=True, - underscore_numbers=False): +def pformat( + object, + indent=4, + width=88, + depth=None, + *, + compact=False, + sort_dicts=True, + underscore_numbers=False, +): """Format a Python object into a pretty-printed representation.""" return PrettyPrinter(indent=indent, width=width, depth=depth, - compact=compact, expand=expand, sort_dicts=sort_dicts, + compact=compact, sort_dicts=sort_dicts, underscore_numbers=underscore_numbers).pformat(object) @@ -112,9 +127,17 @@ def _safe_tuple(t): class PrettyPrinter: - def __init__(self, indent=1, width=80, depth=None, stream=None, *, - compact=False, expand=False, sort_dicts=True, - underscore_numbers=False): + def __init__( + self, + indent=4, + width=88, + depth=None, + stream=None, + *, + compact=False, + sort_dicts=True, + underscore_numbers=False, + ): """Handle pretty printing operations onto a stream using a set of configured parameters. @@ -133,12 +156,6 @@ def __init__(self, indent=1, width=80, depth=None, stream=None, *, compact If true, several items will be combined in one line. - Incompatible with expand mode. - - expand - If true, the output will be formatted similar to - pretty-printed json.dumps() when ``indent`` is supplied. - Incompatible with compact mode. sort_dicts If true, dict keys are sorted. @@ -155,8 +172,6 @@ def __init__(self, indent=1, width=80, depth=None, stream=None, *, raise ValueError('depth must be > 0') if not width: raise ValueError('width must be != 0') - if compact and expand: - raise ValueError('compact and expand are incompatible') self._depth = depth self._indent_per_level = indent self._width = width @@ -165,7 +180,6 @@ def __init__(self, indent=1, width=80, depth=None, stream=None, *, else: self._stream = _sys.stdout self._compact = bool(compact) - self._expand = bool(expand) self._sort_dicts = sort_dicts self._underscore_numbers = underscore_numbers @@ -218,36 +232,36 @@ def _format(self, object, stream, indent, allowance, context, level): stream.write(rep) def _format_block_start(self, start_str, indent): - if self._expand: - return f"{start_str}\n{' ' * indent}" - return start_str + if self._compact: + return start_str + return f"{start_str}\n{' ' * indent}" def _format_block_end(self, end_str, indent): - if self._expand: - return f"\n{' ' * indent}{end_str}" - return end_str + if self._compact: + return end_str + return f"\n{' ' * indent}{end_str}" def _child_indent(self, indent, prefix_len): - if self._expand: - return indent - return indent + prefix_len + if self._compact: + return indent + prefix_len + return indent def _write_indent_padding(self, write): - if self._expand: - if self._indent_per_level > 0: - write(self._indent_per_level * " ") - elif self._indent_per_level > 1: - write((self._indent_per_level - 1) * " ") + if self._compact: + if self._indent_per_level > 1: + write((self._indent_per_level - 1) * " ") + elif self._indent_per_level > 0: + write(self._indent_per_level * " ") def _pprint_dataclass(self, object, stream, indent, allowance, context, level): # Lazy import to improve module import time from dataclasses import fields as dataclass_fields cls_name = object.__class__.__name__ - if self._expand: - indent += self._indent_per_level - else: + if self._compact: indent += len(cls_name) + 1 + else: + indent += self._indent_per_level items = [(f.name, getattr(object, f.name)) for f in dataclass_fields(object) if f.repr] stream.write(self._format_block_start(cls_name + '(', indent)) self._format_namespace_items(items, stream, indent, allowance, context, level) @@ -370,7 +384,7 @@ def _pprint_list(self, object, stream, indent, allowance, context, level): def _pprint_tuple(self, object, stream, indent, allowance, context, level): stream.write(self._format_block_start('(', indent)) - if len(object) == 1 and not self._expand: + if len(object) == 1 and self._compact: endchar = ',)' else: endchar = ')' @@ -391,7 +405,7 @@ def _pprint_set(self, object, stream, indent, allowance, context, level): else: stream.write(self._format_block_start(typ.__name__ + '({', indent)) endchar = '})' - if not self._expand: + if self._compact: indent += len(typ.__name__) + 1 object = sorted(object, key=_safe_key) self._format_items(object, stream, indent, allowance + len(endchar), @@ -409,10 +423,10 @@ def _pprint_str(self, object, stream, indent, allowance, context, level): chunks = [] lines = object.splitlines(True) if level == 1: - if self._expand: - indent += self._indent_per_level - else: + if self._compact: indent += 1 + else: + indent += self._indent_per_level allowance += 1 max_width1 = max_width = self._width - indent for i, line in enumerate(lines): @@ -465,10 +479,10 @@ def _pprint_bytes(self, object, stream, indent, allowance, context, level): return parens = level == 1 if parens: - if self._expand: - indent += self._indent_per_level - else: + if self._compact: indent += 1 + else: + indent += self._indent_per_level allowance += 1 write(self._format_block_start('(', indent)) delim = '' @@ -485,11 +499,11 @@ def _pprint_bytes(self, object, stream, indent, allowance, context, level): def _pprint_bytearray(self, object, stream, indent, allowance, context, level): write = stream.write write(self._format_block_start('bytearray(', indent)) - if self._expand: + if self._compact: + recursive_indent = indent + 10 + else: write(' ' * self._indent_per_level) recursive_indent = indent + self._indent_per_level - else: - recursive_indent = indent + 10 self._pprint_bytes(bytes(object), stream, recursive_indent, allowance + 1, context, level + 1) write(self._format_block_end(')', indent)) @@ -517,10 +531,10 @@ def _pprint_simplenamespace(self, object, stream, indent, allowance, context, le cls_name = 'namespace' else: cls_name = object.__class__.__name__ - if self._expand: - indent += self._indent_per_level - else: + if self._compact: indent += len(cls_name) + 1 + else: + indent += self._indent_per_level items = object.__dict__.items() stream.write(self._format_block_start(cls_name + '(', indent)) self._format_namespace_items(items, stream, indent, allowance, context, @@ -550,7 +564,7 @@ def _format_dict_items(self, items, stream, indent, allowance, context, ) if not last: write(delimnl) - elif self._expand: + elif not self._compact: write(',') def _format_namespace_items(self, items, stream, indent, allowance, context, level): @@ -576,7 +590,7 @@ def _format_namespace_items(self, items, stream, indent, allowance, context, lev ) if not last: write(delimnl) - elif self._expand: + elif not self._compact: write(',') def _format_items(self, items, stream, indent, allowance, context, level): @@ -618,7 +632,7 @@ def _format_items(self, items, stream, indent, allowance, context, level): self._format(ent, stream, indent, allowance if last else 1, context, level) - if last and self._expand: + if last and not self._compact: write(',') def _repr(self, object, context, level): @@ -643,11 +657,11 @@ def _pprint_default_dict(self, object, stream, indent, allowance, context, level return rdf = self._repr(object.default_factory, context, level) cls = object.__class__ - if self._expand: - stream.write('%s(%s, ' % (cls.__name__, rdf)) - else: + if self._compact: indent += len(cls.__name__) + 1 stream.write('%s(%s,\n%s' % (cls.__name__, rdf, ' ' * indent)) + else: + stream.write('%s(%s, ' % (cls.__name__, rdf)) self._pprint_dict(object, stream, indent, allowance + 1, context, level) stream.write(')') @@ -681,14 +695,14 @@ def _pprint_chain_map(self, object, stream, indent, allowance, context, level): cls = object.__class__ stream.write(self._format_block_start(cls.__name__ + '(', indent + self._indent_per_level)) - if self._expand: - indent += self._indent_per_level - else: + if self._compact: indent += len(cls.__name__) + 1 + else: + indent += self._indent_per_level for i, m in enumerate(object.maps): if i == len(object.maps) - 1: self._format(m, stream, indent, allowance + 1, context, level) - if self._expand: + if not self._compact: stream.write(',') stream.write(self._format_block_end(')', indent - self._indent_per_level)) else: @@ -703,7 +717,7 @@ def _pprint_deque(self, object, stream, indent, allowance, context, level): return cls = object.__class__ stream.write(self._format_block_start(cls.__name__ + '([', indent)) - if not self._expand: + if self._compact: indent += len(cls.__name__) + 1 if object.maxlen is None: self._format_items(object, stream, indent, allowance + 2, @@ -713,10 +727,10 @@ def _pprint_deque(self, object, stream, indent, allowance, context, level): self._format_items(object, stream, indent, 2, context, level) rml = self._repr(object.maxlen, context, level) - if self._expand: - stream.write('%s], maxlen=%s)' % ('\n' + ' ' * indent, rml)) - else: + if self._compact: stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml)) + else: + stream.write('%s], maxlen=%s)' % ('\n' + ' ' * indent, rml)) _dispatch[_collections.deque.__repr__] = _pprint_deque @@ -737,10 +751,10 @@ def _pprint_user_string(self, object, stream, indent, allowance, context, level) def _pprint_template(self, object, stream, indent, allowance, context, level): cls_name = object.__class__.__name__ - if self._expand: - indent += self._indent_per_level - else: + if self._compact: indent += len(cls_name) + 1 + else: + indent += self._indent_per_level items = ( ("strings", object.strings), @@ -756,7 +770,20 @@ def _pprint_template(self, object, stream, indent, allowance, context, level): def _pprint_interpolation(self, object, stream, indent, allowance, context, level): cls_name = object.__class__.__name__ - if self._expand: + if self._compact: + indent += len(cls_name) + items = ( + object.value, + object.expression, + object.conversion, + object.format_spec, + ) + stream.write(cls_name + "(") + self._format_items( + items, stream, indent, allowance, context, level + ) + stream.write(")") + else: indent += self._indent_per_level items = ( ("value", object.value), @@ -771,19 +798,6 @@ def _pprint_interpolation(self, object, stream, indent, allowance, context, leve stream.write( self._format_block_end(")", indent - self._indent_per_level) ) - else: - indent += len(cls_name) - items = ( - object.value, - object.expression, - object.conversion, - object.format_spec, - ) - stream.write(cls_name + "(") - self._format_items( - items, stream, indent, allowance, context, level - ) - stream.write(")") t = t"{0}" _dispatch[type(t).__repr__] = _pprint_template diff --git a/Lib/test/test_descrtut.py b/Lib/test/test_descrtut.py index 828440a993a975..425fb85e93558d 100644 --- a/Lib/test/test_descrtut.py +++ b/Lib/test/test_descrtut.py @@ -168,54 +168,56 @@ def merge(self, other): >>> import pprint >>> pprint.pprint(dir(list)) # like list.__dict__.keys(), but sorted - ['__add__', - '__class__', - '__class_getitem__', - '__contains__', - '__delattr__', - '__delitem__', - '__dir__', - '__doc__', - '__eq__', - '__format__', - '__ge__', - '__getattribute__', - '__getitem__', - '__getstate__', - '__gt__', - '__hash__', - '__iadd__', - '__imul__', - '__init__', - '__init_subclass__', - '__iter__', - '__le__', - '__len__', - '__lt__', - '__mul__', - '__ne__', - '__new__', - '__reduce__', - '__reduce_ex__', - '__repr__', - '__reversed__', - '__rmul__', - '__setattr__', - '__setitem__', - '__sizeof__', - '__str__', - '__subclasshook__', - 'append', - 'clear', - 'copy', - 'count', - 'extend', - 'index', - 'insert', - 'pop', - 'remove', - 'reverse', - 'sort'] + [ + '__add__', + '__class__', + '__class_getitem__', + '__contains__', + '__delattr__', + '__delitem__', + '__dir__', + '__doc__', + '__eq__', + '__format__', + '__ge__', + '__getattribute__', + '__getitem__', + '__getstate__', + '__gt__', + '__hash__', + '__iadd__', + '__imul__', + '__init__', + '__init_subclass__', + '__iter__', + '__le__', + '__len__', + '__lt__', + '__mul__', + '__ne__', + '__new__', + '__reduce__', + '__reduce_ex__', + '__repr__', + '__reversed__', + '__rmul__', + '__setattr__', + '__setitem__', + '__sizeof__', + '__str__', + '__subclasshook__', + 'append', + 'clear', + 'copy', + 'count', + 'extend', + 'index', + 'insert', + 'pop', + 'remove', + 'reverse', + 'sort', + ] The new introspection API gives more information than the old one: in addition to the regular methods, it also shows the methods that are diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py index 48375cf459ea0b..55a3c654aa0a47 100644 --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -786,11 +786,7 @@ def test_invocation(self): 'b': ('character string', b'byte string'), 'c': 'string' } - expect = ''' - {'a': [1, 2.0, (3+4j)], - 'b': ('character string', b'byte string'), - 'c': 'string'} - ''' + expect = "{'a': [1, 2.0, (3+4j)], 'b': ('character string', b'byte string'), 'c': 'string'}" self.set_pickle_data(data) with self.subTest(data=data): diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index 041c2072b9e253..d66758d3acd7be 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -3,6 +3,7 @@ import collections import contextlib import dataclasses +import functools import io import itertools import pprint @@ -15,6 +16,10 @@ from test.support import cpython_only from test.support.import_helper import ensure_lazy_imports +# Pin pre-3.15 width/indent for existing formatting tests. +# compact=True keeps the legacy non-JSON-style container wrapping. +_pformat = functools.partial(pprint.pformat, indent=1, width=80, compact=True) + # list, tuple and dict subclasses that do or don't overwrite __repr__ class list2(list): pass @@ -164,7 +169,6 @@ def test_init(self): self.assertRaises(ValueError, pprint.PrettyPrinter, depth=0) self.assertRaises(ValueError, pprint.PrettyPrinter, depth=-1) self.assertRaises(ValueError, pprint.PrettyPrinter, width=0) - self.assertRaises(ValueError, pprint.PrettyPrinter, compact=True, expand=True) def test_basic(self): # Verify .isrecursive() and .isreadable() w/o recursion @@ -284,10 +288,10 @@ def test_same_as_repr(self): True, False, None, ..., ): native = repr(simple) - self.assertEqual(pprint.pformat(simple), native) - self.assertEqual(pprint.pformat(simple, width=1, indent=0) + self.assertEqual(_pformat(simple), native) + self.assertEqual(_pformat(simple, width=1, indent=0) .replace('\n', ' '), native) - self.assertEqual(pprint.pformat(simple, underscore_numbers=True), native) + self.assertEqual(_pformat(simple, underscore_numbers=True), native) self.assertEqual(pprint.saferepr(simple), native) def test_container_repr_override_called(self): @@ -318,8 +322,8 @@ def test_container_repr_override_called(self): ): native = repr(cont) expected = '*' * len(native) - self.assertEqual(pprint.pformat(cont), expected) - self.assertEqual(pprint.pformat(cont, width=1, indent=0), expected) + self.assertEqual(_pformat(cont), expected) + self.assertEqual(_pformat(cont, width=1, indent=0), expected) self.assertEqual(pprint.saferepr(cont), expected) def test_basic_line_wrap(self): @@ -340,7 +344,7 @@ def test_basic_line_wrap(self): 'read_io_runtime_us': 0, 'write_io_runtime_us': 43690}""" for type in [dict, dict2]: - self.assertEqual(pprint.pformat(type(o)), exp) + self.assertEqual(_pformat(type(o)), exp) exp = """\ frozendict({'RPM_cal': 0, @@ -350,7 +354,7 @@ def test_basic_line_wrap(self): 'main_code_runtime_us': 0, 'read_io_runtime_us': 0, 'write_io_runtime_us': 43690})""" - self.assertEqual(pprint.pformat(frozendict(o)), exp) + self.assertEqual(_pformat(frozendict(o)), exp) exp = """\ frozendict2({'RPM_cal': 0, 'RPM_cal2': 48059, @@ -359,79 +363,84 @@ def test_basic_line_wrap(self): 'main_code_runtime_us': 0, 'read_io_runtime_us': 0, 'write_io_runtime_us': 43690})""" - self.assertEqual(pprint.pformat(frozendict2(o)), exp) + self.assertEqual(_pformat(frozendict2(o)), exp) o = range(100) - exp = 'dict_keys([%s])' % ',\n '.join(map(str, o)) + line_ranges = [(0, 22), (22, 42), (42, 62), (62, 82), (82, 100)] + ints = ",\n ".join( + ", ".join(str(i) for i in range(a, b)) for a, b in line_ranges + ) + exp = f"dict_keys([{ints}])" keys = dict.fromkeys(o).keys() - self.assertEqual(pprint.pformat(keys), exp) + self.assertEqual(_pformat(keys), exp) keys = frozendict.fromkeys(o).keys() - self.assertEqual(pprint.pformat(keys), exp) + self.assertEqual(_pformat(keys), exp) - o = range(100) - exp = 'dict_values([%s])' % ',\n '.join(map(str, o)) + exp = f"dict_values([{ints}])" values = {v: v for v in o}.values() - self.assertEqual(pprint.pformat(values), exp) + self.assertEqual(_pformat(values), exp) values = frozendict({v: v for v in o}).values() - self.assertEqual(pprint.pformat(values), exp) + self.assertEqual(_pformat(values), exp) - o = range(100) - exp = 'dict_items([%s])' % ',\n '.join("(%s, %s)" % (i, i) for i in o) + line_ranges = [ + (0, 10), (10, 18), (18, 26), (26, 34), (34, 42), (42, 50), (50, 58), + (58, 66), (66, 74), (74, 82), (82, 90), (90, 98), (98, 100), + ] + tups = ",\n ".join( + ", ".join(f"({i}, {i})" for i in range(a, b)) for a, b in line_ranges + ) + exp = f"dict_items([{tups}])" items = {v: v for v in o}.items() - self.assertEqual(pprint.pformat(items), exp) + self.assertEqual(_pformat(items), exp) items = frozendict({v: v for v in o}).items() - self.assertEqual(pprint.pformat(items), exp) + self.assertEqual(_pformat(items), exp) - o = range(100) - exp = 'odict_keys([%s])' % ',\n '.join(map(str, o)) + exp = f"odict_keys([{ints}])" keys = collections.OrderedDict.fromkeys(o).keys() - self.assertEqual(pprint.pformat(keys), exp) + self.assertEqual(_pformat(keys), exp) - o = range(100) - exp = 'odict_values([%s])' % ',\n '.join(map(str, o)) + exp = f"odict_values([{ints}])" values = collections.OrderedDict({v: v for v in o}).values() - self.assertEqual(pprint.pformat(values), exp) + self.assertEqual(_pformat(values), exp) - o = range(100) - exp = 'odict_items([%s])' % ',\n '.join("(%s, %s)" % (i, i) for i in o) + exp = f"odict_items([{tups}])" items = collections.OrderedDict({v: v for v in o}).items() - self.assertEqual(pprint.pformat(items), exp) + self.assertEqual(_pformat(items), exp) - o = range(100) - exp = 'KeysView({%s})' % (': None,\n '.join(map(str, o)) + ': None') + # KeysView etc. wrap a dict, which always formats one item per line. + none_pairs = ": None,\n ".join(map(str, o)) + ": None" + exp = f"KeysView({{{none_pairs}}})" keys_view = KeysView(dict.fromkeys(o)) - self.assertEqual(pprint.pformat(keys_view), exp) + self.assertEqual(_pformat(keys_view), exp) - o = range(100) - exp = 'ItemsView({%s})' % (': None,\n '.join(map(str, o)) + ': None') + exp = f"ItemsView({{{none_pairs}}})" items_view = ItemsView(dict.fromkeys(o)) - self.assertEqual(pprint.pformat(items_view), exp) + self.assertEqual(_pformat(items_view), exp) - o = range(100) - exp = 'MappingView({%s})' % (': None,\n '.join(map(str, o)) + ': None') + exp = f"MappingView({{{none_pairs}}})" mapping_view = MappingView(dict.fromkeys(o)) - self.assertEqual(pprint.pformat(mapping_view), exp) + self.assertEqual(_pformat(mapping_view), exp) - o = range(100) - exp = 'ValuesView({%s})' % (': None,\n '.join(map(str, o)) + ': None') + exp = f"ValuesView({{{none_pairs}}})" values_view = ValuesView(dict.fromkeys(o)) - self.assertEqual(pprint.pformat(values_view), exp) + self.assertEqual(_pformat(values_view), exp) - o = range(100) - exp = '[%s]' % ',\n '.join(map(str, o)) + exp = f"[{ints}]" for type in [list, list2]: - self.assertEqual(pprint.pformat(type(o)), exp) + self.assertEqual(_pformat(type(o)), exp) - o = tuple(range(100)) - exp = '(%s)' % ',\n '.join(map(str, o)) + exp = f"({ints})" for type in [tuple, tuple2]: - self.assertEqual(pprint.pformat(type(o)), exp) + self.assertEqual(_pformat(type(o)), exp) # indent parameter - o = range(100) - exp = '[ %s]' % ',\n '.join(map(str, o)) + line_ranges = [(0, 21), (21, 40), (40, 59), (59, 78), (78, 97), (97, 100)] + ints = ",\n ".join( + ", ".join(str(i) for i in range(a, b)) for a, b in line_ranges + ) + exp = f"[ {ints}]" for type in [list, list2]: - self.assertEqual(pprint.pformat(type(o), indent=4), exp) + self.assertEqual(_pformat(type(o), indent=4), exp) def test_nested_indentations(self): o1 = list(range(10)) @@ -440,13 +449,13 @@ def test_nested_indentations(self): expected = """\ [ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], {'first': 1, 'second': 2, 'third': 3}]""" - self.assertEqual(pprint.pformat(o, indent=4, width=42), expected) + self.assertEqual(pprint.pformat(o, indent=4, width=42, compact=True), expected) expected = """\ [ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], { 'first': 1, 'second': 2, 'third': 3}]""" - self.assertEqual(pprint.pformat(o, indent=4, width=41), expected) + self.assertEqual(pprint.pformat(o, indent=4, width=41, compact=True), expected) def test_width(self): expected = """\ @@ -460,17 +469,15 @@ def test_width(self): [[[[[1, 2, 3], '1 2']]]]]""" o = eval(expected) - self.assertEqual(pprint.pformat(o, width=15), expected) - self.assertEqual(pprint.pformat(o, width=16), expected) - self.assertEqual(pprint.pformat(o, width=25), expected) - self.assertEqual(pprint.pformat(o, width=14), """\ -[[[[[[1, - 2, + self.assertEqual(_pformat(o, width=15), expected) + self.assertEqual(_pformat(o, width=16), expected) + self.assertEqual(_pformat(o, width=25), expected) + self.assertEqual(_pformat(o, width=14), """\ +[[[[[[1, 2, 3], '1 ' '2']]]], - {1: [1, - 2, + {1: [1, 2, 3], 2: [12, 34]}, @@ -480,15 +487,14 @@ def test_width(self): 'ef',), set2({1, 23}), - [[[[[1, - 2, + [[[[[1, 2, 3], '1 ' '2']]]]]""") def test_integer(self): - self.assertEqual(pprint.pformat(1234567), '1234567') - self.assertEqual(pprint.pformat(1234567, underscore_numbers=True), '1_234_567') + self.assertEqual(_pformat(1234567), '1234567') + self.assertEqual(_pformat(1234567, underscore_numbers=True), '1_234_567') class Temperature(int): def __new__(cls, celsius_degrees): @@ -496,7 +502,7 @@ def __new__(cls, celsius_degrees): def __repr__(self): kelvin_degrees = self + 273.15 return f"{kelvin_degrees:.2f}°K" - self.assertEqual(pprint.pformat(Temperature(1000)), '1273.15°K') + self.assertEqual(_pformat(Temperature(1000)), '1273.15°K') def test_sorted_dict(self): # Starting in Python 2.5, pprint sorts dict displays by key regardless @@ -504,8 +510,8 @@ def test_sorted_dict(self): # Before the change, on 32-bit Windows pformat() gave order # 'a', 'c', 'b' here, so this test failed. d = {'a': 1, 'b': 1, 'c': 1} - self.assertEqual(pprint.pformat(d), "{'a': 1, 'b': 1, 'c': 1}") - self.assertEqual(pprint.pformat([d, d]), + self.assertEqual(_pformat(d), "{'a': 1, 'b': 1, 'c': 1}") + self.assertEqual(_pformat([d, d]), "[{'a': 1, 'b': 1, 'c': 1}, {'a': 1, 'b': 1, 'c': 1}]") # The next one is kind of goofy. The sorted order depends on the @@ -513,63 +519,42 @@ def test_sorted_dict(self): # Python 2.5, this was in the test_same_as_repr() test. It's worth # keeping around for now because it's one of few tests of pprint # against a crazy mix of types. - self.assertEqual(pprint.pformat({"xy\tab\n": (3,), 5: [[]], (): {}}), + self.assertEqual(_pformat({"xy\tab\n": (3,), 5: [[]], (): {}}), r"{5: [[]], 'xy\tab\n': (3,), (): {}}") def test_sort_dict(self): d = dict.fromkeys('cba') - self.assertEqual(pprint.pformat(d, sort_dicts=False), "{'c': None, 'b': None, 'a': None}") - self.assertEqual(pprint.pformat([d, d], sort_dicts=False), + self.assertEqual(_pformat(d, sort_dicts=False), "{'c': None, 'b': None, 'a': None}") + self.assertEqual(_pformat([d, d], sort_dicts=False), "[{'c': None, 'b': None, 'a': None}, {'c': None, 'b': None, 'a': None}]") def test_ordered_dict(self): d = collections.OrderedDict() - self.assertEqual(pprint.pformat(d, width=1), 'OrderedDict()') + self.assertEqual(_pformat(d, width=1), 'OrderedDict()') d = collections.OrderedDict([]) - self.assertEqual(pprint.pformat(d, width=1), 'OrderedDict()') + self.assertEqual(_pformat(d, width=1), 'OrderedDict()') words = 'the quick brown fox jumped over a lazy dog'.split() d = collections.OrderedDict(zip(words, itertools.count())) - self.assertEqual(pprint.pformat(d), -"""\ -OrderedDict([('the', 0), - ('quick', 1), - ('brown', 2), - ('fox', 3), - ('jumped', 4), - ('over', 5), - ('a', 6), - ('lazy', 7), - ('dog', 8)])""") - self.assertEqual(pprint.pformat(d.keys(), sort_dicts=False), + self.assertEqual(_pformat(d), """\ -odict_keys(['the', - 'quick', - 'brown', - 'fox', - 'jumped', - 'over', - 'a', - 'lazy', - 'dog'])""") - self.assertEqual(pprint.pformat(d.items(), sort_dicts=False), +OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), ('jumped', 4), + ('over', 5), ('a', 6), ('lazy', 7), ('dog', 8)])""") + self.assertEqual( + _pformat(d.keys(), sort_dicts=False), + "odict_keys(['the', 'quick', 'brown', 'fox', 'jumped', 'over', 'a', 'lazy', 'dog'])", + ) + self.assertEqual(_pformat(d.items(), sort_dicts=False), """\ -odict_items([('the', 0), - ('quick', 1), - ('brown', 2), - ('fox', 3), - ('jumped', 4), - ('over', 5), - ('a', 6), - ('lazy', 7), - ('dog', 8)])""") - self.assertEqual(pprint.pformat(d.values(), sort_dicts=False), +odict_items([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), ('jumped', 4), ('over', 5), + ('a', 6), ('lazy', 7), ('dog', 8)])""") + self.assertEqual(_pformat(d.values(), sort_dicts=False), "odict_values([0, 1, 2, 3, 4, 5, 6, 7, 8])") def test_mapping_proxy(self): words = 'the quick brown fox jumped over a lazy dog'.split() d = dict(zip(words, itertools.count())) m = types.MappingProxyType(d) - self.assertEqual(pprint.pformat(m), """\ + self.assertEqual(_pformat(m), """\ mappingproxy({'a': 6, 'brown': 2, 'dog': 8, @@ -581,49 +566,81 @@ def test_mapping_proxy(self): 'the': 0})""") d = collections.OrderedDict(zip(words, itertools.count())) m = types.MappingProxyType(d) - self.assertEqual(pprint.pformat(m), """\ -mappingproxy(OrderedDict([('the', 0), - ('quick', 1), - ('brown', 2), - ('fox', 3), - ('jumped', 4), - ('over', 5), - ('a', 6), - ('lazy', 7), + self.assertEqual(_pformat(m), """\ +mappingproxy(OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), + ('jumped', 4), ('over', 5), ('a', 6), ('lazy', 7), ('dog', 8)]))""") def test_dict_views(self): for dict_class in (dict, collections.OrderedDict, collections.Counter): empty = dict_class({}) short = dict_class(dict(zip('edcba', 'edcba'))) - long = dict_class(dict((chr(x), chr(x)) for x in range(90, 64, -1))) - lengths = {"empty": empty, "short": short, "long": long} + lengths = {"empty": empty, "short": short} prefix = "odict" if dict_class is collections.OrderedDict else "dict" for name, d in lengths.items(): with self.subTest(length=name, prefix=prefix): - is_short = len(d) < 6 - joiner = ", " if is_short else ",\n " k = d.keys() v = d.values() i = d.items() - self.assertEqual(pprint.pformat(k, sort_dicts=True), + self.assertEqual(_pformat(k, sort_dicts=True), prefix + "_keys([%s])" % - joiner.join(repr(key) for key in sorted(k))) - self.assertEqual(pprint.pformat(v, sort_dicts=True), + ", ".join(repr(key) for key in sorted(k))) + self.assertEqual(_pformat(v, sort_dicts=True), prefix + "_values([%s])" % - joiner.join(repr(val) for val in sorted(v))) - self.assertEqual(pprint.pformat(i, sort_dicts=True), + ", ".join(repr(val) for val in sorted(v))) + self.assertEqual(_pformat(i, sort_dicts=True), prefix + "_items([%s])" % - joiner.join(repr(item) for item in sorted(i))) - self.assertEqual(pprint.pformat(k, sort_dicts=False), + ", ".join(repr(item) for item in sorted(i))) + self.assertEqual(_pformat(k, sort_dicts=False), prefix + "_keys([%s])" % - joiner.join(repr(key) for key in k)) - self.assertEqual(pprint.pformat(v, sort_dicts=False), + ", ".join(repr(key) for key in k)) + self.assertEqual(_pformat(v, sort_dicts=False), prefix + "_values([%s])" % - joiner.join(repr(val) for val in v)) - self.assertEqual(pprint.pformat(i, sort_dicts=False), + ", ".join(repr(val) for val in v)) + self.assertEqual(_pformat(i, sort_dicts=False), prefix + "_items([%s])" % - joiner.join(repr(item) for item in i)) + ", ".join(repr(item) for item in i)) + + # Long case: views wrap with compact-mode packing. + long = dict((chr(x), chr(x)) for x in range(90, 64, -1)) + sorted_keys = ( + "['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',\n" + " 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']" + ) + unsorted_keys = ( + "['Z', 'Y', 'X', 'W', 'V', 'U', 'T', 'S', 'R', 'Q', 'P', 'O', 'N', 'M', 'L', 'K',\n" + " 'J', 'I', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A']" + ) + sorted_items = ( + "[('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D'), ('E', 'E'), ('F', 'F'),\n" + " ('G', 'G'), ('H', 'H'), ('I', 'I'), ('J', 'J'), ('K', 'K'), ('L', 'L'),\n" + " ('M', 'M'), ('N', 'N'), ('O', 'O'), ('P', 'P'), ('Q', 'Q'), ('R', 'R'),\n" + " ('S', 'S'), ('T', 'T'), ('U', 'U'), ('V', 'V'), ('W', 'W'), ('X', 'X'),\n" + " ('Y', 'Y'), ('Z', 'Z')]" + ) + unsorted_items = ( + "[('Z', 'Z'), ('Y', 'Y'), ('X', 'X'), ('W', 'W'), ('V', 'V'), ('U', 'U'),\n" + " ('T', 'T'), ('S', 'S'), ('R', 'R'), ('Q', 'Q'), ('P', 'P'), ('O', 'O'),\n" + " ('N', 'N'), ('M', 'M'), ('L', 'L'), ('K', 'K'), ('J', 'J'), ('I', 'I'),\n" + " ('H', 'H'), ('G', 'G'), ('F', 'F'), ('E', 'E'), ('D', 'D'), ('C', 'C'),\n" + " ('B', 'B'), ('A', 'A')]" + ) + for dict_class in (dict, collections.OrderedDict, collections.Counter): + d = dict_class(long) + prefix = "odict" if dict_class is collections.OrderedDict else "dict" + with self.subTest(length="long", prefix=prefix): + self.assertEqual(_pformat(d.keys(), sort_dicts=True), + f"{prefix}_keys({sorted_keys})") + self.assertEqual(_pformat(d.values(), sort_dicts=True), + f"{prefix}_values({sorted_keys})") + self.assertEqual(_pformat(d.items(), sort_dicts=True), + f"{prefix}_items({sorted_items})") + self.assertEqual(_pformat(d.keys(), sort_dicts=False), + f"{prefix}_keys({unsorted_keys})") + self.assertEqual(_pformat(d.values(), sort_dicts=False), + f"{prefix}_values({unsorted_keys})") + self.assertEqual(_pformat(d.items(), sort_dicts=False), + f"{prefix}_items({unsorted_items})") def test_abc_views(self): empty = {} @@ -641,55 +658,55 @@ class MV(MappingView): pass s = sorted(i) joined_items = "({%s})" % joiner.join(["%r: %r" % (k, v) for (k, v) in i]) sorted_items = "({%s})" % joiner.join(["%r: %r" % (k, v) for (k, v) in s]) - self.assertEqual(pprint.pformat(KeysView(d), sort_dicts=True), + self.assertEqual(_pformat(KeysView(d), sort_dicts=True), KeysView.__name__ + sorted_items) - self.assertEqual(pprint.pformat(ItemsView(d), sort_dicts=True), + self.assertEqual(_pformat(ItemsView(d), sort_dicts=True), ItemsView.__name__ + sorted_items) - self.assertEqual(pprint.pformat(MappingView(d), sort_dicts=True), + self.assertEqual(_pformat(MappingView(d), sort_dicts=True), MappingView.__name__ + sorted_items) - self.assertEqual(pprint.pformat(MV(d), sort_dicts=True), + self.assertEqual(_pformat(MV(d), sort_dicts=True), MV.__name__ + sorted_items) - self.assertEqual(pprint.pformat(ValuesView(d), sort_dicts=True), + self.assertEqual(_pformat(ValuesView(d), sort_dicts=True), ValuesView.__name__ + sorted_items) - self.assertEqual(pprint.pformat(KeysView(d), sort_dicts=False), + self.assertEqual(_pformat(KeysView(d), sort_dicts=False), KeysView.__name__ + joined_items) - self.assertEqual(pprint.pformat(ItemsView(d), sort_dicts=False), + self.assertEqual(_pformat(ItemsView(d), sort_dicts=False), ItemsView.__name__ + joined_items) - self.assertEqual(pprint.pformat(MappingView(d), sort_dicts=False), + self.assertEqual(_pformat(MappingView(d), sort_dicts=False), MappingView.__name__ + joined_items) - self.assertEqual(pprint.pformat(MV(d), sort_dicts=False), + self.assertEqual(_pformat(MV(d), sort_dicts=False), MV.__name__ + joined_items) - self.assertEqual(pprint.pformat(ValuesView(d), sort_dicts=False), + self.assertEqual(_pformat(ValuesView(d), sort_dicts=False), ValuesView.__name__ + joined_items) def test_nested_views(self): d = {1: MappingView({1: MappingView({1: MappingView({1: 2})})})} self.assertEqual(repr(d), "{1: MappingView({1: MappingView({1: MappingView({1: 2})})})}") - self.assertEqual(pprint.pformat(d), + self.assertEqual(_pformat(d), "{1: MappingView({1: MappingView({1: MappingView({1: 2})})})}") - self.assertEqual(pprint.pformat(d, depth=2), + self.assertEqual(_pformat(d, depth=2), "{1: MappingView({1: {...}})}") d = {} d1 = {1: d.values()} d2 = {1: d1.values()} d3 = {1: d2.values()} - self.assertEqual(pprint.pformat(d3), + self.assertEqual(_pformat(d3), "{1: dict_values([dict_values([dict_values([])])])}") - self.assertEqual(pprint.pformat(d3, depth=2), + self.assertEqual(_pformat(d3, depth=2), "{1: dict_values([{...}])}") def test_unorderable_items_views(self): """Check that views with unorderable items have stable sorting.""" d = dict((((3+1j), 3), ((1+1j), (1+0j)), (1j, 0j), (500, None), (499, None))) iv = ItemsView(d) - self.assertEqual(pprint.pformat(iv), - pprint.pformat(iv)) - self.assertTrue(pprint.pformat(iv).endswith(", 499: None, 500: None})"), - pprint.pformat(iv)) - self.assertEqual(pprint.pformat(d.items()), # Won't be equal unless _safe_tuple - pprint.pformat(d.items())) # is used in _safe_repr - self.assertTrue(pprint.pformat(d.items()).endswith(", (499, None), (500, None)])")) + self.assertEqual(_pformat(iv), + _pformat(iv)) + self.assertTrue(_pformat(iv).endswith(", 499: None, 500: None})"), + _pformat(iv)) + self.assertEqual(_pformat(d.items()), # Won't be equal unless _safe_tuple + _pformat(d.items())) # is used in _safe_repr + self.assertTrue(_pformat(d.items()).endswith(", (499, None), (500, None)])")) def test_mapping_view_subclass_no_mapping(self): class BMV(MappingView): @@ -698,7 +715,7 @@ def __init__(self, d): self.mapping = self._mapping del self._mapping - self.assertRaises(AttributeError, pprint.pformat, BMV({})) + self.assertRaises(AttributeError, _pformat, BMV({})) def test_mapping_subclass_repr(self): """Test that mapping ABC views use their ._mapping's __repr__.""" @@ -722,10 +739,10 @@ def __repr__(self): self.assertEqual(repr(m), "MyMapping(['test', 1])") short_view_repr = "%s(MyMapping(['test', 1]))" self.assertEqual(repr(m.keys()), short_view_repr % "KeysView") - self.assertEqual(pprint.pformat(m.items()), short_view_repr % "ItemsView") - self.assertEqual(pprint.pformat(m.keys()), short_view_repr % "KeysView") - self.assertEqual(pprint.pformat(MappingView(m)), short_view_repr % "MappingView") - self.assertEqual(pprint.pformat(m.values()), short_view_repr % "ValuesView") + self.assertEqual(_pformat(m.items()), short_view_repr % "ItemsView") + self.assertEqual(_pformat(m.keys()), short_view_repr % "KeysView") + self.assertEqual(_pformat(MappingView(m)), short_view_repr % "MappingView") + self.assertEqual(_pformat(m.values()), short_view_repr % "ValuesView") alpha = "abcdefghijklmnopqrstuvwxyz" m = MyMapping(alpha) @@ -733,19 +750,19 @@ def __repr__(self): long_view_repr = "%%s(MyMapping([%s]))" % alpha_repr self.assertEqual(repr(m), "MyMapping([%s])" % alpha_repr) self.assertEqual(repr(m.keys()), long_view_repr % "KeysView") - self.assertEqual(pprint.pformat(m.items()), long_view_repr % "ItemsView") - self.assertEqual(pprint.pformat(m.keys()), long_view_repr % "KeysView") - self.assertEqual(pprint.pformat(MappingView(m)), long_view_repr % "MappingView") - self.assertEqual(pprint.pformat(m.values()), long_view_repr % "ValuesView") + self.assertEqual(_pformat(m.items()), long_view_repr % "ItemsView") + self.assertEqual(_pformat(m.keys()), long_view_repr % "KeysView") + self.assertEqual(_pformat(MappingView(m)), long_view_repr % "MappingView") + self.assertEqual(_pformat(m.values()), long_view_repr % "ValuesView") def test_empty_simple_namespace(self): ns = types.SimpleNamespace() - formatted = pprint.pformat(ns) + formatted = _pformat(ns) self.assertEqual(formatted, "namespace()") def test_small_simple_namespace(self): ns = types.SimpleNamespace(a=1, b=2) - formatted = pprint.pformat(ns) + formatted = _pformat(ns) self.assertEqual(formatted, "namespace(a=1, b=2)") def test_simple_namespace(self): @@ -760,7 +777,7 @@ def test_simple_namespace(self): lazy=7, dog=8, ) - formatted = pprint.pformat(ns, width=60, indent=4) + formatted = pprint.pformat(ns, width=60, indent=4, compact=True) self.assertEqual(formatted, """\ namespace(the=0, quick=1, @@ -785,7 +802,7 @@ class AdvancedNamespace(types.SimpleNamespace): pass lazy=7, dog=8, ) - formatted = pprint.pformat(ns, width=60) + formatted = _pformat(ns, width=60) self.assertEqual(formatted, """\ AdvancedNamespace(the=0, quick=1, @@ -799,17 +816,17 @@ class AdvancedNamespace(types.SimpleNamespace): pass def test_empty_dataclass(self): dc = dataclasses.make_dataclass("MyDataclass", ())() - formatted = pprint.pformat(dc) + formatted = _pformat(dc) self.assertEqual(formatted, "MyDataclass()") def test_small_dataclass(self): dc = dataclass1("text", 123) - formatted = pprint.pformat(dc) + formatted = _pformat(dc) self.assertEqual(formatted, "dataclass1(field1='text', field2=123, field3=False)") def test_larger_dataclass(self): dc = dataclass1("some fairly long text", int(1e10), True) - formatted = pprint.pformat([dc, dc], width=60, indent=4) + formatted = pprint.pformat([dc, dc], width=60, indent=4, compact=True) self.assertEqual(formatted, """\ [ dataclass1(field1='some fairly long text', field2=10000000000, @@ -820,12 +837,12 @@ def test_larger_dataclass(self): def test_dataclass_with_repr(self): dc = dataclass2() - formatted = pprint.pformat(dc, width=20) + formatted = _pformat(dc, width=20) self.assertEqual(formatted, "custom repr that doesn't fit within pprint width") def test_dataclass_no_repr(self): dc = dataclass3() - formatted = pprint.pformat(dc, width=10) + formatted = _pformat(dc, width=10) self.assertRegex( formatted, fr"<{re.escape(__name__)}.dataclass3 object at \w+>", @@ -834,7 +851,7 @@ def test_dataclass_no_repr(self): def test_recursive_dataclass(self): dc = dataclass4(None) dc.a = dc - formatted = pprint.pformat(dc, width=10) + formatted = _pformat(dc, width=10) self.assertEqual(formatted, """\ dataclass4(a=..., b=1)""") @@ -844,7 +861,7 @@ def test_cyclic_dataclass(self): dc6 = dataclass6(None) dc5.a = dc6 dc6.c = dc5 - formatted = pprint.pformat(dc5, width=10) + formatted = _pformat(dc5, width=10) self.assertEqual(formatted, """\ dataclass5(a=dataclass6(c=..., d=1), @@ -858,7 +875,7 @@ def test_subclassing(self): {'names with spaces': 'should be presented using repr()', others.should.not.be: like.this}""" - dotted_printer = DottedPrettyPrinter() + dotted_printer = DottedPrettyPrinter(indent=1, compact=True) self.assertEqual(dotted_printer.pformat(o), exp) # length(repr(obj)) < width @@ -870,47 +887,29 @@ def test_subclassing(self): self.assertEqual(dotted_printer.pformat(o2), exp2) def test_set_reprs(self): - self.assertEqual(pprint.pformat(set()), 'set()') - self.assertEqual(pprint.pformat(set(range(3))), '{0, 1, 2}') - self.assertEqual(pprint.pformat(set(range(7)), width=20), '''\ -{0, - 1, - 2, - 3, - 4, - 5, + self.assertEqual(_pformat(set()), 'set()') + self.assertEqual(_pformat(set(range(3))), '{0, 1, 2}') + self.assertEqual(_pformat(set(range(7)), width=20), '''\ +{0, 1, 2, 3, 4, 5, 6}''') - self.assertEqual(pprint.pformat(set2(range(7)), width=20), '''\ -set2({0, - 1, - 2, - 3, - 4, - 5, - 6})''') - self.assertEqual(pprint.pformat(set3(range(7)), width=20), + self.assertEqual(_pformat(set2(range(7)), width=20), '''\ +set2({0, 1, 2, 3, 4, + 5, 6})''') + self.assertEqual(_pformat(set3(range(7)), width=20), 'set3({0, 1, 2, 3, 4, 5, 6})') - self.assertEqual(pprint.pformat(frozenset()), 'frozenset()') - self.assertEqual(pprint.pformat(frozenset(range(3))), + self.assertEqual(_pformat(frozenset()), 'frozenset()') + self.assertEqual(_pformat(frozenset(range(3))), 'frozenset({0, 1, 2})') - self.assertEqual(pprint.pformat(frozenset(range(7)), width=20), '''\ -frozenset({0, - 1, - 2, - 3, - 4, - 5, + self.assertEqual(_pformat(frozenset(range(7)), width=20), '''\ +frozenset({0, 1, 2, + 3, 4, 5, 6})''') - self.assertEqual(pprint.pformat(frozenset2(range(7)), width=20), '''\ -frozenset2({0, - 1, - 2, - 3, - 4, - 5, + self.assertEqual(_pformat(frozenset2(range(7)), width=20), '''\ +frozenset2({0, 1, 2, + 3, 4, 5, 6})''') - self.assertEqual(pprint.pformat(frozenset3(range(7)), width=20), + self.assertEqual(_pformat(frozenset3(range(7)), width=20), 'frozenset3({0, 1, 2, 3, 4, 5, 6})') def test_set_of_sets_reprs(self): @@ -942,21 +941,21 @@ def test_set_of_sets_reprs(self): fs0 = frozenset() fs1 = frozenset(('abc', 'xyz')) data = frozenset((fs0, fs1)) - self.assertEqual(pprint.pformat(data), + self.assertEqual(_pformat(data), 'frozenset({%r, %r})' % (fs0, fs1)) - self.assertEqual(pprint.pformat(data), repr(data)) + self.assertEqual(_pformat(data), repr(data)) fs2 = frozenset(('one', 'two')) data = {fs2: frozenset((fs0, fs1))} - self.assertEqual(pprint.pformat(data), + self.assertEqual(_pformat(data), "{%r: frozenset({%r, %r})}" % (fs2, fs0, fs1)) - self.assertEqual(pprint.pformat(data), repr(data)) + self.assertEqual(_pformat(data), repr(data)) # Single-line, unordered: fs1 = frozenset(("xyz", "qwerty")) fs2 = frozenset(("abcd", "spam")) fs = frozenset((fs1, fs2)) - self.assertEqual(pprint.pformat(fs), repr(fs)) + self.assertEqual(_pformat(fs), repr(fs)) # Multiline, unordered: def check(res, invariants): @@ -966,7 +965,7 @@ def check(res, invariants): fs1 = frozenset(('regular string', 'other string')) fs2 = frozenset(('third string', 'one more string')) check( - pprint.pformat(frozenset((fs1, fs2))), + _pformat(frozenset((fs1, fs2))), [ """ frozenset({%r, @@ -981,7 +980,7 @@ def check(res, invariants): # Everything is multiline, unordered: check( - pprint.pformat( + _pformat( frozenset(( frozenset(( "xyz very-very long string", @@ -1028,16 +1027,16 @@ def test_depth(self): nested_tuple = (1, (2, (3, (4, (5, 6))))) nested_dict = {1: {2: {3: {4: {5: {6: 6}}}}}} nested_list = [1, [2, [3, [4, [5, [6, []]]]]]] - self.assertEqual(pprint.pformat(nested_tuple), repr(nested_tuple)) - self.assertEqual(pprint.pformat(nested_dict), repr(nested_dict)) - self.assertEqual(pprint.pformat(nested_list), repr(nested_list)) + self.assertEqual(_pformat(nested_tuple), repr(nested_tuple)) + self.assertEqual(_pformat(nested_dict), repr(nested_dict)) + self.assertEqual(_pformat(nested_list), repr(nested_list)) lv1_tuple = '(1, (...))' lv1_dict = '{1: {...}}' lv1_list = '[1, [...]]' - self.assertEqual(pprint.pformat(nested_tuple, depth=1), lv1_tuple) - self.assertEqual(pprint.pformat(nested_dict, depth=1), lv1_dict) - self.assertEqual(pprint.pformat(nested_list, depth=1), lv1_list) + self.assertEqual(_pformat(nested_tuple, depth=1), lv1_tuple) + self.assertEqual(_pformat(nested_dict, depth=1), lv1_dict) + self.assertEqual(_pformat(nested_list, depth=1), lv1_list) def test_sort_unorderable_values(self): # Issue 3976: sorted pprints fail for unorderable values. @@ -1047,24 +1046,24 @@ def test_sort_unorderable_values(self): skeys = sorted(keys, key=id) clean = lambda s: s.replace(' ', '').replace('\n','') - self.assertEqual(clean(pprint.pformat(set(keys))), + self.assertEqual(clean(_pformat(set(keys))), '{' + ','.join(map(repr, skeys)) + '}') - self.assertEqual(clean(pprint.pformat(frozenset(keys))), + self.assertEqual(clean(_pformat(frozenset(keys))), 'frozenset({' + ','.join(map(repr, skeys)) + '})') - self.assertEqual(clean(pprint.pformat(dict.fromkeys(keys))), + self.assertEqual(clean(_pformat(dict.fromkeys(keys))), '{' + ','.join('%r:None' % k for k in skeys) + '}') - self.assertEqual(clean(pprint.pformat(dict.fromkeys(keys).keys())), + self.assertEqual(clean(_pformat(dict.fromkeys(keys).keys())), 'dict_keys([' + ','.join('%r' % k for k in skeys) + '])') - self.assertEqual(clean(pprint.pformat(dict.fromkeys(keys).items())), + self.assertEqual(clean(_pformat(dict.fromkeys(keys).items())), 'dict_items([' + ','.join('(%r,None)' % k for k in skeys) + '])') # Issue 10017: TypeError on user-defined types as dict keys. - self.assertEqual(pprint.pformat({Unorderable: 0, 1: 0}), + self.assertEqual(_pformat({Unorderable: 0, 1: 0}), '{1: 0, ' + repr(Unorderable) +': 0}') # Issue 14998: TypeError on tuples with NoneTypes as dict keys. keys = [(1,), (None,)] - self.assertEqual(pprint.pformat(dict.fromkeys(keys, 0)), + self.assertEqual(_pformat(dict.fromkeys(keys, 0)), '{%r: 0, %r: 0}' % tuple(sorted(keys, key=id))) def test_sort_orderable_and_unorderable_values(self): @@ -1077,24 +1076,24 @@ def test_sort_orderable_and_unorderable_values(self): self.assertEqual(sorted([b, a]), [a, b]) self.assertEqual(sorted([a, b]), [a, b]) # set - self.assertEqual(pprint.pformat(set([b, a]), width=1), + self.assertEqual(_pformat(set([b, a]), width=1), '{%r,\n %r}' % (a, b)) - self.assertEqual(pprint.pformat(set([a, b]), width=1), + self.assertEqual(_pformat(set([a, b]), width=1), '{%r,\n %r}' % (a, b)) # dict - self.assertEqual(pprint.pformat(dict.fromkeys([b, a]), width=1), + self.assertEqual(_pformat(dict.fromkeys([b, a]), width=1), '{%r: None,\n %r: None}' % (a, b)) - self.assertEqual(pprint.pformat(dict.fromkeys([a, b]), width=1), + self.assertEqual(_pformat(dict.fromkeys([a, b]), width=1), '{%r: None,\n %r: None}' % (a, b)) def test_str_wrap(self): # pprint tries to wrap strings intelligently fox = 'the quick brown fox jumped over a lazy dog' - self.assertEqual(pprint.pformat(fox, width=19), """\ + self.assertEqual(_pformat(fox, width=19), """\ ('the quick brown ' 'fox jumped over ' 'a lazy dog')""") - self.assertEqual(pprint.pformat({'a': 1, 'b': fox, 'c': 2}, + self.assertEqual(_pformat({'a': 1, 'b': fox, 'c': 2}, width=25), """\ {'a': 1, 'b': 'the quick brown ' @@ -1107,28 +1106,28 @@ def test_str_wrap(self): # - non-ASCII is allowed # - an apostrophe doesn't disrupt the pprint special = "Portons dix bons \"whiskys\"\nà l'avocat goujat\t qui fumait au zoo" - self.assertEqual(pprint.pformat(special, width=68), repr(special)) - self.assertEqual(pprint.pformat(special, width=31), """\ + self.assertEqual(_pformat(special, width=68), repr(special)) + self.assertEqual(_pformat(special, width=31), """\ ('Portons dix bons "whiskys"\\n' "à l'avocat goujat\\t qui " 'fumait au zoo')""") - self.assertEqual(pprint.pformat(special, width=20), """\ + self.assertEqual(_pformat(special, width=20), """\ ('Portons dix bons ' '"whiskys"\\n' "à l'avocat " 'goujat\\t qui ' 'fumait au zoo')""") - self.assertEqual(pprint.pformat([[[[[special]]]]], width=35), """\ + self.assertEqual(_pformat([[[[[special]]]]], width=35), """\ [[[[['Portons dix bons "whiskys"\\n' "à l'avocat goujat\\t qui " 'fumait au zoo']]]]]""") - self.assertEqual(pprint.pformat([[[[[special]]]]], width=25), """\ + self.assertEqual(_pformat([[[[[special]]]]], width=25), """\ [[[[['Portons dix bons ' '"whiskys"\\n' "à l'avocat " 'goujat\\t qui ' 'fumait au zoo']]]]]""") - self.assertEqual(pprint.pformat([[[[[special]]]]], width=23), """\ + self.assertEqual(_pformat([[[[[special]]]]], width=23), """\ [[[[['Portons dix ' 'bons "whiskys"\\n' "à l'avocat " @@ -1137,14 +1136,14 @@ def test_str_wrap(self): 'zoo']]]]]""") # An unwrappable string is formatted as its repr unwrappable = "x" * 100 - self.assertEqual(pprint.pformat(unwrappable, width=80), repr(unwrappable)) - self.assertEqual(pprint.pformat(''), "''") + self.assertEqual(_pformat(unwrappable, width=80), repr(unwrappable)) + self.assertEqual(_pformat(''), "''") # Check that the pprint is a usable repr special *= 10 for width in range(3, 40): - formatted = pprint.pformat(special, width=width) + formatted = _pformat(special, width=width) self.assertEqual(eval(formatted), special) - formatted = pprint.pformat([special] * 2, width=width) + formatted = _pformat([special] * 2, width=width) self.assertEqual(eval(formatted), [special] * 2) def test_compact(self): @@ -1157,7 +1156,7 @@ def test_compact(self): 14, 15], [], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4]]""" - self.assertEqual(pprint.pformat(o, width=47, compact=True), expected) + self.assertEqual(_pformat(o, width=47, compact=True), expected) def test_compact_width(self): levels = 20 @@ -1166,117 +1165,117 @@ def test_compact_width(self): for i in range(levels - 1): o = [o] for w in range(levels * 2 + 1, levels + 3 * number - 1): - lines = pprint.pformat(o, width=w, compact=True).splitlines() + lines = _pformat(o, width=w, compact=True).splitlines() maxwidth = max(map(len, lines)) self.assertLessEqual(maxwidth, w) self.assertGreater(maxwidth, w - 3) def test_bytes_wrap(self): - self.assertEqual(pprint.pformat(b'', width=1), "b''") - self.assertEqual(pprint.pformat(b'abcd', width=1), "b'abcd'") + self.assertEqual(_pformat(b'', width=1), "b''") + self.assertEqual(_pformat(b'abcd', width=1), "b'abcd'") letters = b'abcdefghijklmnopqrstuvwxyz' - self.assertEqual(pprint.pformat(letters, width=29), repr(letters)) - self.assertEqual(pprint.pformat(letters, width=19), """\ + self.assertEqual(_pformat(letters, width=29), repr(letters)) + self.assertEqual(_pformat(letters, width=19), """\ (b'abcdefghijkl' b'mnopqrstuvwxyz')""") - self.assertEqual(pprint.pformat(letters, width=18), """\ + self.assertEqual(_pformat(letters, width=18), """\ (b'abcdefghijkl' b'mnopqrstuvwx' b'yz')""") - self.assertEqual(pprint.pformat(letters, width=16), """\ + self.assertEqual(_pformat(letters, width=16), """\ (b'abcdefghijkl' b'mnopqrstuvwx' b'yz')""") special = bytes(range(16)) - self.assertEqual(pprint.pformat(special, width=61), repr(special)) - self.assertEqual(pprint.pformat(special, width=48), """\ + self.assertEqual(_pformat(special, width=61), repr(special)) + self.assertEqual(_pformat(special, width=48), """\ (b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(pprint.pformat(special, width=32), """\ + self.assertEqual(_pformat(special, width=32), """\ (b'\\x00\\x01\\x02\\x03' b'\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(pprint.pformat(special, width=1), """\ + self.assertEqual(_pformat(special, width=1), """\ (b'\\x00\\x01\\x02\\x03' b'\\x04\\x05\\x06\\x07' b'\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(pprint.pformat({'a': 1, 'b': letters, 'c': 2}, + self.assertEqual(_pformat({'a': 1, 'b': letters, 'c': 2}, width=21), """\ {'a': 1, 'b': b'abcdefghijkl' b'mnopqrstuvwx' b'yz', 'c': 2}""") - self.assertEqual(pprint.pformat({'a': 1, 'b': letters, 'c': 2}, + self.assertEqual(_pformat({'a': 1, 'b': letters, 'c': 2}, width=20), """\ {'a': 1, 'b': b'abcdefgh' b'ijklmnop' b'qrstuvwxyz', 'c': 2}""") - self.assertEqual(pprint.pformat([[[[[[letters]]]]]], width=25), """\ + self.assertEqual(_pformat([[[[[[letters]]]]]], width=25), """\ [[[[[[b'abcdefghijklmnop' b'qrstuvwxyz']]]]]]""") - self.assertEqual(pprint.pformat([[[[[[special]]]]]], width=41), """\ + self.assertEqual(_pformat([[[[[[special]]]]]], width=41), """\ [[[[[[b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07' b'\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f']]]]]]""") # Check that the pprint is a usable repr for width in range(1, 64): - formatted = pprint.pformat(special, width=width) + formatted = _pformat(special, width=width) self.assertEqual(eval(formatted), special) - formatted = pprint.pformat([special] * 2, width=width) + formatted = _pformat([special] * 2, width=width) self.assertEqual(eval(formatted), [special] * 2) def test_bytearray_wrap(self): - self.assertEqual(pprint.pformat(bytearray(), width=1), "bytearray(b'')") + self.assertEqual(_pformat(bytearray(), width=1), "bytearray(b'')") letters = bytearray(b'abcdefghijklmnopqrstuvwxyz') - self.assertEqual(pprint.pformat(letters, width=40), repr(letters)) - self.assertEqual(pprint.pformat(letters, width=28), """\ + self.assertEqual(_pformat(letters, width=40), repr(letters)) + self.assertEqual(_pformat(letters, width=28), """\ bytearray(b'abcdefghijkl' b'mnopqrstuvwxyz')""") - self.assertEqual(pprint.pformat(letters, width=27), """\ + self.assertEqual(_pformat(letters, width=27), """\ bytearray(b'abcdefghijkl' b'mnopqrstuvwx' b'yz')""") - self.assertEqual(pprint.pformat(letters, width=25), """\ + self.assertEqual(_pformat(letters, width=25), """\ bytearray(b'abcdefghijkl' b'mnopqrstuvwx' b'yz')""") special = bytearray(range(16)) - self.assertEqual(pprint.pformat(special, width=72), repr(special)) - self.assertEqual(pprint.pformat(special, width=57), """\ + self.assertEqual(_pformat(special, width=72), repr(special)) + self.assertEqual(_pformat(special, width=57), """\ bytearray(b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(pprint.pformat(special, width=41), """\ + self.assertEqual(_pformat(special, width=41), """\ bytearray(b'\\x00\\x01\\x02\\x03' b'\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(pprint.pformat(special, width=1), """\ + self.assertEqual(_pformat(special, width=1), """\ bytearray(b'\\x00\\x01\\x02\\x03' b'\\x04\\x05\\x06\\x07' b'\\x08\\t\\n\\x0b' b'\\x0c\\r\\x0e\\x0f')""") - self.assertEqual(pprint.pformat({'a': 1, 'b': letters, 'c': 2}, + self.assertEqual(_pformat({'a': 1, 'b': letters, 'c': 2}, width=31), """\ {'a': 1, 'b': bytearray(b'abcdefghijkl' b'mnopqrstuvwx' b'yz'), 'c': 2}""") - self.assertEqual(pprint.pformat([[[[[letters]]]]], width=37), """\ + self.assertEqual(_pformat([[[[[letters]]]]], width=37), """\ [[[[[bytearray(b'abcdefghijklmnop' b'qrstuvwxyz')]]]]]""") - self.assertEqual(pprint.pformat([[[[[special]]]]], width=50), """\ + self.assertEqual(_pformat([[[[[special]]]]], width=50), """\ [[[[[bytearray(b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07' b'\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f')]]]]]""") def test_default_dict(self): d = collections.defaultdict(int) - self.assertEqual(pprint.pformat(d, width=1), "defaultdict(, {})") + self.assertEqual(_pformat(d, width=1), "defaultdict(, {})") words = 'the quick brown fox jumped over a lazy dog'.split() d = collections.defaultdict(int, zip(words, itertools.count())) - self.assertEqual(pprint.pformat(d), + self.assertEqual(_pformat(d), """\ defaultdict(, {'a': 6, @@ -1291,15 +1290,15 @@ def test_default_dict(self): def test_counter(self): d = collections.Counter() - self.assertEqual(pprint.pformat(d, width=1), "Counter()") + self.assertEqual(_pformat(d, width=1), "Counter()") d = collections.Counter('senselessness') - self.assertEqual(pprint.pformat(d, width=40), + self.assertEqual(_pformat(d, width=40), """\ Counter({'s': 6, 'e': 4, 'n': 2, 'l': 1})""") - self.assertEqual(pprint.pformat(d, indent=2, width=1), + self.assertEqual(_pformat(d, indent=2, width=1), """\ Counter({ 's': 6, 'e': 4, @@ -1308,11 +1307,11 @@ def test_counter(self): def test_chainmap(self): d = collections.ChainMap() - self.assertEqual(pprint.pformat(d, width=1), "ChainMap({})") + self.assertEqual(_pformat(d, width=1), "ChainMap({})") words = 'the quick brown fox jumped over a lazy dog'.split() items = list(zip(words, itertools.count())) d = collections.ChainMap(dict(items)) - self.assertEqual(pprint.pformat(d), + self.assertEqual(_pformat(d), """\ ChainMap({'a': 6, 'brown': 2, @@ -1324,7 +1323,7 @@ def test_chainmap(self): 'quick': 1, 'the': 0})""") d = collections.ChainMap(dict(items), collections.OrderedDict(items)) - self.assertEqual(pprint.pformat(d), + self.assertEqual(_pformat(d), """\ ChainMap({'a': 6, 'brown': 2, @@ -1335,16 +1334,10 @@ def test_chainmap(self): 'over': 5, 'quick': 1, 'the': 0}, - OrderedDict([('the', 0), - ('quick', 1), - ('brown', 2), - ('fox', 3), - ('jumped', 4), - ('over', 5), - ('a', 6), - ('lazy', 7), + OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), + ('jumped', 4), ('over', 5), ('a', 6), ('lazy', 7), ('dog', 8)]))""") - self.assertEqual(pprint.pformat(d.keys()), + self.assertEqual(_pformat(d.keys()), """\ KeysView(ChainMap({'a': 6, 'brown': 2, @@ -1355,16 +1348,10 @@ def test_chainmap(self): 'over': 5, 'quick': 1, 'the': 0}, - OrderedDict([('the', 0), - ('quick', 1), - ('brown', 2), - ('fox', 3), - ('jumped', 4), - ('over', 5), - ('a', 6), - ('lazy', 7), + OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), + ('jumped', 4), ('over', 5), ('a', 6), ('lazy', 7), ('dog', 8)])))""") - self.assertEqual(pprint.pformat(d.items()), + self.assertEqual(_pformat(d.items()), """\ ItemsView(ChainMap({'a': 6, 'brown': 2, @@ -1375,16 +1362,10 @@ def test_chainmap(self): 'over': 5, 'quick': 1, 'the': 0}, - OrderedDict([('the', 0), - ('quick', 1), - ('brown', 2), - ('fox', 3), - ('jumped', 4), - ('over', 5), - ('a', 6), - ('lazy', 7), + OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), + ('jumped', 4), ('over', 5), ('a', 6), ('lazy', 7), ('dog', 8)])))""") - self.assertEqual(pprint.pformat(d.values()), + self.assertEqual(_pformat(d.values()), """\ ValuesView(ChainMap({'a': 6, 'brown': 2, @@ -1395,52 +1376,34 @@ def test_chainmap(self): 'over': 5, 'quick': 1, 'the': 0}, - OrderedDict([('the', 0), - ('quick', 1), - ('brown', 2), - ('fox', 3), - ('jumped', 4), - ('over', 5), - ('a', 6), - ('lazy', 7), + OrderedDict([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), + ('jumped', 4), ('over', 5), ('a', 6), ('lazy', 7), ('dog', 8)])))""") def test_deque(self): d = collections.deque() - self.assertEqual(pprint.pformat(d, width=1), "deque([])") + self.assertEqual(_pformat(d, width=1), "deque([])") d = collections.deque(maxlen=7) - self.assertEqual(pprint.pformat(d, width=1), "deque([], maxlen=7)") + self.assertEqual(_pformat(d, width=1), "deque([], maxlen=7)") words = 'the quick brown fox jumped over a lazy dog'.split() d = collections.deque(zip(words, itertools.count())) - self.assertEqual(pprint.pformat(d), + self.assertEqual(_pformat(d), """\ -deque([('the', 0), - ('quick', 1), - ('brown', 2), - ('fox', 3), - ('jumped', 4), - ('over', 5), - ('a', 6), - ('lazy', 7), - ('dog', 8)])""") +deque([('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), ('jumped', 4), + ('over', 5), ('a', 6), ('lazy', 7), ('dog', 8)])""") d = collections.deque(zip(words, itertools.count()), maxlen=7) - self.assertEqual(pprint.pformat(d), + self.assertEqual(_pformat(d), """\ -deque([('brown', 2), - ('fox', 3), - ('jumped', 4), - ('over', 5), - ('a', 6), - ('lazy', 7), - ('dog', 8)], +deque([('brown', 2), ('fox', 3), ('jumped', 4), ('over', 5), ('a', 6), + ('lazy', 7), ('dog', 8)], maxlen=7)""") def test_user_dict(self): d = collections.UserDict() - self.assertEqual(pprint.pformat(d, width=1), "{}") + self.assertEqual(_pformat(d, width=1), "{}") words = 'the quick brown fox jumped over a lazy dog'.split() d = collections.UserDict(zip(words, itertools.count())) - self.assertEqual(pprint.pformat(d), + self.assertEqual(_pformat(d), """\ {'a': 6, 'brown': 2, @@ -1451,7 +1414,7 @@ def test_user_dict(self): 'over': 5, 'quick': 1, 'the': 0}""") - self.assertEqual(pprint.pformat(d.keys()), """\ + self.assertEqual(_pformat(d.keys()), """\ KeysView({'a': 6, 'brown': 2, 'dog': 8, @@ -1461,7 +1424,7 @@ def test_user_dict(self): 'over': 5, 'quick': 1, 'the': 0})""") - self.assertEqual(pprint.pformat(d.items()), """\ + self.assertEqual(_pformat(d.items()), """\ ItemsView({'a': 6, 'brown': 2, 'dog': 8, @@ -1471,7 +1434,7 @@ def test_user_dict(self): 'over': 5, 'quick': 1, 'the': 0})""") - self.assertEqual(pprint.pformat(d.values()), """\ + self.assertEqual(_pformat(d.values()), """\ ValuesView({'a': 6, 'brown': 2, 'dog': 8, @@ -1484,31 +1447,24 @@ def test_user_dict(self): def test_user_list(self): d = collections.UserList() - self.assertEqual(pprint.pformat(d, width=1), "[]") + self.assertEqual(_pformat(d, width=1), "[]") words = 'the quick brown fox jumped over a lazy dog'.split() d = collections.UserList(zip(words, itertools.count())) - self.assertEqual(pprint.pformat(d), + self.assertEqual(_pformat(d), """\ -[('the', 0), - ('quick', 1), - ('brown', 2), - ('fox', 3), - ('jumped', 4), - ('over', 5), - ('a', 6), - ('lazy', 7), - ('dog', 8)]""") +[('the', 0), ('quick', 1), ('brown', 2), ('fox', 3), ('jumped', 4), ('over', 5), + ('a', 6), ('lazy', 7), ('dog', 8)]""") def test_user_string(self): d = collections.UserString('') - self.assertEqual(pprint.pformat(d, width=1), "''") + self.assertEqual(_pformat(d, width=1), "''") d = collections.UserString('the quick brown fox jumped over a lazy dog') - self.assertEqual(pprint.pformat(d, width=20), + self.assertEqual(_pformat(d, width=20), """\ ('the quick brown ' 'fox jumped over ' 'a lazy dog')""") - self.assertEqual(pprint.pformat({1: d}, width=20), + self.assertEqual(_pformat({1: d}, width=20), """\ {1: 'the quick ' 'brown fox ' @@ -1517,22 +1473,22 @@ def test_user_string(self): def test_template(self): d = t"" - self.assertEqual(pprint.pformat(d), + self.assertEqual(_pformat(d), "Template(strings=('',), interpolations=())") - self.assertEqual(pprint.pformat(d), repr(d)) - self.assertEqual(pprint.pformat(d, width=1), + self.assertEqual(_pformat(d), repr(d)) + self.assertEqual(_pformat(d, width=1), """\ Template(strings=('',), interpolations=())""") name = "World" d = t"Hello {name}" - self.assertEqual(pprint.pformat(d), + self.assertEqual(_pformat(d), """\ Template(strings=('Hello ', ''), interpolations=(Interpolation('World', 'name', None, ''),))""") ver = {3.13: False, 3.14: True} d = t"Hello { {"name": "Python", "version": ver}!s:z}!" - self.assertEqual(pprint.pformat(d, width=1), + self.assertEqual(_pformat(d, width=1), """\ Template(strings=('Hello ', '!'), @@ -1550,13 +1506,13 @@ def test_template(self): def test_expand_template(self): d = t"" self.assertEqual( - pprint.pformat(d, expand=True), + pprint.pformat(d), "Template(strings=('',), interpolations=())", ) name = "World" d = t"Hello {name}" self.assertEqual( - pprint.pformat(d, width=40, indent=4, expand=True), + pprint.pformat(d, width=40, indent=4), """\ Template( strings=('Hello ', ''), @@ -1573,7 +1529,7 @@ def test_expand_template(self): ver = {3.13: False, 3.14: True} d = t"Hello { {"name": "Python", "version": ver}!s:z}!" self.assertEqual( - pprint.pformat(d, width=40, indent=4, expand=True), + pprint.pformat(d, width=40, indent=4), """\ Template( strings=('Hello ', '!'), @@ -1614,8 +1570,7 @@ class DummyDataclass: corge=7, garply=(1, 2, 3, 4), ) - self.assertEqual(pprint.pformat(dummy_dataclass, width=40, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_dataclass, width=40, indent=4), """\ DummyDataclass( foo='foo', @@ -1635,8 +1590,7 @@ def test_expand_dict(self): "quux": ["foo", "bar", "baz"], "corge": 7, } - self.assertEqual(pprint.pformat(dummy_dict, width=40, indent=4, - expand=True, sort_dicts=False), + self.assertEqual(pprint.pformat(dummy_dict, width=40, indent=4, sort_dicts=False), """\ { 'foo': 'bar', @@ -1654,8 +1608,7 @@ def test_expand_ordered_dict(self): ("baz", 123), ] ) - self.assertEqual(pprint.pformat(dummy_ordered_dict, width=20, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_ordered_dict, width=20, indent=4), """\ OrderedDict([ ('foo', 1), @@ -1670,8 +1623,7 @@ def test_expand_list(self): "baz", "qux", ] - self.assertEqual(pprint.pformat(dummy_list, width=20, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_list, width=20, indent=4), """\ [ 'foo', @@ -1689,8 +1641,7 @@ def test_expand_tuple(self): 5, 6, ) - self.assertEqual(pprint.pformat(dummy_tuple, width=20, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_tuple, width=20, indent=4), """\ ( 'foo', @@ -1703,7 +1654,7 @@ def test_expand_tuple(self): def test_expand_single_element_tuple(self): self.assertEqual( - pprint.pformat((1,), width=1, indent=4, expand=True), + pprint.pformat((1,), width=1, indent=4), """\ ( 1, @@ -1717,8 +1668,7 @@ def test_expand_set(self): "qux", (1, 2, 3), } - self.assertEqual(pprint.pformat(dummy_set, width=20, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_set, width=20, indent=4), """\ { 'bar', @@ -1741,8 +1691,7 @@ def test_expand_frozenset(self): frozenset(dummy_set), } ) - self.assertEqual(pprint.pformat(dummy_frozenset, width=40, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_frozenset, width=40, indent=4), """\ frozenset({ frozenset({(1, 2, 3)}), @@ -1757,7 +1706,7 @@ def test_expand_frozendict(self): {"foo": "bar", "baz": 123, "qux": [1, 2]} ) self.assertEqual( - pprint.pformat(dummy_frozendict, width=20, indent=4, expand=True), + pprint.pformat(dummy_frozendict, width=20, indent=4), """\ frozendict({ 'baz': 123, @@ -1768,8 +1717,7 @@ def test_expand_frozendict(self): def test_expand_bytes(self): dummy_bytes = b"Hello world! foo bar baz 123 456 789" - self.assertEqual(pprint.pformat(dummy_bytes, width=20, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_bytes, width=20, indent=4), """\ ( b'Hello world!' @@ -1780,8 +1728,7 @@ def test_expand_bytes(self): def test_expand_bytearray(self): dummy_bytes = b"Hello world! foo bar baz 123 456 789" dummy_byte_array = bytearray(dummy_bytes) - self.assertEqual(pprint.pformat(dummy_byte_array, width=40, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_byte_array, width=40, indent=4), """\ bytearray( b'Hello world! foo bar baz 123 456' @@ -1797,8 +1744,7 @@ def test_expand_mappingproxy(self): "corge": 7, } dummy_mappingproxy = types.MappingProxyType(dummy_dict) - self.assertEqual(pprint.pformat(dummy_mappingproxy, width=40, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_mappingproxy, width=40, indent=4), """\ mappingproxy({ 'baz': 123, @@ -1819,8 +1765,7 @@ def test_expand_namespace(self): ), ) - self.assertEqual(pprint.pformat(dummy_namespace, width=40, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_namespace, width=40, indent=4), """\ namespace( foo='bar', @@ -1838,8 +1783,7 @@ def test_expand_defaultdict(self): dummy_defaultdict["foo"].append("baz") dummy_defaultdict["foo"].append("qux") dummy_defaultdict["bar"] = {"foo": "bar", "baz": None} - self.assertEqual(pprint.pformat(dummy_defaultdict, width=40, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_defaultdict, width=40, indent=4), """\ defaultdict(, { 'bar': {'baz': None, 'foo': 'bar'}, @@ -1856,8 +1800,7 @@ def test_expand_counter(self): 'd': 2, 'e': 1, })""" - self.assertEqual(pprint.pformat(dummy_counter, width=40, indent=4, - expand=True), expected) + self.assertEqual(pprint.pformat(dummy_counter, width=40, indent=4), expected) expected2 = """\ Counter({ @@ -1867,8 +1810,7 @@ def test_expand_counter(self): 'd': 2, 'e': 1, })""" - self.assertEqual(pprint.pformat(dummy_counter, width=20, indent=2, - expand=True), expected2) + self.assertEqual(pprint.pformat(dummy_counter, width=20, indent=2), expected2) def test_expand_chainmap(self): dummy_dict = { @@ -1884,8 +1826,7 @@ def test_expand_chainmap(self): {"corge": dummy_dict}, ) dummy_chainmap.maps.append({"garply": "waldo"}) - self.assertEqual(pprint.pformat(dummy_chainmap, width=40, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_chainmap, width=40, indent=4), """\ ChainMap( {'foo': 'bar'}, @@ -1927,8 +1868,7 @@ def test_expand_deque(self): dummy_deque.append(dummy_dict) dummy_deque.extend(dummy_list) dummy_deque.appendleft(dummy_set) - self.assertEqual(pprint.pformat(dummy_deque, width=40, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_deque, width=40, indent=4), """\ deque([ {(1, 2, 3)}, @@ -1959,8 +1899,7 @@ def __init__(self, *args, **kwargs): "corge": 7 }) dummy_userdict.access_count = 5 - self.assertEqual(pprint.pformat(dummy_userdict, width=40, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_userdict, width=40, indent=4), """\ { 'baz': 123, @@ -1980,8 +1919,7 @@ def __init__(self, *args, **kwargs): dummy_userlist = DummyUserList(["first", 2, {"key": "value"}, [4, 5, 6]]) - self.assertEqual(pprint.pformat(dummy_userlist, width=40, indent=4, - expand=True), + self.assertEqual(pprint.pformat(dummy_userlist, width=40, indent=4), """\ [ 'first', @@ -1993,7 +1931,7 @@ def __init__(self, *args, **kwargs): def test_expand_dict_keys(self): d = {"foo": 1, "bar": 2, "baz": 3, "qux": 4, "quux": 5} self.assertEqual( - pprint.pformat(d.keys(), width=20, indent=4, expand=True), + pprint.pformat(d.keys(), width=20, indent=4), """\ dict_keys([ 'bar', @@ -2007,7 +1945,7 @@ def test_expand_dict_keys(self): def test_expand_dict_values(self): d = {"foo": 1, "bar": 2, "baz": 3, "qux": 4, "quux": 5} self.assertEqual( - pprint.pformat(d.values(), width=20, indent=4, expand=True), + pprint.pformat(d.values(), width=20, indent=4), """\ dict_values([ 1, @@ -2021,7 +1959,7 @@ def test_expand_dict_values(self): def test_expand_dict_items(self): d = {"foo": 1, "bar": 2, "baz": 3, "qux": 4, "quux": 5} self.assertEqual( - pprint.pformat(d.items(), width=20, indent=4, expand=True), + pprint.pformat(d.items(), width=20, indent=4), """\ dict_items([ ('bar', 2), @@ -2035,7 +1973,7 @@ def test_expand_dict_items(self): def test_expand_str(self): s = "The quick brown fox jumped over the lazy dog " * 3 self.assertEqual( - pprint.pformat(s, width=40, indent=4, expand=True), + pprint.pformat(s, width=40, indent=4), """\ ( 'The quick brown fox jumped over ' diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index ed0868e0017fce..33af75ccf5682b 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -1017,15 +1017,19 @@ def test_windows_feature_macros(self): 'PyOS_CheckStack', ) -EXPECTED_FEATURE_MACROS = set(['HAVE_FORK', - 'MS_WINDOWS', - 'PY_HAVE_THREAD_NATIVE_ID', - 'Py_REF_DEBUG', - 'Py_TRACE_REFS', - 'USE_STACKCHECK']) -WINDOWS_FEATURE_MACROS = {'HAVE_FORK': False, - 'MS_WINDOWS': True, - 'PY_HAVE_THREAD_NATIVE_ID': True, - 'Py_REF_DEBUG': 'maybe', - 'Py_TRACE_REFS': 'maybe', - 'USE_STACKCHECK': 'maybe'} +EXPECTED_FEATURE_MACROS = set([ + 'HAVE_FORK', + 'MS_WINDOWS', + 'PY_HAVE_THREAD_NATIVE_ID', + 'Py_REF_DEBUG', + 'Py_TRACE_REFS', + 'USE_STACKCHECK', +]) +WINDOWS_FEATURE_MACROS = { + 'HAVE_FORK': False, + 'MS_WINDOWS': True, + 'PY_HAVE_THREAD_NATIVE_ID': True, + 'Py_REF_DEBUG': 'maybe', + 'Py_TRACE_REFS': 'maybe', + 'USE_STACKCHECK': 'maybe', +} diff --git a/Lib/test/test_unittest/testmock/testhelpers.py b/Lib/test/test_unittest/testmock/testhelpers.py index 0e82c723ec3eaa..f8643552011f4e 100644 --- a/Lib/test/test_unittest/testmock/testhelpers.py +++ b/Lib/test/test_unittest/testmock/testhelpers.py @@ -1162,9 +1162,7 @@ def test_call_list_str(self): mock.foo.bar().baz('fish', cat='dog') expected = ( - "[call(1, 2),\n" - " call.foo(a=3),\n" - " call.foo.bar(),\n" + "[call(1, 2), call.foo(a=3), call.foo.bar()," " call.foo.bar().baz('fish', cat='dog')]" ) self.assertEqual(str(mock.mock_calls), expected) diff --git a/Misc/NEWS.d/next/Library/2026-04-30-18-56-23.gh-issue-149189.mszW10.rst b/Misc/NEWS.d/next/Library/2026-04-30-18-56-23.gh-issue-149189.mszW10.rst new file mode 100644 index 00000000000000..1fd7f76bb25c09 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-30-18-56-23.gh-issue-149189.mszW10.rst @@ -0,0 +1,7 @@ +:mod:`pprint` now uses modern defaults: ``indent=4`` and ``width=88``, +and the default ``compact=False`` output is now formatted similar to +pretty-printed :func:`json.dumps`, with opening parentheses and brackets +followed by a newline and the contents indented by one level. The +*expand* parameter, added in 3.15.0a8, has been removed; ``compact=False`` +(the default) now produces the former ``expand=True`` layout. +Patch by Hugo van Kemenade.