bpo-40260: Update modulefinder to use io.open_code() and respect coding comments (GH-19488)

This commit is contained in:
Barry 2020-04-14 20:16:06 +01:00 committed by GitHub
parent aade1cc453
commit d42e582063
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 75 additions and 21 deletions

View File

@ -5,6 +5,7 @@ import importlib._bootstrap_external
import importlib.machinery import importlib.machinery
import marshal import marshal
import os import os
import io
import sys import sys
import types import types
import warnings import warnings
@ -68,35 +69,32 @@ def _find_module(name, path=None):
# Some special cases: # Some special cases:
if spec.loader is importlib.machinery.BuiltinImporter: if spec.loader is importlib.machinery.BuiltinImporter:
return None, None, ("", "", _C_BUILTIN) return None, None, ("", _C_BUILTIN)
if spec.loader is importlib.machinery.FrozenImporter: if spec.loader is importlib.machinery.FrozenImporter:
return None, None, ("", "", _PY_FROZEN) return None, None, ("", _PY_FROZEN)
file_path = spec.origin file_path = spec.origin
if spec.loader.is_package(name): if spec.loader.is_package(name):
return None, os.path.dirname(file_path), ("", "", _PKG_DIRECTORY) return None, os.path.dirname(file_path), ("", _PKG_DIRECTORY)
if isinstance(spec.loader, importlib.machinery.SourceFileLoader): if isinstance(spec.loader, importlib.machinery.SourceFileLoader):
kind = _PY_SOURCE kind = _PY_SOURCE
mode = "r"
elif isinstance(spec.loader, importlib.machinery.ExtensionFileLoader): elif isinstance(spec.loader, importlib.machinery.ExtensionFileLoader):
kind = _C_EXTENSION kind = _C_EXTENSION
mode = "rb"
elif isinstance(spec.loader, importlib.machinery.SourcelessFileLoader): elif isinstance(spec.loader, importlib.machinery.SourcelessFileLoader):
kind = _PY_COMPILED kind = _PY_COMPILED
mode = "rb"
else: # Should never happen. else: # Should never happen.
return None, None, ("", "", _SEARCH_ERROR) return None, None, ("", _SEARCH_ERROR)
file = open(file_path, mode) file = io.open_code(file_path)
suffix = os.path.splitext(file_path)[-1] suffix = os.path.splitext(file_path)[-1]
return file, file_path, (suffix, mode, kind) return file, file_path, (suffix, kind)
class Module: class Module:
@ -160,15 +158,15 @@ class ModuleFinder:
def run_script(self, pathname): def run_script(self, pathname):
self.msg(2, "run_script", pathname) self.msg(2, "run_script", pathname)
with open(pathname) as fp: with io.open_code(pathname) as fp:
stuff = ("", "r", _PY_SOURCE) stuff = ("", _PY_SOURCE)
self.load_module('__main__', fp, pathname, stuff) self.load_module('__main__', fp, pathname, stuff)
def load_file(self, pathname): def load_file(self, pathname):
dir, name = os.path.split(pathname) dir, name = os.path.split(pathname)
name, ext = os.path.splitext(name) name, ext = os.path.splitext(name)
with open(pathname) as fp: with io.open_code(pathname) as fp:
stuff = (ext, "r", _PY_SOURCE) stuff = (ext, _PY_SOURCE)
self.load_module(name, fp, pathname, stuff) self.load_module(name, fp, pathname, stuff)
def import_hook(self, name, caller=None, fromlist=None, level=-1): def import_hook(self, name, caller=None, fromlist=None, level=-1):
@ -333,14 +331,14 @@ class ModuleFinder:
return m return m
def load_module(self, fqname, fp, pathname, file_info): def load_module(self, fqname, fp, pathname, file_info):
suffix, mode, type = file_info suffix, type = file_info
self.msgin(2, "load_module", fqname, fp and "fp", pathname) self.msgin(2, "load_module", fqname, fp and "fp", pathname)
if type == _PKG_DIRECTORY: if type == _PKG_DIRECTORY:
m = self.load_package(fqname, pathname) m = self.load_package(fqname, pathname)
self.msgout(2, "load_module ->", m) self.msgout(2, "load_module ->", m)
return m return m
if type == _PY_SOURCE: if type == _PY_SOURCE:
co = compile(fp.read()+'\n', pathname, 'exec') co = compile(fp.read()+b'\n', pathname, 'exec')
elif type == _PY_COMPILED: elif type == _PY_COMPILED:
try: try:
data = fp.read() data = fp.read()
@ -504,7 +502,7 @@ class ModuleFinder:
if path is None: if path is None:
if name in sys.builtin_module_names: if name in sys.builtin_module_names:
return (None, None, ("", "", _C_BUILTIN)) return (None, None, ("", _C_BUILTIN))
path = self.path path = self.path

