mirror of
https://github.com/python/cpython.git
synced 2025-11-02 19:12:55 +00:00
Implement get_source for importlib.abc.PyLoader using source_path and get_data.
This commit is contained in:
parent
28c013dcb4
commit
d43b30b046
4 changed files with 59 additions and 10 deletions
|
|
@ -226,6 +226,13 @@ are also provided to help in implementing the core ABCs.
|
||||||
:meth:`importlib.abc.InspectLoader.get_code` that creates code objects
|
:meth:`importlib.abc.InspectLoader.get_code` that creates code objects
|
||||||
from Python source code.
|
from Python source code.
|
||||||
|
|
||||||
|
.. method:: get_source(fullname)
|
||||||
|
|
||||||
|
A concrete implementation of
|
||||||
|
:meth:`importlib.abc.InspectLoader.get_source`. Uses
|
||||||
|
:meth:`importlib.abc.InspectLoader.get_data` and :meth:`source_path` to
|
||||||
|
get the source code.
|
||||||
|
|
||||||
|
|
||||||
.. class:: PyPycLoader
|
.. class:: PyPycLoader
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ to do
|
||||||
|
|
||||||
* Public API left to expose (w/ docs!)
|
* Public API left to expose (w/ docs!)
|
||||||
|
|
||||||
+ abc.PyLoader.get_source
|
|
||||||
+ util.set_loader
|
+ util.set_loader
|
||||||
|
|
||||||
* Implement InspectLoader for BuiltinImporter and FrozenImporter.
|
* Implement InspectLoader for BuiltinImporter and FrozenImporter.
|
||||||
|
|
|
||||||
|
|
@ -369,6 +369,26 @@ class PyLoader:
|
||||||
source = source.replace(line_endings, b'\n')
|
source = source.replace(line_endings, b'\n')
|
||||||
return compile(source, source_path, 'exec', dont_inherit=True)
|
return compile(source, source_path, 'exec', dont_inherit=True)
|
||||||
|
|
||||||
|
# Never use in implementing import! Imports code within the method.
|
||||||
|
def get_source(self, fullname):
|
||||||
|
"""Return the source code for a module.
|
||||||
|
|
||||||
|
self.source_path() and self.get_data() are used to implement this
|
||||||
|
method.
|
||||||
|
|
||||||
|
"""
|
||||||
|
path = self.source_path(fullname)
|
||||||
|
if path is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
source_bytes = self.get_data(path)
|
||||||
|
except IOError:
|
||||||
|
return ImportError("source not available through get_data()")
|
||||||
|
import io
|
||||||
|
import tokenize
|
||||||
|
encoding = tokenize.detect_encoding(io.BytesIO(source_bytes).readline)
|
||||||
|
return source_bytes.decode(encoding[0])
|
||||||
|
|
||||||
|
|
||||||
class PyPycLoader(PyLoader):
|
class PyPycLoader(PyLoader):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ import unittest
|
||||||
class PyLoaderMock(abc.PyLoader):
|
class PyLoaderMock(abc.PyLoader):
|
||||||
|
|
||||||
# Globals that should be defined for all modules.
|
# Globals that should be defined for all modules.
|
||||||
source = ("_ = '::'.join([__name__, __file__, __package__, "
|
source = (b"_ = '::'.join([__name__, __file__, __package__, "
|
||||||
"repr(__loader__)])")
|
b"repr(__loader__)])")
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
"""Take a dict of 'module_name: path' pairings.
|
"""Take a dict of 'module_name: path' pairings.
|
||||||
|
|
@ -30,7 +30,7 @@ class PyLoaderMock(abc.PyLoader):
|
||||||
def get_data(self, path):
|
def get_data(self, path):
|
||||||
if path not in self.path_to_module:
|
if path not in self.path_to_module:
|
||||||
raise IOError
|
raise IOError
|
||||||
return self.source.encode('utf-8')
|
return self.source
|
||||||
|
|
||||||
def is_package(self, name):
|
def is_package(self, name):
|
||||||
try:
|
try:
|
||||||
|
|
@ -38,9 +38,6 @@ class PyLoaderMock(abc.PyLoader):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ImportError
|
raise ImportError
|
||||||
|
|
||||||
def get_source(self, name): # Should not be needed.
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def source_path(self, name):
|
def source_path(self, name):
|
||||||
try:
|
try:
|
||||||
return self.module_paths[name]
|
return self.module_paths[name]
|
||||||
|
|
@ -181,7 +178,7 @@ class PyLoaderTests(testing_abc.LoaderTests):
|
||||||
module = imp.new_module(name)
|
module = imp.new_module(name)
|
||||||
module.blah = None
|
module.blah = None
|
||||||
mock = self.mocker({name: 'path/to/mod'})
|
mock = self.mocker({name: 'path/to/mod'})
|
||||||
mock.source = "1/0"
|
mock.source = b"1/0"
|
||||||
with util.uncache(name):
|
with util.uncache(name):
|
||||||
sys.modules[name] = module
|
sys.modules[name] = module
|
||||||
self.assertRaises(ZeroDivisionError, mock.load_module, name)
|
self.assertRaises(ZeroDivisionError, mock.load_module, name)
|
||||||
|
|
@ -192,7 +189,7 @@ class PyLoaderTests(testing_abc.LoaderTests):
|
||||||
def test_unloadable(self):
|
def test_unloadable(self):
|
||||||
name = "mod"
|
name = "mod"
|
||||||
mock = self.mocker({name: 'path/to/mod'})
|
mock = self.mocker({name: 'path/to/mod'})
|
||||||
mock.source = "1/0"
|
mock.source = b"1/0"
|
||||||
with util.uncache(name):
|
with util.uncache(name):
|
||||||
self.assertRaises(ZeroDivisionError, mock.load_module, name)
|
self.assertRaises(ZeroDivisionError, mock.load_module, name)
|
||||||
self.assert_(name not in sys.modules)
|
self.assert_(name not in sys.modules)
|
||||||
|
|
@ -201,6 +198,8 @@ class PyLoaderTests(testing_abc.LoaderTests):
|
||||||
|
|
||||||
class PyLoaderInterfaceTests(unittest.TestCase):
|
class PyLoaderInterfaceTests(unittest.TestCase):
|
||||||
|
|
||||||
|
"""Tests for importlib.abc.PyLoader to make sure that when source_path()
|
||||||
|
doesn't return a path everything works as expected."""
|
||||||
|
|
||||||
def test_no_source_path(self):
|
def test_no_source_path(self):
|
||||||
# No source path should lead to ImportError.
|
# No source path should lead to ImportError.
|
||||||
|
|
@ -216,6 +215,30 @@ class PyLoaderInterfaceTests(unittest.TestCase):
|
||||||
self.assertRaises(ImportError, mock.load_module, name)
|
self.assertRaises(ImportError, mock.load_module, name)
|
||||||
|
|
||||||
|
|
||||||
|
class PyLoaderGetSourceTests(unittest.TestCase):
|
||||||
|
|
||||||
|
"""Tests for importlib.abc.PyLoader.get_source()."""
|
||||||
|
|
||||||
|
def test_default_encoding(self):
|
||||||
|
# Should have no problems with UTF-8 text.
|
||||||
|
name = 'mod'
|
||||||
|
mock = PyLoaderMock({name: 'path/to/mod'})
|
||||||
|
source = 'x = "ü"'
|
||||||
|
mock.source = source.encode('utf-8')
|
||||||
|
returned_source = mock.get_source(name)
|
||||||
|
self.assertEqual(returned_source, source)
|
||||||
|
|
||||||
|
def test_decoded_source(self):
|
||||||
|
# Decoding should work.
|
||||||
|
name = 'mod'
|
||||||
|
mock = PyLoaderMock({name: 'path/to/mod'})
|
||||||
|
source = "# coding: Latin-1\nx='ü'"
|
||||||
|
assert source.encode('latin-1') != source.encode('utf-8')
|
||||||
|
mock.source = source.encode('latin-1')
|
||||||
|
returned_source = mock.get_source(name)
|
||||||
|
self.assertEqual(returned_source, source)
|
||||||
|
|
||||||
|
|
||||||
class PyPycLoaderTests(PyLoaderTests):
|
class PyPycLoaderTests(PyLoaderTests):
|
||||||
|
|
||||||
"""Tests for importlib.abc.PyPycLoader."""
|
"""Tests for importlib.abc.PyPycLoader."""
|
||||||
|
|
@ -380,7 +403,7 @@ class MissingPathsTests(unittest.TestCase):
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
from test.support import run_unittest
|
from test.support import run_unittest
|
||||||
run_unittest(PyLoaderTests, PyLoaderInterfaceTests,
|
run_unittest(PyLoaderTests, PyLoaderInterfaceTests, PyLoaderGetSourceTests,
|
||||||
PyPycLoaderTests, SkipWritingBytecodeTests,
|
PyPycLoaderTests, SkipWritingBytecodeTests,
|
||||||
RegeneratedBytecodeTests, BadBytecodeFailureTests,
|
RegeneratedBytecodeTests, BadBytecodeFailureTests,
|
||||||
MissingPathsTests)
|
MissingPathsTests)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue