Skip to content

Commit b462110

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

File tree

1 file changed

+44
-20
lines changed

1 file changed

+44
-20
lines changed

_pytest/main.py

Lines changed: 44 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,58 @@ 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
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+
subname = fullname.split(".")[-1]
748+
if subname != fullname and self.path is None:
749+
return None
750+
if self.path is None:
751+
path = None
752+
else:
753+
path = [self.path]
754+
try:
755+
file, filename, etc = pkgutil.imp.find_module(subname,
756+
path)
757+
except ImportError:
758+
return None
759+
return pkgutil.ImpLoader(fullname, file, filename, etc)
760+
761+
old_find_module = pkgutil.ImpImporter.find_module
762+
pkgutil.ImpImporter.find_module = find_module_patched
742763
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
764+
yield
765+
finally:
766+
pkgutil.ImpImporter.find_module = old_find_module
767+
else:
768+
yield
769+
#
770+
# if six.PY2: # python 3.4+ uses importlib instead
771+
# pkgutil.ImpImporter.find_module = find_module_patched
750772

751773
try:
752-
loader = pkgutil.find_loader(x)
774+
with _patched_find_module():
775+
loader = pkgutil.find_loader(x)
753776
except ImportError:
754777
return x
755778
if loader is None:
756779
return x
757780
# This method is sometimes invoked when AssertionRewritingHook, which
758781
# does not define a get_filename method, is already in place:
759782
try:
760-
path = loader.get_filename(x)
783+
with _patched_find_module():
784+
path = loader.get_filename(x)
761785
except AttributeError:
762786
# Retrieve path from AssertionRewritingHook:
763787
path = loader.modules[x][0].co_filename

0 commit comments

Comments
 (0)