View File

@ -40,7 +40,8 @@ a/module.py
from c import something from c import something
b/__init__.py b/__init__.py
from sys import * from sys import *
"""] """,
]
maybe_test_new = [ maybe_test_new = [
"a.module", "a.module",
@ -245,6 +246,48 @@ b/__init__.py
b/c.py b/c.py
"""] """]
coding_default_utf8_test = [
"a_utf8",
["a_utf8", "b_utf8"],
[], [],
"""\
a_utf8.py
# use the default of utf8
print('Unicode test A code point 2090 \u2090 that is not valid in cp1252')
import b_utf8
b_utf8.py
# use the default of utf8
print('Unicode test B code point 2090 \u2090 that is not valid in cp1252')
"""]
coding_explicit_utf8_test = [
"a_utf8",
["a_utf8", "b_utf8"],
[], [],
"""\
a_utf8.py
# coding=utf8
print('Unicode test A code point 2090 \u2090 that is not valid in cp1252')
import b_utf8
b_utf8.py
# use the default of utf8
print('Unicode test B code point 2090 \u2090 that is not valid in cp1252')
"""]
coding_explicit_cp1252_test = [
"a_cp1252",
["a_cp1252", "b_utf8"],
[], [],
b"""\
a_cp1252.py
# coding=cp1252
# 0xe2 is not allowed in utf8
print('CP1252 test P\xe2t\xe9')
import b_utf8
b_utf8.py
# use the default of utf8
print('Unicode test A code point 2090 \u2090 that is not valid in cp1252')
"""]
def open_file(path): def open_file(path):
dirname = os.path.dirname(path) dirname = os.path.dirname(path)
@ -253,18 +296,22 @@ def open_file(path):
except OSError as e: except OSError as e:
if e.errno != errno.EEXIST: if e.errno != errno.EEXIST:
raise raise
return open(path, "w") return open(path, 'wb')
def create_package(source): def create_package(source):
ofi = None ofi = None
try: try:
for line in source.splitlines(): for line in source.splitlines():
if line.startswith(" ") or line.startswith("\t"): if type(line) != bytes:
ofi.write(line.strip() + "\n") line = line.encode('utf-8')
if line.startswith(b' ') or line.startswith(b'\t'):
ofi.write(line.strip() + b'\n')
else: else:
if ofi: if ofi:
ofi.close() ofi.close()
if type(line) == bytes:
line = line.decode('utf-8')
ofi = open_file(os.path.join(TEST_DIR, line.strip())) ofi = open_file(os.path.join(TEST_DIR, line.strip()))
finally: finally:
if ofi: if ofi:
@ -337,7 +384,7 @@ class ModuleFinderTest(unittest.TestCase):
source_path = base_path + importlib.machinery.SOURCE_SUFFIXES[0] source_path = base_path + importlib.machinery.SOURCE_SUFFIXES[0]
bytecode_path = base_path + importlib.machinery.BYTECODE_SUFFIXES[0] bytecode_path = base_path + importlib.machinery.BYTECODE_SUFFIXES[0]
with open_file(source_path) as file: with open_file(source_path) as file:
file.write('testing_modulefinder = True\n') file.write('testing_modulefinder = True\n'.encode('utf-8'))
py_compile.compile(source_path, cfile=bytecode_path) py_compile.compile(source_path, cfile=bytecode_path)
os.remove(source_path) os.remove(source_path)
self._do_test(bytecode_test) self._do_test(bytecode_test)
@ -365,6 +412,14 @@ b.py
""" % list(range(2**16))] # 2**16 constants """ % list(range(2**16))] # 2**16 constants
self._do_test(extended_opargs_test) self._do_test(extended_opargs_test)
def test_coding_default_utf8(self):
self._do_test(coding_default_utf8_test)
def test_coding_explicit_utf8(self):
self._do_test(coding_explicit_utf8_test)
def test_coding_explicit_cp1252(self):
self._do_test(coding_explicit_cp1252_test)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -0,0 +1 @@
Ensure :mod:`modulefinder` uses :func:`io.open_code` and respects coding comments.