PyPy3 support (#2146)

* Error out eval_file

* Enable dynamic attribute support for Pypy >= 6

* Add a test for dynamic attribute support

* Skip test for eval_file on pypy

* Workaround for __qualname__ on PyPy3

* Add a PyPy3.6 7.3.0 build

* Only disable in PyPy3

* Fix travis testing

* No numpy and scipy for pypy

* Enable test on pypy2

* Fix logic in eval_file

* Skip a few tests due to bugs in PyPy

* scipy wheels are broken. make pypy2 a failrue

Co-authored-by: Andreas Kloeckner <inform@tiker.net>
diff --git a/.travis.yml b/.travis.yml
index f9a9065..0e50458 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -192,9 +192,8 @@
           make pytest -j 2"
         set +ex
   allow_failures:
-    - name: PyPy 7.3, Python 2.7, c++11, gcc 4.8
-    - name: PyPy 7.3, Python 3.6, c++11, gcc 5
     - name: Python 3.9 beta, c++17, gcc 7 (w/o numpy/scipy)
+    - name: PyPy 7.3, Python 2.7, c++11, gcc 4.8
 cache:
   directories:
   - $HOME/.local/bin
@@ -278,15 +277,17 @@
     fi
 
     export NPY_NUM_BUILD_JOBS=2
-    echo "Installing pytest, numpy, scipy..."
     local PIP_CMD=""
     if [ -n "$PYPY" ]; then
       # For expediency, install only versions that are available on the extra index.
+      echo "Not installing numpy, scipy as working wheels are not available"
+      # travis_wait 30 $PY_CMD -m pip install --user --upgrade --extra-index-url https://antocuni.github.io/pypy-wheels/manylinux2010 \
+      #    numpy scipy
+      echo "Installing pytest"
       travis_wait 30 \
-        $PY_CMD -m pip install --user --upgrade --extra-index-url https://antocuni.github.io/pypy-wheels/manylinux2010 \
-          numpy scipy
         $PY_CMD -m pip install --user --upgrade pytest
     else
+      echo "Installing pytest, numpy, scipy..."
       $PY_CMD -m pip install --user --upgrade pytest numpy scipy
     fi
     echo "done."
diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h
index e5783d9..f6b89c2 100644
--- a/include/pybind11/detail/class.h
+++ b/include/pybind11/detail/class.h
@@ -15,7 +15,7 @@
 NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 NAMESPACE_BEGIN(detail)
 
-#if PY_VERSION_HEX >= 0x03030000
+#if PY_VERSION_HEX >= 0x03030000 && !defined(PYPY_VERSION)
 #  define PYBIND11_BUILTIN_QUALNAME
 #  define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
 #else
@@ -475,7 +475,7 @@
 /// Give instances of this type a `__dict__` and opt into garbage collection.
 inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
     auto type = &heap_type->ht_type;
-#if defined(PYPY_VERSION)
+#if defined(PYPY_VERSION) && (PYPY_VERSION_NUM < 0x06000000)
     pybind11_fail(std::string(type->tp_name) + ": dynamic attributes are "
                                                "currently not supported in "
                                                "conjunction with PyPy!");
diff --git a/include/pybind11/eval.h b/include/pybind11/eval.h
index ea85ba1..422e629 100644
--- a/include/pybind11/eval.h
+++ b/include/pybind11/eval.h
@@ -66,6 +66,20 @@
     eval<eval_statements>(s, global, local);
 }
 
+#if defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x3000000
+template <eval_mode mode = eval_statements>
+object eval_file(str, object, object) {
+    pybind11_fail("eval_file not supported in PyPy3. Use eval");
+}
+template <eval_mode mode = eval_statements>
+object eval_file(str, object) {
+    pybind11_fail("eval_file not supported in PyPy3. Use eval");
+}
+template <eval_mode mode = eval_statements>
+object eval_file(str) {
+    pybind11_fail("eval_file not supported in PyPy3. Use eval");
+}
+#else
 template <eval_mode mode = eval_statements>
 object eval_file(str fname, object global = globals(), object local = object()) {
     if (!local)
@@ -113,5 +127,6 @@
         throw error_already_set();
     return reinterpret_steal<object>(result);
 }
