diff -r ab6f520f3637 Lib/pydoc.py
--- a/Lib/pydoc.py Mon Sep 21 01:11:26 2015 -0400
+++ b/Lib/pydoc.py Mon Sep 21 16:21:35 2015 +0300
@@ -660,7 +660,11 @@ class HTMLDoc(Doc):
head = '%s' % linkedname
try:
path = inspect.getabsfile(object)
- url = urllib.parse.quote(path)
+ encodedpath = os.fsencode(path)
+ if os.fsdecode(encodedpath) == path:
+ url = urllib.parse.quote_from_bytes(encodedpath)
+ else:
+ url = urllib.parse.quote(path, errors='surrogatepass')
filelink = self.filelink(url, path)
except TypeError:
filelink = '(built-in)'
diff -r ab6f520f3637 Lib/test/test_pydoc.py
--- a/Lib/test/test_pydoc.py Mon Sep 21 01:11:26 2015 -0400
+++ b/Lib/test/test_pydoc.py Mon Sep 21 16:21:35 2015 +0300
@@ -10,6 +10,7 @@ import keyword
import _pickle
import pkgutil
import re
+import shutil
import stat
import string
import test.support
@@ -23,9 +24,9 @@ from io import StringIO
from collections import namedtuple
from test.support.script_helper import assert_python_ok
from test.support import (
- TESTFN, rmtree,
+ TESTFN, TESTFN_UNDECODABLE, TESTFN_UNENCODABLE, rmtree,
reap_children, reap_threads, captured_output, captured_stdout,
- captured_stderr, unlink, requires_docstrings
+ captured_stderr, unlink, requires_docstrings, temp_dir, swap_item
)
from test import pydoc_mod
@@ -347,7 +348,7 @@ def get_pydoc_html(module):
"Returns pydoc generated output as html"
doc = pydoc.HTMLDoc()
output = doc.docmodule(module)
- loc = doc.getdocloc(pydoc_mod) or ""
+ loc = doc.getdocloc(module) or ""
if loc:
loc = "
Module Docs"
return output.strip(), loc
@@ -355,7 +356,7 @@ def get_pydoc_html(module):
def get_pydoc_text(module):
"Returns pydoc generated output as text"
doc = pydoc.TextDoc()
- loc = doc.getdocloc(pydoc_mod) or ""
+ loc = doc.getdocloc(module) or ""
if loc:
loc = "\nMODULE DOCS\n " + loc + "\n"
@@ -413,6 +414,59 @@ class PydocDocTest(unittest.TestCase):
expected_html_data_docstrings)
self.assertEqual(result, expected_html)
+ def load_mod(self, name, path):
+ loader = importlib._bootstrap_external.SourceFileLoader(name, path)
+ spec = importlib.util.spec_from_file_location(name, path, loader=loader)
+ return importlib._bootstrap._load(spec)
+
+ @unittest.skipUnless(TESTFN_UNDECODABLE,
+ "needed undecodable filename")
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
+ @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
+ 'trace function introduces __locals__ unexpectedly')
+ @requires_docstrings
+ def test_html_doc_undecodable_path(self):
+ with swap_item(sys.modules, pydoc_mod.__name__, None), \
+ temp_dir(TESTFN_UNDECODABLE):
+ path = os.path.join(TESTFN_UNDECODABLE, b'pydoc_mod.py')
+ shutil.copyfile(pydoc_mod.__file__, path)
+ path = os.path.abspath(os.fsdecode(path))
+ mod = self.load_mod(pydoc_mod.__name__, path)
+ result, doc_loc = get_pydoc_html(mod)
+ mod_file = inspect.getabsfile(mod)
+ mod_url = urllib.parse.quote_from_bytes(os.fsencode(mod_file))
+ expected_html = expected_html_pattern % (
+ (mod_url, mod_file, doc_loc) +
+ expected_html_data_docstrings)
+ self.assertEqual(result, expected_html)
+
+ @unittest.skipUnless(TESTFN_UNENCODABLE,
+ "needed unencodable filename")
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
+ @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
+ 'trace function introduces __locals__ unexpectedly')
+ @requires_docstrings
+ def test_html_doc_unencodable_path(self):
+ with swap_item(sys.modules, pydoc_mod.__name__, None), \
+ temp_dir(TESTFN_UNENCODABLE):
+ path = os.path.join(TESTFN_UNENCODABLE, 'pydoc_mod.py')
+ shutil.copyfile(pydoc_mod.__file__, path)
+ path = os.path.abspath(path)
+ mod = self.load_mod(pydoc_mod.__name__, path)
+ result, doc_loc = get_pydoc_html(mod)
+ mod_file = inspect.getabsfile(mod)
+ encodedpath = os.fsencode(mod_file)
+ if os.fsdecode(encodedpath) == mod_file:
+ mod_url = urllib.parse.quote_from_bytes(encodedpath)
+ else:
+ mod_url = urllib.parse.quote(mod_file, errors='surrogatepass')
+ expected_html = expected_html_pattern % (
+ (mod_url, mod_file, doc_loc) +
+ expected_html_data_docstrings)
+ self.assertEqual(result, expected_html)
+
@unittest.skipIf(sys.flags.optimize >= 2,
"Docstrings are omitted with -O2 and above")
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
@@ -425,6 +479,7 @@ class PydocDocTest(unittest.TestCase):
expected_text_data_docstrings +
(inspect.getabsfile(pydoc_mod),))
self.assertEqual(expected_text, result)
+ maxDiff=99990
def test_text_enum_member_with_value_zero(self):
# Test issue #20654 to ensure enum member with value 0 can be