Repository: pypa/setuptools

Issue:
TestDepends.testRequire regression in 41.6.0 (py3)
While trying to build the new release of setuptools, I get the following test failure:

```
==================================================================== FAILURES =====================================================================
_____________________________________________________________ TestDepends.testRequire _____________________________________________________________

self = <setuptools.tests.test_setuptools.TestDepends object at 0x7fbfae31d710>

    @needs_bytecode
    def testRequire(self):
        req = Require('Json', '1.0.3', 'json')
    
        assert req.name == 'Json'
        assert req.module == 'json'
        assert req.requested_version == '1.0.3'
        assert req.attribute == '__version__'
        assert req.full_name() == 'Json-1.0.3'
    
        from json import __version__
        assert req.get_version() == __version__
        assert req.version_ok('1.0.9')
        assert not req.version_ok('0.9.1')
        assert not req.version_ok('unknown')
    
        assert req.is_present()
        assert req.is_current()
    
        req = Require('Json 3000', '03000', 'json', format=LooseVersion)
        assert req.is_present()
        assert not req.is_current()
        assert not req.version_ok('unknown')
    
        req = Require('Do-what-I-mean', '1.0', 'd-w-i-m')
        assert not req.is_present()
        assert not req.is_current()
    
        req = Require('Tests', None, 'tests', homepage="http://example.com")
        assert req.format is None
        assert req.attribute is None
        assert req.requested_version is None
        assert req.full_name() == 'Tests'
        assert req.homepage == 'http://example.com'
    
        from setuptools.tests import __path__
        paths = [os.path.dirname(p) for p in __path__]
>       assert req.is_present(paths)
E       AssertionError: assert False
E        +  where False = <bound method Require.is_present of <setuptools.depends.Require object at 0x7fbfae0d0b38>>(['/tmp/portage/dev-python/setuptools-41.6.0/work/setuptools-41.6.0-python3_5/setuptools'])
E        +    where <bound method Require.is_present of <setuptools.depends.Require object at 0x7fbfae0d0b38>> = <setuptools.depends.Require object at 0x7fbfae0d0b38>.is_present

setuptools/tests/test_setuptools.py:120: AssertionError
```

I can reproduce it reliably with at least pypy3.6 (7.2.0) & python3.5 (3.5.7). I haven't tested other versions yet.

Full build log: [dev-python:setuptools-41.6.0:20191030-083347.log](https://github.com/pypa/setuptools/files/3787797/dev-python.setuptools-41.6.0.20191030-083347.log)




Discussion:
In 41.5.1 all tests pass.
We have the same problem when trying to update to the new release in Fedora.
I have checked that `paths` are equivalent on both versions:

Old, 41.5.1:

    DEBUG: __path__ = ['/builddir/build/BUILD/setuptools-41.5.1/setuptools/tests']
    DEBUG: paths = ['/builddir/build/BUILD/setuptools-41.5.1/setuptools']

New, 41.6.0:

    DEBUG: __path__ = ['/builddir/build/BUILD/setuptools-41.6.0/setuptools/tests']
    DEBUG: paths = ['/builddir/build/BUILD/setuptools-41.6.0/setuptools']

Yet the test passes on 41.5.1 and fails on 41.6.0.
looks like this part is buggy:

https://github.com/pypa/setuptools/blob/master/setuptools/_imp.py#L22-L24

```
imp.find_module(self.module, paths)
(None, '/home/abuild/rpmbuild/BUILD/setuptools-41.6.0/setuptools/tests', ('', '', 5))
```

but `importlib.findspec(self.module, paths)` returns `None` and throws Importerror

And documentation says:

> If the module is a package, file is None, pathname is the package path and the last item in the description tuple is PKG_DIRECTORY.

and even worse `importlib.util.find_spec` parameters are `name` and `package` , not list of paths

Resolving patch:
diff --git a/setuptools/_imp.py b/setuptools/_imp.py
--- a/setuptools/_imp.py
+++ b/setuptools/_imp.py
@@ -17,9 +17,18 @@
 PY_FROZEN = 7
 
 
+def find_spec(module, paths):
+    finder = (
+        importlib.machinery.PathFinder().find_spec
+        if isinstance(paths, list) else
+        importlib.util.find_spec
+    )
+    return finder(module, paths)
+
+
 def find_module(module, paths=None):
     """Just like 'imp.find_module()', but with package support"""
-    spec = importlib.util.find_spec(module, paths)
+    spec = find_spec(module, paths)
     if spec is None:
         raise ImportError("Can't find %s" % module)
     if not spec.has_location and hasattr(spec, 'submodule_search_locations'):
@@ -60,14 +69,14 @@ def find_module(module, paths=None):
 
 
 def get_frozen_object(module, paths=None):
-    spec = importlib.util.find_spec(module, paths)
+    spec = find_spec(module, paths)
     if not spec:
         raise ImportError("Can't find %s" % module)
     return spec.loader.get_code(module)
 
 
 def get_module(module, paths, info):
-    spec = importlib.util.find_spec(module, paths)
+    spec = find_spec(module, paths)
     if not spec:
         raise ImportError("Can't find %s" % module)
     return module_from_spec(spec)


Test patch:
diff --git a/setuptools/tests/test_setuptools.py b/setuptools/tests/test_setuptools.py
--- a/setuptools/tests/test_setuptools.py
+++ b/setuptools/tests/test_setuptools.py
@@ -108,6 +108,11 @@ def testRequire(self):
         assert not req.is_present()
         assert not req.is_current()
 
+    @needs_bytecode
+    def test_require_present(self):
+        # In #1896, this test was failing for months with the only
+        # complaint coming from test runners (not end users).
+        # TODO: Evaluate if this code is needed at all.
         req = Require('Tests', None, 'tests', homepage="http://example.com")
         assert req.format is None
         assert req.attribute is None