mirror of
https://github.com/python/cpython.git
synced 2025-07-15 23:35:23 +00:00
Issue #23374: Fixed pydoc failure with non-ASCII files when stdout encoding
differs from file system encoding (e.g. on Mac OS).
This commit is contained in:
commit
7065f376e0
3 changed files with 25 additions and 9 deletions
22
Lib/pydoc.py
22
Lib/pydoc.py
|
@ -1405,9 +1405,6 @@ class _PlainTextDoc(TextDoc):
|
||||||
def pager(text):
|
def pager(text):
|
||||||
"""The first time this is called, determine what kind of pager to use."""
|
"""The first time this is called, determine what kind of pager to use."""
|
||||||
global pager
|
global pager
|
||||||
# Escape non-encodable characters to avoid encoding errors later
|
|
||||||
encoding = sys.getfilesystemencoding()
|
|
||||||
text = text.encode(encoding, 'backslashreplace').decode(encoding)
|
|
||||||
pager = getpager()
|
pager = getpager()
|
||||||
pager(text)
|
pager(text)
|
||||||
|
|
||||||
|
@ -1450,10 +1447,12 @@ def plain(text):
|
||||||
|
|
||||||
def pipepager(text, cmd):
|
def pipepager(text, cmd):
|
||||||
"""Page through text by feeding it to another program."""
|
"""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:
|
try:
|
||||||
pipe.write(text)
|
with proc:
|
||||||
pipe.close()
|
with io.TextIOWrapper(proc.stdin, errors='backslashreplace') as pipe:
|
||||||
|
pipe.write(text)
|
||||||
except OSError:
|
except OSError:
|
||||||
pass # Ignore broken pipes caused by quitting the pager program.
|
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."""
|
"""Page through text by invoking a program on a temporary file."""
|
||||||
import tempfile
|
import tempfile
|
||||||
filename = tempfile.mktemp()
|
filename = tempfile.mktemp()
|
||||||
with open(filename, 'w') as file:
|
with open(filename, 'w', errors='backslashreplace') as file:
|
||||||
file.write(text)
|
file.write(text)
|
||||||
try:
|
try:
|
||||||
os.system(cmd + ' "' + filename + '"')
|
os.system(cmd + ' "' + filename + '"')
|
||||||
finally:
|
finally:
|
||||||
os.unlink(filename)
|
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):
|
def ttypager(text):
|
||||||
"""Page through text on a text terminal."""
|
"""Page through text on a text terminal."""
|
||||||
lines = plain(text).split('\n')
|
lines = plain(_escape_stdout(text)).split('\n')
|
||||||
try:
|
try:
|
||||||
import tty
|
import tty
|
||||||
fd = sys.stdin.fileno()
|
fd = sys.stdin.fileno()
|
||||||
|
@ -1514,7 +1518,7 @@ def ttypager(text):
|
||||||
|
|
||||||
def plainpager(text):
|
def plainpager(text):
|
||||||
"""Simply print unformatted text. This is the ultimate fallback."""
|
"""Simply print unformatted text. This is the ultimate fallback."""
|
||||||
sys.stdout.write(plain(text))
|
sys.stdout.write(plain(_escape_stdout(text)))
|
||||||
|
|
||||||
def describe(thing):
|
def describe(thing):
|
||||||
"""Produce a short description of the given thing."""
|
"""Produce a short description of the given thing."""
|
||||||
|
|
|
@ -34,6 +34,10 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
threading = None
|
threading = None
|
||||||
|
|
||||||
|
class nonascii:
|
||||||
|
'Це не латиниця'
|
||||||
|
pass
|
||||||
|
|
||||||
if test.support.HAVE_DOCSTRINGS:
|
if test.support.HAVE_DOCSTRINGS:
|
||||||
expected_data_docstrings = (
|
expected_data_docstrings = (
|
||||||
'dictionary for instance variables (if defined)',
|
'dictionary for instance variables (if defined)',
|
||||||
|
@ -460,6 +464,11 @@ class PydocDocTest(unittest.TestCase):
|
||||||
self.assertEqual(expected, result,
|
self.assertEqual(expected, result,
|
||||||
"documentation for missing module found")
|
"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):
|
def test_input_strip(self):
|
||||||
missing_module = " test.i_am_not_here "
|
missing_module = " test.i_am_not_here "
|
||||||
result = str(run_pydoc(missing_module), 'ascii')
|
result = str(run_pydoc(missing_module), 'ascii')
|
||||||
|
|
|
@ -13,6 +13,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #23374: Fixed pydoc failure with non-ASCII files when stdout encoding
|
||||||
|
differs from file system encoding (e.g. on Mac OS).
|
||||||
|
|
||||||
- Issue #23481: Remove RC4 from the SSL module's default cipher list.
|
- Issue #23481: Remove RC4 from the SSL module's default cipher list.
|
||||||
|
|
||||||
- Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty
|
- Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue