From 9ffe85e1e86bc6718f105f2ab9833ef80f691367 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sun, 26 May 2013 16:45:10 -0400 Subject: Move importlib.abc.SourceLoader.source_to_code() to InspectLoader. While the previous location was fine, it makes more sense to have the method higher up in the inheritance chain, especially at a point where get_source() is defined which is the earliest source_to_code() could programmatically be used in the inheritance tree in importlib.abc. --- Doc/library/importlib.rst | 22 ++++++++-------- Lib/importlib/abc.py | 7 ++++++ Lib/test/test_importlib/test_abc.py | 50 ++++++++++++++++++++++++++++++++++--- Misc/NEWS | 2 +- 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index c44a345..cf86073 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -349,6 +349,17 @@ ABC hierarchy:: .. versionchanged:: 3.4 Raises :exc:`ImportError` instead of :exc:`NotImplementedError`. + .. method:: source_to_code(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 + .. class:: ExecutionLoader @@ -466,17 +477,6 @@ ABC hierarchy:: .. versionchanged:: 3.4 No longer raises :exc:`NotImplementedError` when called. - .. method:: source_to_code(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) Concrete implementation of :meth:`InspectLoader.get_code`. diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py index 7752ac4..cdcf244 100644 --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -165,6 +165,13 @@ class InspectLoader(Loader): """ raise ImportError + def source_to_code(self, data, path=''): + """Compile 'data' into a code object. + + The 'data' argument can be anything that compile() can handle. The'path' + argument should be where the data was retrieved (when applicable).""" + return compile(data, path, 'exec', dont_inherit=True) + _register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter, machinery.ExtensionFileLoader) diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py index 8d3d51e..5d1661c 100644 --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -12,7 +12,7 @@ import unittest from . import util -##### Inheritance +##### Inheritance ############################################################## class InheritanceTests: """Test that the specified class is a subclass/superclass of the expected @@ -81,7 +81,7 @@ class SourceLoader(InheritanceTests, unittest.TestCase): subclasses = [machinery.SourceFileLoader] -##### Default semantics +##### Default return values #################################################### class MetaPathFinderSubclass(abc.MetaPathFinder): def find_module(self, fullname, path): @@ -205,7 +205,50 @@ class ExecutionLoaderDefaultsTests(unittest.TestCase): self.ins.get_filename('blah') -##### SourceLoader +##### InspectLoader concrete methods ########################################### +class InspectLoaderConcreteMethodTests(unittest.TestCase): + + def source_to_module(self, data, path=None): + """Help with source_to_code() tests.""" + module = imp.new_module('blah') + loader = InspectLoaderSubclass() + if path is None: + code = loader.source_to_code(data) + else: + code = loader.source_to_code(data, path) + exec(code, module.__dict__) + return module + + def test_source_to_code_source(self): + # Since compile() can handle strings, so should source_to_code(). + source = 'attr = 42' + module = self.source_to_module(source) + self.assertTrue(hasattr(module, 'attr')) + self.assertEqual(module.attr, 42) + + def test_source_to_code_bytes(self): + # Since compile() can handle bytes, so should source_to_code(). + source = b'attr = 42' + module = self.source_to_module(source) + self.assertTrue(hasattr(module, 'attr')) + self.assertEqual(module.attr, 42) + + def test_source_to_code_path(self): + # Specifying a path should set it for the code object. + path = 'path/to/somewhere' + loader = InspectLoaderSubclass() + code = loader.source_to_code('', path) + self.assertEqual(code.co_filename, path) + + def test_source_to_code_no_path(self): + # Not setting a path should still work and be set to since that + # is a pre-existing practice as a default to compile(). + loader = InspectLoaderSubclass() + code = loader.source_to_code('') + self.assertEqual(code.co_filename, '') + + +##### SourceLoader concrete methods ############################################ class SourceOnlyLoaderMock(abc.SourceLoader): # Globals that should be defined for all modules. @@ -498,5 +541,6 @@ class SourceLoaderGetSourceTests(unittest.TestCase): self.assertEqual(mock.get_source(name), expect) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS index 24b5189..7dabb2e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1111,7 +1111,7 @@ Library - Issue #16522: added FAIL_FAST flag to doctest. -- Issue #15627: Add the importlib.abc.SourceLoader.source_to_code() method. +- Issue #15627: Add the importlib.abc.InspectLoader.source_to_code() method. - Issue #16408: Fix file descriptors not being closed in error conditions in the zipfile module. Patch by Serhiy Storchaka. -- cgit v0.12