Make patch for issue in pkgutil.ImpImporter local by using contextmanager.

This commit is contained in:
Henk-Jaap Wagenaar 2017-12-12 08:27:08 +00:00
parent dc19624248
commit 3ca1e4b7f0
1 changed files with 42 additions and 19 deletions

View File

@ -1,8 +1,10 @@
""" core implementation of testing process: init, session, runtest loop. """ """ core implementation of testing process: init, session, runtest loop. """
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import contextlib
import functools import functools
import os import os
import pkgutil
import six import six
import sys import sys
@ -728,28 +730,48 @@ class Session(FSCollector):
"""Convert a dotted module name to path. """Convert a dotted module name to path.
""" """
import pkgutil @contextlib.contextmanager
def _patched_find_module():
"""Patch bug in pkgutil.ImpImporter.find_module
if six.PY2: # python 3.4+ uses importlib instead When using pkgutil.find_loader on python<3.4 it removes symlinks
def find_module_patched(self, fullname, path=None): from the path due to a call to os.path.realpath. This is not consistent
subname = fullname.split(".")[-1] with actually doing the import (in these versions, pkgutil and __import__
if subname != fullname and self.path is None: did not share the same underlying code). This can break conftest
return None discovery for pytest where symlinks are involved.
if self.path is None:
path = None The only supported python<3.4 by pytest is python 2.7.
else: """
path = [self.path] if six.PY2: # python 3.4+ uses importlib instead
def find_module_patched(self, fullname, path=None):
# Note: we ignore 'path' argument since it is only used via meta_path
subname = fullname.split(".")[-1]
if subname != fullname and self.path is None:
return None
if self.path is None:
path = None
else:
# original: path = [os.path.realpath(self.path)]
path = [self.path]
try:
file, filename, etc = pkgutil.imp.find_module(subname,
path)
except ImportError:
return None
return pkgutil.ImpLoader(fullname, file, filename, etc)
old_find_module = pkgutil.ImpImporter.find_module
pkgutil.ImpImporter.find_module = find_module_patched
try: try:
file, filename, etc = pkgutil.imp.find_module(subname, yield
path) finally:
except ImportError: pkgutil.ImpImporter.find_module = old_find_module
return None else:
return pkgutil.ImpLoader(fullname, file, filename, etc) yield
pkgutil.ImpImporter.find_module = find_module_patched
try: try:
loader = pkgutil.find_loader(x) with _patched_find_module():
loader = pkgutil.find_loader(x)
except ImportError: except ImportError:
return x return x
if loader is None: if loader is None:
@ -757,7 +779,8 @@ class Session(FSCollector):
# This method is sometimes invoked when AssertionRewritingHook, which # This method is sometimes invoked when AssertionRewritingHook, which
# does not define a get_filename method, is already in place: # does not define a get_filename method, is already in place:
try: try:
path = loader.get_filename(x) with _patched_find_module():
path = loader.get_filename(x)
except AttributeError: except AttributeError:
# Retrieve path from AssertionRewritingHook: # Retrieve path from AssertionRewritingHook:
path = loader.modules[x][0].co_filename path = loader.modules[x][0].co_filename