+#endif
 
 NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/tests/conftest.py b/tests/conftest.py
index 57f681c..58ebeca 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -215,6 +215,11 @@
     pytest.requires_eigen_and_scipy = skipif(
         not have_eigen or not scipy, reason="eigen and/or scipy are not installed")
     pytest.unsupported_on_pypy = skipif(pypy, reason="unsupported on PyPy")
+    pytest.bug_in_pypy = pytest.mark.xfail(pypy, reason="bug in PyPy")
+    pytest.unsupported_on_pypy3 = skipif(pypy and sys.version_info.major >= 3,
+                                         reason="unsupported on PyPy3")
+    pytest.unsupported_on_pypy_lt_6 = skipif(pypy and sys.pypy_version_info[0] < 6,
+                                             reason="unsupported on PyPy<6")
     pytest.unsupported_on_py2 = skipif(sys.version_info.major < 3,
                                        reason="unsupported on Python 2.x")
     pytest.gc_collect = gc_collect
diff --git a/tests/test_eval.py b/tests/test_eval.py
index bda4ef6..94228e7 100644
--- a/tests/test_eval.py
+++ b/tests/test_eval.py
@@ -1,4 +1,5 @@
 import os
+import pytest
 from pybind11_tests import eval_ as m
 
 
@@ -10,8 +11,12 @@
     assert m.test_eval()
     assert m.test_eval_single_statement()
 
+    assert m.test_eval_failure()
+
+
+@pytest.unsupported_on_pypy3
+def test_eval_file():
     filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
     assert m.test_eval_file(filename)
 
-    assert m.test_eval_failure()
     assert m.test_eval_file_failure()
diff --git a/tests/test_local_bindings.py b/tests/test_local_bindings.py
index b380376..be841a7 100644
--- a/tests/test_local_bindings.py
+++ b/tests/test_local_bindings.py
@@ -152,6 +152,7 @@
     assert m.local_cpp_types_addr() != cm.local_cpp_types_addr()
 
 
+@pytest.bug_in_pypy
 def test_stl_caster_vs_stl_bind(msg):
     """One module uses a generic vector caster from `<pybind11/stl.h>` while the other
     exports `std::vector<int>` via `py:bind_vector` and `py::module_local`"""
diff --git a/tests/test_multiple_inheritance.cpp b/tests/test_multiple_inheritance.cpp
index ba1674f..70e3417 100644
--- a/tests/test_multiple_inheritance.cpp
+++ b/tests/test_multiple_inheritance.cpp
@@ -193,7 +193,7 @@
         .def_readwrite_static("static_value", &VanillaStaticMix2::static_value);
 
 
-#if !defined(PYPY_VERSION)
+#if !(defined(PYPY_VERSION) && (PYPY_VERSION_NUM < 0x06000000))
     struct WithDict { };
     struct VanillaDictMix1 : Vanilla, WithDict { };
     struct VanillaDictMix2 : WithDict, Vanilla { };
diff --git a/tests/test_multiple_inheritance.py b/tests/test_multiple_inheritance.py
index 475dd3b..7a6e4a0 100644
--- a/tests/test_multiple_inheritance.py
+++ b/tests/test_multiple_inheritance.py
@@ -10,6 +10,7 @@
     assert mt.bar() == 4
 
 
+@pytest.bug_in_pypy
 def test_multiple_inheritance_mix1():
     class Base1:
         def __init__(self, i):
@@ -49,6 +50,7 @@
     assert mt.bar() == 4
 
 
+@pytest.bug_in_pypy
 def test_multiple_inheritance_python():
 
     class MI1(m.Base1, m.Base2):
@@ -253,7 +255,7 @@
         assert d.static_value == 0
 
 
-@pytest.unsupported_on_pypy
+@pytest.unsupported_on_pypy_lt_6
 def test_mi_dynamic_attributes():
     """Mixing bases with and without dynamic attribute support"""