importlib.abc.SourceLoader.get_source() was re-raising SyntaxError and

UnicodeDecodeError as ImportError. That was over-reaching the point of
raising ImportError in get_source() (which is to signal the source
code was not found when it should have). Conflating the two exceptions
with ImportError could lead to masking errors with the source which
should be known outside of whether there was an error simply getting
the source to begin with.
This commit is contained in:
Brett Cannon 2013-06-16 18:05:54 -04:00
parent 01b0475b08
commit f4375ef4d4
4 changed files with 1722 additions and 1734 deletions

View file

@ -282,3 +282,12 @@ that may require changes to your code.
it would write to is a symlink or a non-regular file. This is to act as a it would write to is a symlink or a non-regular file. This is to act as a
warning that import will overwrite those files with a regular file regardless warning that import will overwrite those files with a regular file regardless
of what type of file path they were originally. of what type of file path they were originally.
* :meth:`importlib.abc.SourceLoader.get_source` no longer raises
:exc:`ImportError` when the source code being loaded triggers a
:exc:`SyntaxError` or :exc:`UnicodeDecodeError`. As :exc:`ImportError` is
meant to be raised only when source code cannot be found but it should, it was
felt to be over-reaching/overloading of that meaning when the source code is
found but improperly structured. If you were catching ImportError before and
wish to continue to ignore syntax or decoding issues, catch all three
exceptions now.

View file

@ -959,25 +959,17 @@ class SourceLoader(_LoaderBasics):
def get_source(self, fullname): def get_source(self, fullname):
"""Concrete implementation of InspectLoader.get_source.""" """Concrete implementation of InspectLoader.get_source."""
import tokenize
path = self.get_filename(fullname) path = self.get_filename(fullname)
try: try:
source_bytes = self.get_data(path) source_bytes = self.get_data(path)
except OSError as exc: except OSError as exc:
raise ImportError("source not available through get_data()", raise ImportError("source not available through get_data()",
name=fullname) from exc name=fullname) from exc
import tokenize
readsource = _io.BytesIO(source_bytes).readline readsource = _io.BytesIO(source_bytes).readline
try: encoding = tokenize.detect_encoding(readsource)
encoding = tokenize.detect_encoding(readsource)
except SyntaxError as exc:
raise ImportError("Failed to detect encoding",
name=fullname) from exc
newline_decoder = _io.IncrementalNewlineDecoder(None, True) newline_decoder = _io.IncrementalNewlineDecoder(None, True)
try: return newline_decoder.decode(source_bytes.decode(encoding[0]))
return newline_decoder.decode(source_bytes.decode(encoding[0]))
except UnicodeDecodeError as exc:
raise ImportError("Failed to decode source file",
name=fullname) from exc
def source_to_code(self, data, path, *, _optimize=-1): def source_to_code(self, data, path, *, _optimize=-1):
"""Return the code object compiled from source. """Return the code object compiled from source.

View file

@ -123,6 +123,9 @@ Core and Builtins
Library Library
------- -------
- importlib.abc.SourceLoader.get_source() no longer changes SyntaxError or
UnicodeDecodeError into ImportError.
- Issue #18058, 18057: Make the namespace package loader meet the - Issue #18058, 18057: Make the namespace package loader meet the
importlib.abc.InspectLoader ABC, allowing for namespace packages to work with importlib.abc.InspectLoader ABC, allowing for namespace packages to work with
runpy. runpy.

File diff suppressed because it is too large Load diff