Skip to content

Commit 3ca1e4b

Browse files
committed
Make patch for issue in pkgutil.ImpImporter local by using contextmanager.
1 parent dc19624 commit 3ca1e4b

File tree

1 file changed

+43
-20
lines changed

1 file changed

+43
-20
lines changed

_pytest/main.py

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
""" core implementation of testing process: init, session, runtest loop. """
22
from __future__ import absolute_import, division, print_function
33

4+
import contextlib
45
import functools
56
import os
7+
import pkgutil
68
import six
79
import sys
810

@@ -728,36 +730,57 @@ def _tryconvertpyarg(self, x):
728730
"""Convert a dotted module name to path.
729731
730732
"""
731-
import pkgutil
732-
733-
if six.PY2: # python 3.4+ uses importlib instead
734-
def find_module_patched(self, fullname, path=None):
735-
subname = fullname.split(".")[-1]
736-
if subname != fullname and self.path is None:
737-
return None
738-
if self.path is None:
739-
path = None
740-
else:
741-
path = [self.path]
733+
@contextlib.contextmanager
734+
def _patched_find_module():
735+
"""Patch bug in pkgutil.ImpImporter.find_module
736+
737+
When using pkgutil.find_loader on python<3.4 it removes symlinks
738+
from the path due to a call to os.path.realpath. This is not consistent
739+
with actually doing the import (in these versions, pkgutil and __import__
740+
did not share the same underlying code). This can break conftest
741+
discovery for pytest where symlinks are involved.
742+
743+
The only supported python<3.4 by pytest is python 2.7.
744+
"""
745+
if six.PY2: # python 3.4+ uses importlib instead
746+
def find_module_patched(self, fullname, path=None):
747+
# Note: we ignore 'path' argument since it is only used via meta_path
748+
subname = fullname.split(".")[-1]
749+
if subname != fullname and self.path is None:
750+
return None
751+
if self.path is None:
752+
path = None
753+
else:
754+
# original: path = [os.path.realpath(self.path)]
755+
path = [self.path]
756+
try:
757+
file, filename, etc = pkgutil.imp.find_module(subname,
758+
path)
759+
except ImportError:
760+
return None
761+
return pkgutil.ImpLoader(fullname, file, filename, etc)
762+
763+
old_find_module = pkgutil.ImpImporter.find_module
764+
pkgutil.ImpImporter.find_module = find_module_patched
742765
try:
743-
file, filename, etc = pkgutil.imp.find_module(subname,
744-
path)
745-
except ImportError:
746-
return None
747-
return pkgutil.ImpLoader(fullname, file, filename, etc)
748-
749-
pkgutil.ImpImporter.find_module = find_module_patched
766+
yield
767+
finally:
768+
pkgutil.ImpImporter.find_module = old_find_module
769+
else:
770+
yield
750771

751772
try:
752-
loader = pkgutil.find_loader(x)
773+
with _patched_find_module():
774+
loader = pkgutil.find_loader(x)
753775
except ImportError:
754776
return x
755777
if loader is None:
756778
return x
757779
# This method is sometimes invoked when AssertionRewritingHook, which
758780
# does not define a get_filename method, is already in place:
759781
try:
760-
path = loader.get_filename(x)
782+
with _patched_find_module():
783+
path = loader.get_filename(x)
761784
except AttributeError:
762785
# Retrieve path from AssertionRewritingHook:
763786
path = loader.modules[x][0].co_filename

0 commit comments

Comments
 (0)