diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2015-02-20 21:47:09 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2015-02-20 21:47:09 (GMT) |
commit | 7065f376e08bce1657904d3b2acb9989949f3efc (patch) | |
tree | 2e2faf88ac5e8d5298a0739ae4bc3fce12e731cd /Lib | |
parent | 78a82491277bc4ed3058757857abffd6119aea8e (diff) | |
parent | 5e3d7a401d8568d3308b8928b146a9c306bc3ca8 (diff) | |
download | cpython-7065f376e08bce1657904d3b2acb9989949f3efc.zip cpython-7065f376e08bce1657904d3b2acb9989949f3efc.tar.gz cpython-7065f376e08bce1657904d3b2acb9989949f3efc.tar.bz2 |
Issue #23374: Fixed pydoc failure with non-ASCII files when stdout encoding
differs from file system encoding (e.g. on Mac OS).
Diffstat (limited to 'Lib')
-rwxr-xr-x | Lib/pydoc.py | 22 | ||||
-rw-r--r-- | Lib/test/test_pydoc.py | 9 |
2 files changed, 22 insertions, 9 deletions
diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 1fc8cc7..b762389 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1405,9 +1405,6 @@ class _PlainTextDoc(TextDoc): def pager(text): """The first time this is called, determine what kind of pager to use.""" global pager - # Escape non-encodable characters to avoid encoding errors later - encoding = sys.getfilesystemencoding() - text = text.encode(encoding, 'backslashreplace').decode(encoding) pager = getpager() pager(text) @@ -1450,10 +1447,12 @@ def plain(text): def pipepager(text, cmd): """Page through text by feeding it to another program.""" - pipe = os.popen(cmd, 'w') + import subprocess + proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE) try: - pipe.write(text) - pipe.close() + with proc: + with io.TextIOWrapper(proc.stdin, errors='backslashreplace') as pipe: + pipe.write(text) except OSError: pass # Ignore broken pipes caused by quitting the pager program. @@ -1461,16 +1460,21 @@ def tempfilepager(text, cmd): """Page through text by invoking a program on a temporary file.""" import tempfile filename = tempfile.mktemp() - with open(filename, 'w') as file: + with open(filename, 'w', errors='backslashreplace') as file: file.write(text) try: os.system(cmd + ' "' + filename + '"') finally: os.unlink(filename) +def _escape_stdout(text): + # Escape non-encodable characters to avoid encoding errors later + encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8' + return text.encode(encoding, 'backslashreplace').decode(encoding) + def ttypager(text): """Page through text on a text terminal.""" - lines = plain(text).split('\n') + lines = plain(_escape_stdout(text)).split('\n') try: import tty fd = sys.stdin.fileno() @@ -1514,7 +1518,7 @@ def ttypager(text): def plainpager(text): """Simply print unformatted text. This is the ultimate fallback.""" - sys.stdout.write(plain(text)) + sys.stdout.write(plain(_escape_stdout(text))) def describe(thing): """Produce a short description of the given thing.""" diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index 41ad792..e9fed0a 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -34,6 +34,10 @@ try: except ImportError: threading = None +class nonascii: + 'Це не латиниця' + pass + if test.support.HAVE_DOCSTRINGS: expected_data_docstrings = ( 'dictionary for instance variables (if defined)', @@ -460,6 +464,11 @@ class PydocDocTest(unittest.TestCase): self.assertEqual(expected, result, "documentation for missing module found") + def test_not_ascii(self): + result = run_pydoc('test.test_pydoc.nonascii', PYTHONIOENCODING='ascii') + encoded = nonascii.__doc__.encode('ascii', 'backslashreplace') + self.assertIn(encoded, result) + def test_input_strip(self): missing_module = " test.i_am_not_here " result = str(run_pydoc(missing_module), 'ascii') |