Commit a113ac58 authored by Brett Cannon's avatar Brett Cannon

Implement InspectLoader for BuiltinImporter.

parent 7aa21f75
...@@ -175,11 +175,12 @@ are also provided to help in implementing the core ABCs. ...@@ -175,11 +175,12 @@ are also provided to help in implementing the core ABCs.
An abstract base class for a :term:`loader` which implements the optional An abstract base class for a :term:`loader` which implements the optional
:pep:`302` protocol for loaders which inspect modules. :pep:`302` protocol for loaders which inspect modules.
.. method:: is_package(fullname) .. method:: get_code(fullname)
An abstract method to return a true value if the module is a package, a An abstract method to return the :class:`code` object for a module.
false value otherwise. :exc:`ImportError` is raised if the :keyword:`None` is returned if the module does not have a code object
:term:`loader` cannot find the module. (e.g. built-in module). :exc:`ImportError` is raised if loader cannot
find the requested module.
.. method:: get_source(fullname) .. method:: get_source(fullname)
...@@ -188,12 +189,11 @@ are also provided to help in implementing the core ABCs. ...@@ -188,12 +189,11 @@ are also provided to help in implementing the core ABCs.
source is available (e.g. a built-in module). Raises :exc:`ImportError` source is available (e.g. a built-in module). Raises :exc:`ImportError`
if the loader cannot find the module specified. if the loader cannot find the module specified.
.. method:: get_code(fullname) .. method:: is_package(fullname)
An abstract method to return the :class:`code` object for a module. An abstract method to return a true value if the module is a package, a
:keyword:`None` is returned if the module does not have a code object false value otherwise. :exc:`ImportError` is raised if the
(e.g. built-in module). :exc:`ImportError` is raised if loader cannot :term:`loader` cannot find the module.
find the requested module.
.. class:: PyLoader .. class:: PyLoader
...@@ -274,7 +274,8 @@ find and load modules. ...@@ -274,7 +274,8 @@ find and load modules.
An :term:`importer` for built-in modules. All known built-in modules are An :term:`importer` for built-in modules. All known built-in modules are
listed in :data:`sys.builtin_module_names`. This class implements the listed in :data:`sys.builtin_module_names`. This class implements the
:class:`importlib.abc.Finder` and :class:`importlib.abc.Loader` ABCs. :class:`importlib.abc.Finder` and :class:`importlib.abc.InspectLoader`
ABCs.
Only class methods are defined by this class to alleviate the need for Only class methods are defined by this class to alleviate the need for
instantiation. instantiation.
......
to do to do
///// /////
* Fill in docstrings for ABCs. * Implement InspectLoader for FrozenImporter.
* Implement InspectLoader for BuiltinImporter and FrozenImporter.
+ Expose function to see if a frozen module is a package. + Expose function to see if a frozen module is a package.
......
...@@ -173,6 +173,16 @@ def _check_name(method): ...@@ -173,6 +173,16 @@ def _check_name(method):
return inner return inner
def _requires_builtin(fxn):
"""Decorator to verify the named module is built-in."""
def wrapper(self, fullname):
if fullname not in sys.builtin_module_names:
raise ImportError("{0} is not a built-in module".format(fullname))
return fxn(self, fullname)
_wrap(wrapper, fxn)
return wrapper
def _suffix_list(suffix_type): def _suffix_list(suffix_type):
"""Return a list of file suffixes based on the imp file type.""" """Return a list of file suffixes based on the imp file type."""
return [suffix[0] for suffix in imp.get_suffixes() return [suffix[0] for suffix in imp.get_suffixes()
...@@ -204,10 +214,9 @@ class BuiltinImporter: ...@@ -204,10 +214,9 @@ class BuiltinImporter:
@classmethod @classmethod
@set_package @set_package
@set_loader @set_loader
@_requires_builtin
def load_module(cls, fullname): def load_module(cls, fullname):
"""Load a built-in module.""" """Load a built-in module."""
if fullname not in sys.builtin_module_names:
raise ImportError("{0} is not a built-in module".format(fullname))
is_reload = fullname in sys.modules is_reload = fullname in sys.modules
try: try:
return imp.init_builtin(fullname) return imp.init_builtin(fullname)
...@@ -216,6 +225,24 @@ class BuiltinImporter: ...@@ -216,6 +225,24 @@ class BuiltinImporter:
del sys.modules[fullname] del sys.modules[fullname]
raise raise
@classmethod
@_requires_builtin
def get_code(cls, fullname):
"""Return None as built-in modules do not have code objects."""
return None
@classmethod
@_requires_builtin
def get_source(cls, fullname):
"""Return None as built-in modules do not have source code."""
return None
@classmethod
@_requires_builtin
def is_package(cls, fullname):
"""Return None as built-in module are never packages."""
return False
class FrozenImporter: class FrozenImporter:
......
...@@ -14,7 +14,6 @@ class Loader(metaclass=abc.ABCMeta): ...@@ -14,7 +14,6 @@ class Loader(metaclass=abc.ABCMeta):
"""Abstract method which when implemented should load a module.""" """Abstract method which when implemented should load a module."""
raise NotImplementedError raise NotImplementedError
Loader.register(machinery.BuiltinImporter)
Loader.register(machinery.FrozenImporter) Loader.register(machinery.FrozenImporter)
...@@ -75,6 +74,8 @@ class InspectLoader(Loader): ...@@ -75,6 +74,8 @@ class InspectLoader(Loader):
module.""" module."""
return NotImplementedError return NotImplementedError
InspectLoader.register(machinery.BuiltinImporter)
class PyLoader(_bootstrap.PyLoader, InspectLoader): class PyLoader(_bootstrap.PyLoader, InspectLoader):
......
from importlib import machinery from importlib import machinery
from .. import abc from .. import abc
from .. import util from .. import util
from . import util as builtin_util
import sys import sys
import unittest import unittest
...@@ -9,13 +10,11 @@ class FinderTests(abc.FinderTests): ...@@ -9,13 +10,11 @@ class FinderTests(abc.FinderTests):
"""Test find_module() for built-in modules.""" """Test find_module() for built-in modules."""
assert 'errno' in sys.builtin_module_names
name = 'errno'
def test_module(self): def test_module(self):
# Common case. # Common case.
with util.uncache(self.name): with util.uncache(builtin_util.NAME):
self.assert_(machinery.BuiltinImporter.find_module(self.name)) found = machinery.BuiltinImporter.find_module(builtin_util.NAME)
self.assert_(found)
def test_package(self): def test_package(self):
# Built-in modules cannot be a package. # Built-in modules cannot be a package.
...@@ -40,8 +39,9 @@ class FinderTests(abc.FinderTests): ...@@ -40,8 +39,9 @@ class FinderTests(abc.FinderTests):
def test_ignore_path(self): def test_ignore_path(self):
# The value for 'path' should always trigger a failed import. # The value for 'path' should always trigger a failed import.
with util.uncache(self.name): with util.uncache(builtin_util.NAME):
loader = machinery.BuiltinImporter.find_module(self.name, ['pkg']) loader = machinery.BuiltinImporter.find_module(builtin_util.NAME,
['pkg'])
self.assert_(loader is None) self.assert_(loader is None)
......
...@@ -2,6 +2,7 @@ import importlib ...@@ -2,6 +2,7 @@ import importlib
from importlib import machinery from importlib import machinery
from .. import abc from .. import abc
from .. import util from .. import util
from . import util as builtin_util
import sys import sys
import types import types
...@@ -12,9 +13,6 @@ class LoaderTests(abc.LoaderTests): ...@@ -12,9 +13,6 @@ class LoaderTests(abc.LoaderTests):
"""Test load_module() for built-in modules.""" """Test load_module() for built-in modules."""
assert 'errno' in sys.builtin_module_names
name = 'errno'
verification = {'__name__': 'errno', '__package__': '', verification = {'__name__': 'errno', '__package__': '',
'__loader__': machinery.BuiltinImporter} '__loader__': machinery.BuiltinImporter}
...@@ -30,8 +28,8 @@ class LoaderTests(abc.LoaderTests): ...@@ -30,8 +28,8 @@ class LoaderTests(abc.LoaderTests):
def test_module(self): def test_module(self):
# Common case. # Common case.
with util.uncache(self.name): with util.uncache(builtin_util.NAME):
module = self.load_module(self.name) module = self.load_module(builtin_util.NAME)
self.verify(module) self.verify(module)
def test_package(self): def test_package(self):
...@@ -48,9 +46,9 @@ class LoaderTests(abc.LoaderTests): ...@@ -48,9 +46,9 @@ class LoaderTests(abc.LoaderTests):
def test_module_reuse(self): def test_module_reuse(self):
# Test that the same module is used in a reload. # Test that the same module is used in a reload.
with util.uncache(self.name): with util.uncache(builtin_util.NAME):
module1 = self.load_module(self.name) module1 = self.load_module(builtin_util.NAME)
module2 = self.load_module(self.name) module2 = self.load_module(builtin_util.NAME)
self.assert_(module1 is module2) self.assert_(module1 is module2)
def test_unloadable(self): def test_unloadable(self):
...@@ -65,9 +63,36 @@ class LoaderTests(abc.LoaderTests): ...@@ -65,9 +63,36 @@ class LoaderTests(abc.LoaderTests):
self.assertRaises(ImportError, self.load_module, 'importlib') self.assertRaises(ImportError, self.load_module, 'importlib')
class InspectLoaderTests(unittest.TestCase):
"""Tests for InspectLoader methods for BuiltinImporter."""
def test_get_code(self):
# There is no code object.
result = machinery.BuiltinImporter.get_code(builtin_util.NAME)
self.assert_(result is None)
def test_get_source(self):
# There is no source.
result = machinery.BuiltinImporter.get_source(builtin_util.NAME)
self.assert_(result is None)
def test_is_package(self):
# Cannot be a package.
result = machinery.BuiltinImporter.is_package(builtin_util.NAME)
self.assert_(not result)
def test_not_builtin(self):
# Modules not built-in should raise ImportError.
for meth_name in ('get_code', 'get_source', 'is_package'):
method = getattr(machinery.BuiltinImporter, meth_name)
self.assertRaises(ImportError, method, builtin_util.BAD_NAME)
def test_main(): def test_main():
from test.support import run_unittest from test.support import run_unittest
run_unittest(LoaderTests) run_unittest(LoaderTests, InspectLoaderTests)
if __name__ == '__main__': if __name__ == '__main__':
......
import sys
assert 'errno' in sys.builtin_module_names
NAME = 'errno'
assert 'importlib' not in sys.builtin_module_names
BAD_NAME = 'importlib'
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment