Skip to content

Commit

Permalink
Use new Python module import system hooks to eliminate deprecation wa…
Browse files Browse the repository at this point in the history
…rnings.
  • Loading branch information
GrahamDumpleton committed Mar 5, 2022
1 parent 9399d7c commit 53323ba
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 8 deletions.
4 changes: 4 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ Version 1.14.0
implemented such that you don't have to use `Type.__wrapped__` instead of
`Type` as last argument to `isinstance()`.

* Eliminated deprecation warnings related to Python module import system, which
would have turned into broken code in Python 3.12. This was used by the post
import hook mechanism.

**New Features**

* Binary wheels provided on PyPi for `aarch64` Linux systems and macOS
Expand Down
65 changes: 57 additions & 8 deletions src/wrapt/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@

if PY2:
string_types = basestring,
find_spec = None
else:
import importlib
string_types = str,
from importlib.util import find_spec

from .decorators import synchronized

Expand Down Expand Up @@ -158,6 +159,16 @@ def load_module(self, fullname):

return module

# Python 3.4 introduced create_module() and exec_module() instead of
# load_module() alone. Splitting the two steps.

def create_module(self, spec):
return self.loader.create_module(spec)

def exec_module(self, module):
self.loader.exec_module(module)
notify_module_loaded(module)

class ImportHookFinder:

def __init__(self):
Expand Down Expand Up @@ -187,7 +198,7 @@ def find_module(self, fullname, path=None):
# Now call back into the import system again.

try:
if PY2:
if not find_spec:
# For Python 2 we don't have much choice but to
# call back in to __import__(). This will
# actually cause the module to be imported. If no
Expand All @@ -208,14 +219,52 @@ def find_module(self, fullname, path=None):
# our own loader which will then in turn call the
# real loader to import the module and invoke the
# post import hooks.
try:
import importlib.util
loader = importlib.util.find_spec(fullname).loader
except (ImportError, AttributeError):
loader = importlib.find_loader(fullname, path)
if loader:

loader = getattr(find_spec(fullname), "loader", None)

if loader and not isinstance(loader, _ImportHookChainedLoader):
return _ImportHookChainedLoader(loader)

finally:
del self.in_progress[fullname]

def find_spec(self, fullname, path=None, target=None):
# Since Python 3.4, you are meant to implement find_spec() method
# instead of find_module() and since Python 3.10 you get deprecation
# warnings if you don't define find_spec().

# If the module being imported is not one we have registered
# post import hooks for, we can return immediately. We will
# take no further part in the importing of this module.

if not fullname in _post_import_hooks:
return None

# When we are interested in a specific module, we will call back
# into the import system a second time to defer to the import
# finder that is supposed to handle the importing of the module.
# We set an in progress flag for the target module so that on
# the second time through we don't trigger another call back
# into the import system and cause a infinite loop.

if fullname in self.in_progress:
return None

self.in_progress[fullname] = True

# Now call back into the import system again.

try:
# This should only be Python 3 so find_spec() should always
# exist so don't need to check.

spec = find_spec(fullname)
loader = getattr(spec, "loader", None)

if loader and not isinstance(loader, _ImportHookChainedLoader):
spec.loader = _ImportHookChainedLoader(loader)

return spec

finally:
del self.in_progress[fullname]
Expand Down

0 comments on commit 53323ba

Please sign in to comment.