mirror of
https://github.com/python/cpython.git
synced 2025-08-22 09:45:06 +00:00
bpo-45324: Capture data in FrozenImporter.find_spec() to use in exec_module(). (gh-28633)
Before this change we end up duplicating effort and throwing away data in FrozenImporter.find_spec(). Now we do the work once in find_spec() and the only thing we do in FrozenImporter.exec_module() is turn the raw frozen data into a code object and then exec it. We've added _imp.find_frozen(), add an arg to _imp.get_frozen_object(), and updated FrozenImporter. We've also moved some code around to reduce duplication, get a little more consistency in outcomes, and be more efficient. Note that this change is mostly necessary if we want to set __file__ on frozen stdlib modules. (See https://bugs.python.org/issue21736.) https://bugs.python.org/issue45324
This commit is contained in:
parent
b9bb74871b
commit
c3d9ac8b34
6 changed files with 331 additions and 120 deletions
|
@ -826,10 +826,15 @@ class FrozenImporter:
|
|||
|
||||
@classmethod
|
||||
def find_spec(cls, fullname, path=None, target=None):
|
||||
if _imp.is_frozen(fullname):
|
||||
return spec_from_loader(fullname, cls, origin=cls._ORIGIN)
|
||||
else:
|
||||
info = _call_with_frames_removed(_imp.find_frozen, fullname)
|
||||
if info is None:
|
||||
return None
|
||||
data, ispkg = info
|
||||
spec = spec_from_loader(fullname, cls,
|
||||
origin=cls._ORIGIN,
|
||||
is_package=ispkg)
|
||||
spec.loader_state = data
|
||||
return spec
|
||||
|
||||
@classmethod
|
||||
def find_module(cls, fullname, path=None):
|
||||
|
@ -849,11 +854,22 @@ class FrozenImporter:
|
|||
|
||||
@staticmethod
|
||||
def exec_module(module):
|
||||
name = module.__spec__.name
|
||||
if not _imp.is_frozen(name):
|
||||
raise ImportError('{!r} is not a frozen module'.format(name),
|
||||
name=name)
|
||||
code = _call_with_frames_removed(_imp.get_frozen_object, name)
|
||||
spec = module.__spec__
|
||||
name = spec.name
|
||||
try:
|
||||
data = spec.loader_state
|
||||
except AttributeError:
|
||||
if not _imp.is_frozen(name):
|
||||
raise ImportError('{!r} is not a frozen module'.format(name),
|
||||
name=name)
|
||||
data = None
|
||||
else:
|
||||
# We clear the extra data we got from the finder, to save memory.
|
||||
# Note that if this method is called again (e.g. by
|
||||
# importlib.reload()) then _imp.get_frozen_object() will notice
|
||||
# no data was provided and will look it up.
|
||||
spec.loader_state = None
|
||||
code = _call_with_frames_removed(_imp.get_frozen_object, name, data)
|
||||
exec(code, module.__dict__)
|
||||
|
||||
@classmethod
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue