mirror of https://github.com/python/cpython
Issue #15627: Add the compile_source() method to
importlib.abc.SourceLoader. This provides an easy hook into the import system to allow for source transformations, AST optimizations, etc.
This commit is contained in:
parent
195ad6ce05
commit
5650e4f41c
|
@ -364,10 +364,12 @@ ABC hierarchy::
|
||||||
* :meth:`ResourceLoader.get_data`
|
* :meth:`ResourceLoader.get_data`
|
||||||
* :meth:`ExecutionLoader.get_filename`
|
* :meth:`ExecutionLoader.get_filename`
|
||||||
Should only return the path to the source file; sourceless
|
Should only return the path to the source file; sourceless
|
||||||
loading is not supported.
|
loading is not supported (see :class:`SourcelessLoader` if that
|
||||||
|
functionality is required)
|
||||||
|
|
||||||
The abstract methods defined by this class are to add optional bytecode
|
The abstract methods defined by this class are to add optional bytecode
|
||||||
file support. Not implementing these optional methods causes the loader to
|
file support. Not implementing these optional methods (or causing them to
|
||||||
|
raise :exc:`NotImplementedError`) causes the loader to
|
||||||
only work with source code. Implementing the methods allows the loader to
|
only work with source code. Implementing the methods allows the loader to
|
||||||
work with source *and* bytecode files; it does not allow for *sourceless*
|
work with source *and* bytecode files; it does not allow for *sourceless*
|
||||||
loading where only bytecode is provided. Bytecode files are an
|
loading where only bytecode is provided. Bytecode files are an
|
||||||
|
@ -407,6 +409,17 @@ ABC hierarchy::
|
||||||
When writing to the path fails because the path is read-only
|
When writing to the path fails because the path is read-only
|
||||||
(:attr:`errno.EACCES`), do not propagate the exception.
|
(:attr:`errno.EACCES`), do not propagate the exception.
|
||||||
|
|
||||||
|
.. method:: compile_source(data, path)
|
||||||
|
|
||||||
|
Create a code object from Python source.
|
||||||
|
|
||||||
|
The *data* argument can be whatever the :func:`compile` function
|
||||||
|
supports (i.e. string or bytes). The *path* argument should be
|
||||||
|
the "path" to where the source code originated from, which can be an
|
||||||
|
abstract concept (e.g. location in a zip file).
|
||||||
|
|
||||||
|
.. versionadded:: 3.4
|
||||||
|
|
||||||
.. method:: get_code(fullname)
|
.. method:: get_code(fullname)
|
||||||
|
|
||||||
Concrete implementation of :meth:`InspectLoader.get_code`.
|
Concrete implementation of :meth:`InspectLoader.get_code`.
|
||||||
|
|
|
@ -931,6 +931,14 @@ class SourceLoader(_LoaderBasics):
|
||||||
raise ImportError("Failed to decode source file",
|
raise ImportError("Failed to decode source file",
|
||||||
name=fullname) from exc
|
name=fullname) from exc
|
||||||
|
|
||||||
|
def compile_source(self, data, path):
|
||||||
|
"""Return the code object compiled from source.
|
||||||
|
|
||||||
|
The 'data' argument can be any object type that compile() supports.
|
||||||
|
"""
|
||||||
|
return _call_with_frames_removed(compile, data, path, 'exec',
|
||||||
|
dont_inherit=True)
|
||||||
|
|
||||||
def get_code(self, fullname):
|
def get_code(self, fullname):
|
||||||
"""Concrete implementation of InspectLoader.get_code.
|
"""Concrete implementation of InspectLoader.get_code.
|
||||||
|
|
||||||
|
@ -976,9 +984,7 @@ class SourceLoader(_LoaderBasics):
|
||||||
raise ImportError(msg.format(bytecode_path),
|
raise ImportError(msg.format(bytecode_path),
|
||||||
name=fullname, path=bytecode_path)
|
name=fullname, path=bytecode_path)
|
||||||
source_bytes = self.get_data(source_path)
|
source_bytes = self.get_data(source_path)
|
||||||
code_object = _call_with_frames_removed(compile,
|
code_object = self.compile_source(source_bytes, source_path)
|
||||||
source_bytes, source_path, 'exec',
|
|
||||||
dont_inherit=True)
|
|
||||||
_verbose_message('code object from {}', source_path)
|
_verbose_message('code object from {}', source_path)
|
||||||
if (not sys.dont_write_bytecode and bytecode_path is not None and
|
if (not sys.dont_write_bytecode and bytecode_path is not None and
|
||||||
source_mtime is not None):
|
source_mtime is not None):
|
||||||
|
|
|
@ -148,6 +148,11 @@ class SourceOnlyLoaderTests(SourceLoaderTestHarness):
|
||||||
code_object = self.loader.get_code(self.name)
|
code_object = self.loader.get_code(self.name)
|
||||||
self.verify_code(code_object)
|
self.verify_code(code_object)
|
||||||
|
|
||||||
|
def test_compile_source(self):
|
||||||
|
# Verify the compiled code object.
|
||||||
|
code = self.loader.compile_source(self.loader.source, self.path)
|
||||||
|
self.verify_code(code)
|
||||||
|
|
||||||
def test_load_module(self):
|
def test_load_module(self):
|
||||||
# Loading a module should set __name__, __loader__, __package__,
|
# Loading a module should set __name__, __loader__, __package__,
|
||||||
# __path__ (for packages), __file__, and __cached__.
|
# __path__ (for packages), __file__, and __cached__.
|
||||||
|
@ -395,9 +400,7 @@ class AbstractMethodImplTests(unittest.TestCase):
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
from test.support import run_unittest
|
from test.support import run_unittest
|
||||||
run_unittest(SkipWritingBytecodeTests, RegeneratedBytecodeTests,
|
run_unittest(SourceOnlyLoaderTests,
|
||||||
BadBytecodeFailureTests, MissingPathsTests,
|
|
||||||
SourceOnlyLoaderTests,
|
|
||||||
SourceLoaderBytecodeTests,
|
SourceLoaderBytecodeTests,
|
||||||
SourceLoaderGetSourceTests,
|
SourceLoaderGetSourceTests,
|
||||||
AbstractMethodImplTests)
|
AbstractMethodImplTests)
|
||||||
|
|
|
@ -133,6 +133,8 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #15627: Add the importlib.abc.SourceLoader.compile_source() method.
|
||||||
|
|
||||||
- Issue #16408: Fix file descriptors not being closed in error conditions
|
- Issue #16408: Fix file descriptors not being closed in error conditions
|
||||||
in the zipfile module. Patch by Serhiy Storchaka.
|
in the zipfile module. Patch by Serhiy Storchaka.
|
||||||
|
|
||||||
|
|
4718
Python/importlib.h
4718
Python/importlib.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue