| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent abf7a18 commit c8ca336
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -71,7 +71,6 @@ class or function within a module or module in a package. If the | |||
| 71 | 71 | import textwrap | |
| 72 | 72 | import time | |
| 73 | 73 | import tokenize | |
| 74 | - import urllib.parse | ||
| 75 | 74 | import warnings | |
| 76 | 75 | from annotationlib import Format | |
| 77 | 76 | from collections import deque | |
@@ -795,7 +794,8 @@ def docmodule(self, object, name=None, mod=None, *ignored): | |||
| 795 | 794 | head = linkedname | |
| 796 | 795 | try: | |
| 797 | 796 | path = inspect.getabsfile(object) | |
| 798 | - url = urllib.parse.quote(path) | ||
| 797 | + import urllib.request | ||
| 798 | + url = urllib.request.pathname2url(path) | ||
| 799 | 799 | filelink = self.filelink(url, path) | |
| 800 | 800 | except TypeError: | |
| 801 | 801 | filelink = '(built-in)' | |
@@ -1790,7 +1790,8 @@ def writedoc(thing, forceload=0): | |||
| 1790 | 1790 | """Write HTML documentation to a file in the current directory.""" | |
| 1791 | 1791 | object, name = resolve(thing, forceload) | |
| 1792 | 1792 | page = html.page(describe(object), html.document(object, name)) | |
| 1793 | - with open(name + '.html', 'w', encoding='utf-8') as file: | ||
| 1793 | + with open(name + '.html', 'w', encoding='utf-8', | ||
| 1794 | + errors='backslashreplace') as file: | ||
| 1794 | 1795 | file.write(page) | |
| 1795 | 1796 | print('wrote', name + '.html') | |
| 1796 | 1797 | ||
@@ -2387,7 +2388,7 @@ def do_GET(self): | |||
| 2387 | 2388 | self.send_header('Content-Type', '%s; charset=UTF-8' % content_type) | |
| 2388 | 2389 | self.end_headers() | |
| 2389 | 2390 | self.wfile.write(self.urlhandler( | |
| 2390 | - self.path, content_type).encode('utf-8')) | ||
| 2391 | + self.path, content_type).encode('utf-8', 'backslashreplace')) | ||
| 2391 | 2392 | ||
| 2392 | 2393 | def log_message(self, *args): | |
| 2393 | 2394 | # Don't log messages. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,6 +19,7 @@ | |||
| 19 | 19 | import unittest | |
| 20 | 20 | import unittest.mock | |
| 21 | 21 | import urllib.parse | |
| 22 | + import urllib.request | ||
| 22 | 23 | import xml.etree | |
| 23 | 24 | import xml.etree.ElementTree | |
| 24 | 25 | import textwrap | |
@@ -429,7 +430,7 @@ def test_html_doc(self): | |||
| 429 | 430 | expected_lines = [line.strip() for line in expected_lines if line] | |
| 430 | 431 | self.assertEqual(text_lines, expected_lines) | |
| 431 | 432 | mod_file = inspect.getabsfile(pydoc_mod) | |
| 432 | - mod_url = urllib.parse.quote(mod_file) | ||
| 433 | + mod_url = urllib.request.pathname2url(mod_file) | ||
| 433 | 434 | self.assertIn(mod_url, result) | |
| 434 | 435 | self.assertIn(mod_file, result) | |
| 435 | 436 | self.assertIn(doc_loc, result) | |
@@ -1024,6 +1025,31 @@ def test_synopsis_sourceless_empty_doc(self): | |||
| 1024 | 1025 | synopsis_cached = pydoc.synopsis(cached_path, {}) | |
| 1025 | 1026 | self.assertIsNone(synopsis_cached) | |
| 1026 | 1027 | ||
| 1028 | + @unittest.skipUnless(os_helper.TESTFN_UNDECODABLE, | ||
| 1029 | + 'requires undecodable file names') | ||
| 1030 | + def test_html_doc_undecodable_path(self): | ||
| 1031 | + # gh-69371: the path of the module is not encodable in UTF-8. | ||
| 1032 | + with os_helper.temp_cwd() as test_dir: | ||
| 1033 | + subdir = os.path.join(os.fsencode(test_dir), | ||
| 1034 | + os_helper.TESTFN_UNDECODABLE) | ||
| 1035 | + try: | ||
| 1036 | + os.mkdir(subdir) | ||
| 1037 | + except OSError: | ||
| 1038 | + self.skipTest('undecodable paths are not supported') | ||
| 1039 | + with open(os.path.join(subdir, b'undecodable_mod.py'), 'w') as f: | ||
| 1040 | + f.write('"""Module docstring."""\n') | ||
| 1041 | + with import_helper.DirsOnSysPath(os.fsdecode(subdir)): | ||
| 1042 | + mod = import_helper.import_fresh_module('undecodable_mod') | ||
| 1043 | + doc = pydoc.HTMLDoc().docmodule(mod) | ||
| 1044 | + with captured_stdout(): | ||
| 1045 | + pydoc.writedoc(mod) | ||
| 1046 | + # The link contains the percent-encoded path... | ||
| 1047 | + path = inspect.getabsfile(mod) | ||
| 1048 | + self.assertIn(urllib.request.pathname2url(path), doc) | ||
| 1049 | + # ...and the page can be written and served as UTF-8. | ||
| 1050 | + with open('undecodable_mod.html', encoding='utf-8') as f: | ||
| 1051 | + self.assertIn('undecodable_mod', f.read()) | ||
| 1052 | + | ||
| 1027 | 1053 | def test_splitdoc_with_description(self): | |
| 1028 | 1054 | example_string = "I Am A Doc\n\n\nHere is my description" | |
| 1029 | 1055 | self.assertEqual(pydoc.splitdoc(example_string), | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,5 @@ | |||
| 1 | + Fix :mod:`pydoc` for modules whose path contains undecodable bytes. | ||
| 2 | + :func:`!pydoc.writedoc` and the pydoc HTTP server no longer fail with | ||
| 3 | + :exc:`UnicodeEncodeError`: the file URL is now percent-encoded using the | ||
| 4 | + filesystem encoding, and characters unencodable in the generated HTML page | ||
| 5 | + are escaped with backslashes. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments