[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/compiler-research/cppjit/main/test/test_pythonization.py [Back]  [Original]

import sys

import py
from pytest import mark, raises
from support import (
    IS_CLANG_REPL,
    IS_LINUX_ARM,
    IS_MAC,
    IS_VALGRIND,
    setup_make,
)

currpath = py.path.local(__file__).dirpath()
test_dct = str(currpath.join("cpp/pythonizablesDict"))


def setup_module(mod):
    setup_make("pythonizables")


class TestClassPYTHONIZATION:
    def setup_class(cls):
        cls.test_dct = test_dct
        import cppjit

        cls.pyzables = cppjit.load_reflection_info(cls.test_dct)

    @mark.xfail(condition=IS_MAC, reason="Fails on OSX")
    def test00_api(self):
        """Test basic semantics of the pythonization API"""

        import cppjit

        raises(TypeError, cppjit.py.add_pythonization, 1)

        def pythonizor1(klass, name):
            pass

        def pythonizor2(klass, name):
            pass

        pythonizor3 = pythonizor1

        cppjit.py.add_pythonization(pythonizor1)
        assert cppjit.py.remove_pythonization(pythonizor2) == False
        assert cppjit.py.remove_pythonization(pythonizor3) == True

        def pythonizor(klass, name):
            if name == "pyzables::SomeDummy1":
                klass.test = 1

        cppjit.py.add_pythonization(pythonizor)
        assert cppjit.gbl.pyzables.SomeDummy1.test == 1

        def pythonizor(klass, name):
            if name == "SomeDummy2":
                klass.test = 2

        cppjit.py.add_pythonization(pythonizor, "pyzables")

        # global pythonizors are still run even if namespaced ones available
        def pythonizor(klass, name):
            if name == "pyzables::SomeDummy2":
                klass.test = 3

        cppjit.py.add_pythonization(pythonizor)

        assert cppjit.gbl.pyzables.SomeDummy2.test == 3

        cppjit.cppdef("""
            namespace pyzables {
                class TObjString {
                public:
                    std::string s;
                    TObjString(std::string ss) : s(ss) {}
                    size_t Sizeof() { return s.size() + 1; }
                };
            }
        """)

        def root_pythonizor(klass, name):
            if name == "pyzables::TObjString":
                klass.__len__ = klass.Sizeof

        cppjit.py.add_pythonization(root_pythonizor)

        assert len(cppjit.gbl.pyzables.TObjString("aap")) == 4  # include '\0'

    def test01_size_mapping(self):
        """Use composites to map GetSize() onto buffer returns"""

        import cppjit

        def set_size(self, buf):
            buf.reshape((self.GetN(),))
            return buf

        cppjit.py.add_pythonization(
            cppjit.py.compose_method("NakedBuffers$", "Get[XY]$", set_size), "pyzables"
        )

        bsize, xval, yval = 3, 2, 5
        m = cppjit.gbl.pyzables.NakedBuffers(bsize, xval, yval)

        x = m.GetX()
        assert len(x) == bsize
        assert list(x) == list(map(lambda x: x * xval, range(bsize)))

        y = m.GetY()
        assert len(y) == bsize
        assert list(y) == list(map(lambda x: x * yval, range(bsize)))

    def test02_size_mapping_of_templated_method(self):
        """Use composites to map GetSize() onto buffer returns"""

        import cppjit

        def set_size(self, buf):
            buf.reshape((self.GetN(),))
            return buf

        cppjit.py.add_pythonization(
            cppjit.py.compose_method("NakedBuffers2.*Vector.*", "Get[XY]$", set_size),
            "pyzables",
        )

        bsize, xval, yval = 3, 2, 5
        m = cppjit.gbl.pyzables.NakedBuffers2[cppjit.gbl.pyzables.Vector](
            bsize, xval, yval
        )

        x = m.GetX()
        assert len(x) == bsize
        assert list(x) == list(map(lambda x: x * xval, range(bsize)))

        y = m.GetY()
        assert len(y) == bsize
        assert list(y) == list(map(lambda x: x * yval, range(bsize)))

    def test03_type_pinning(self):
        """Verify pinnability of returns"""

        import cppjit

        cppjit.gbl.pyzables.GimeDerived.__creates__ = True

        result = cppjit.gbl.pyzables.GimeDerived()
        assert type(result) == cppjit.gbl.pyzables.MyDerived

        cppjit.py.pin_type(cppjit.gbl.pyzables.MyBase)
        assert type(result) == cppjit.gbl.pyzables.MyDerived

    def test04_transparency(self):
        """Transparent use of smart pointers"""

        import cppjit

        Countable = cppjit.gbl.pyzables.Countable
        mine = cppjit.gbl.pyzables.mine

        assert type(mine) == Countable
        assert mine.m_check == 0xCDCDCDCD
        assert type(mine.__smartptr__()) == cppjit.gbl.std.shared_ptr(Countable)
        assert mine.__smartptr__().get().m_check == 0xCDCDCDCD
        assert mine.say_hi() == "Hi!"

    @mark.xfail(
        run=False,
        condition=IS_VALGRIND and IS_LINUX_ARM and IS_CLANG_REPL,
        reason="Crashes on Valgind Clang-Repl-ARM",
    )
    def test05_converters(self):
        """Smart pointer argument passing"""

        import cppjit

        pz = cppjit.gbl.pyzables
        mine = pz.mine

        assert 0xCDCDCDCD == pz.pass_mine_rp_ptr(mine)
        assert 0xCDCDCDCD == pz.pass_mine_rp_ref(mine)
        assert 0xCDCDCDCD == pz.pass_mine_rp(mine)

        assert 0xCDCDCDCD == pz.pass_mine_sp_ptr(mine)
        assert 0xCDCDCDCD == pz.pass_mine_sp_ref(mine)

        assert 0xCDCDCDCD == pz.pass_mine_sp_ptr(mine.__smartptr__())
        assert 0xCDCDCDCD == pz.pass_mine_sp_ref(mine.__smartptr__())

        assert 0xCDCDCDCD == pz.pass_mine_sp(mine)
        assert 0xCDCDCDCD == pz.pass_mine_sp(mine.__smartptr__())

        # TODO:
        # cppjit.gbl.mine = mine
        pz.renew_mine()

    @mark.xfail(
        run=False,
        condition=IS_VALGRIND and IS_LINUX_ARM and IS_CLANG_REPL,
        reason="Fails with Valgrind with Clang-Repl ARM",
    )
    def test06_executors(self):
        """Smart pointer return types"""

        import cppjit

        pz = cppjit.gbl.pyzables
        Countable = pz.Countable

        mine = pz.gime_mine_ptr()
        assert type(mine) == Countable
        assert mine.m_check == 0xCDCDCDCD
        assert type(mine.__smartptr__()) == cppjit.gbl.std.shared_ptr(Countable)
        assert mine.__smartptr__().get().m_check == 0xCDCDCDCD
        assert mine.say_hi() == "Hi!"

        mine = pz.gime_mine_ref()
        assert type(mine) == Countable
        assert mine.m_check == 0xCDCDCDCD
        assert type(mine.__smartptr__()) == cppjit.gbl.std.shared_ptr(Countable)
        assert mine.__smartptr__().get().m_check == 0xCDCDCDCD
        assert mine.say_hi() == "Hi!"

        mine = pz.gime_mine()
        assert type(mine) == Countable
        assert mine.m_check == 0xCDCDCDCD
        assert type(mine.__smartptr__()) == cppjit.gbl.std.shared_ptr(Countable)
        assert mine.__smartptr__().get().m_check == 0xCDCDCDCD
        assert mine.say_hi() == "Hi!"

    def test07_creates_flag(self):
        """Effect of creates flag on return type"""

        import gc

        import cppjit

        pz = cppjit.gbl.pyzables
        Countable = pz.Countable

        gc.collect()
        oldcount = Countable.sInstances  # there's eg. one global variable

        pz.gime_naked_countable.__creates__ = True
        for i in range(10):
            cnt = pz.gime_naked_countable()
            gc.collect()
            assert Countable.sInstances == oldcount + 1
            del cnt
        gc.collect()

        assert Countable.sInstances == oldcount

    def test08_base_class_pythonization(self):
        """Derived class should not re-pythonize base class pythonization"""

        import cppjit

        d = cppjit.gbl.pyzables.IndexableDerived()

        assert d[0] == 42
        assert d[-1] == 42
        # skip the IndexErorr test: pythonization for __getitem__[index] < size()
        # can not be applied strict enough (instead of an index, this could be an
        # associative  container, with 'index' a key, not a counter
        # raises(IndexError, d.__getitem__, 1)

    @mark.xfail(condition=IS_MAC, reason="Fails on OS X")
    def test09_cpp_side_pythonization(self):
        """Use of C++ side pythonizations"""

        import cppjit

        # explicit pythonization
        for kls in [
            cppjit.gbl.pyzables.WithCallback1,
            cppjit.gbl.pyzables.WithCallback2,
        ]:
            w = kls(42)
            assert hasattr(w, "GetInt")
            assert not hasattr(w, "get_int")
            assert w.GetInt() == 42

            assert hasattr(w, "SetInt")
            assert not hasattr(w, "set_int")
            w.SetInt(17)
            assert w.GetInt() == 17

            assert kls.klass_name == kls.__cpp_name__

        # up-the-hierarchy pythonization
        w = cppjit.gbl.pyzables.WithCallback3(42)
        assert hasattr(w, "GetInt")
        assert not hasattr(w, "get_int")
        assert w.GetInt() == 2 * 42

        assert hasattr(w, "SetInt")
        assert not hasattr(w, "set_int")
        w.SetInt(17)
        assert w.GetInt() == 4 * 17

        assert cppjit.gbl.pyzables.WithCallback2.klass_name == "pyzables::WithCallback3"

    @mark.xfail(condition=IS_MAC, reason="Fails on OS X")
    def test10_shared_ptr_reset(self):
        """Checks that smart pointer types are Pythonized with the special
        __smartptr__ member that can also be used to reset the underlying smart
        pointer."""

        import cppjit

        optr = cppjit.gbl.std.make_shared["std::string"]("hello smart pointer")
        o2 = cppjit.gbl.std.string()
        cppjit._backend.SetOwnership(
            o2, False
        )  # This object will be owned by the smart pointer
        optr.__smartptr__().reset(o2)
        assert optr == o2


## actual test run
if __name__ == "__main__":
    result = run_pytest(__file__)  # noqa: F821
    sys.exit(result)

Web Proxy Viewer  |  New URL  |  Original Page