Repository: cython/cython

Issue:
[BUG] PyPy (`!CYTHON_PEP489_MULTI_PHASE_INIT`) code path in Cython/Utility/ImportExport.c causes deprecation warnings
**Describe the bug**
The code path used in `__Pyx_SetPackagePathFromImportLib()` for PyPy3 (implied by `!CYTHON_PEP489_MULTI_PHASE_INIT`) uses deprecated `find_loader()` API that causes warnings that ultimately cause hypothesis' test suite to error out.

**To Reproduce**
This is using a venv created with PyPy3.9 7.3.9:

```
$ pypy3.9 -m venv venv
$ . venv/bin/activate
# cython needs to be installed to activate extensions in pydantic
(venv) $ pip install cython
Collecting cython
  Using cached Cython-0.29.28-py2.py3-none-any.whl (983 kB)
Installing collected packages: cython
Successfully installed cython-0.29.28
# install pydantic with extensions using Cython
(venv) $ git clone -q --depth 1 https://github.com/samuelcolvin/pydantic
(venv) $ pip install ./pydantic
Processing ./pydantic
  Preparing metadata (setup.py) ... done
Collecting typing-extensions>=3.7.4.3
  Using cached typing_extensions-4.2.0-py3-none-any.whl (24 kB)
Using legacy 'setup.py install' for pydantic, since package 'wheel' is not installed.
Installing collected packages: typing-extensions, pydantic
  Running setup.py install for pydantic ... done
Successfully installed pydantic-1.9.0 typing-extensions-4.2.0
(venv) $ python -Wdefault -c 'import pydantic'
<string>:1: DeprecationWarning: Deprecated since Python 3.4. Use importlib.util.find_spec() instead.
<frozen importlib._bootstrap>:228: ImportWarning: can't resolve package from __spec__ or __package__, falling back on __name__ and __path__
<frozen importlib._bootstrap>:228: ImportWarning: can't resolve package from __spec__ or __package__, falling back on __name__ and __path__
```

**Expected behavior**
No warnings.

**Environment (please complete the following information):**
 - OS: Gentoo Linux
 - Python version: PyPy3.9 7.3.9
 - Cython version: 0.29.28 (the code seems to be present on `master` too)

**Additional context**
These warnings seem to interact badly with pytest. They affect pydantic, pydantic installs a hypothesis entry point and pytest on hypothesis fails to run because of the warnings while importing:

```
pypy3 -m pytest -vv -ra -l -Wdefault --color=yes -p no:cov -p no:flake8 -p no:flakes -p no:pylint tests/cover tests/pytest tests/quality -n 12
Exception ignored in: 'pydantic'
Traceback (most recent call last):
  File "/usr/lib/pypy3.9/importlib/__init__.py", line 82, in find_loader
    warnings.warn('Deprecated since Python 3.4. '
DeprecationWarning: Deprecated since Python 3.4. Use importlib.util.find_spec() instead.
ERROR: while parsing the following warning configuration:

  ignore::hypothesis.errors.NonInteractiveExampleWarning

This error occurred:

Traceback (most recent call last):
  File "/usr/lib/pypy3.9/site-packages/_pytest/config/__init__.py", line 1638, in parse_warning_filter
    category: Type[Warning] = _resolve_warning_category(category_)
  File "/usr/lib/pypy3.9/site-packages/_pytest/config/__init__.py", line 1676, in _resolve_warning_category
    m = __import__(module, None, None, [klass])
  File "/tmp/portage/dev-python/hypothesis-6.46.1/work/hypothesis-hypothesis-python-6.46.1/hypothesis-python-pypy3/install/usr/lib/pypy3.9/site-packages/hypothesis/__init__.py", line 56, in <module>
    run()
  File "/tmp/portage/dev-python/hypothesis-6.46.1/work/hypothesis-hypothesis-python-6.46.1/hypothesis-python-pypy3/install/usr/lib/pypy3.9/site-packages/hypothesis/entry_points.py", line 63, in run
    hook = entry.load()
  File "/usr/lib/pypy3.9/importlib/metadata.py", line 86, in load
    module = import_module(match.group('module'))
  File "/usr/lib/pypy3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 972, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 666, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 565, in module_from_spec
  File "<builtin>/frozen importlib._bootstrap_external", line 1186, in create_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "pydantic/__init__.py", line 2, in init pydantic.__init__
    from . import dataclasses
ImportWarning: can't resolve package from __spec__ or __package__, falling back on __name__ and __path__
```


Discussion:
I think a PR to use `importlib.util.find_spec()` would be welcome (if it works). It'd probably be necessary to keep the old code for Python 2.7 for the moment.

Resolving patch:
diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py
--- a/Cython/Compiler/ModuleNode.py
+++ b/Cython/Compiler/ModuleNode.py
@@ -3254,18 +3254,12 @@ def generate_module_import_setup(self, env, code):
             # packages require __path__, so all we can do is try to figure
             # out the module path at runtime by rerunning the import lookup
             code.putln("if (!CYTHON_PEP489_MULTI_PHASE_INIT) {")
-            package_name, _ = self.full_module_name.rsplit('.', 1)
-            if '.' in package_name:
-                parent_name = '"%s"' % (package_name.rsplit('.', 1)[0],)
-            else:
-                parent_name = 'NULL'
             code.globalstate.use_utility_code(UtilityCode.load(
                 "SetPackagePathFromImportLib", "ImportExport.c"))
             code.putln(code.error_goto_if_neg(
-                '__Pyx_SetPackagePathFromImportLib(%s, %s)' % (
-                    parent_name,
+                '__Pyx_SetPackagePathFromImportLib(%s)' % (
                     code.globalstate.get_py_string_const(
-                        EncodedString(env.module_name)).cname),
+                        self.full_module_name).cname),
                 self.pos))
             code.putln("}")
 


Test patch: