File: test_crossing.py

package info (click to toggle)
pypy3 7.3.19%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 212,236 kB
  • sloc: python: 2,098,316; ansic: 540,565; sh: 21,462; asm: 14,419; cpp: 4,451; makefile: 4,209; objc: 761; xml: 530; exp: 499; javascript: 314; pascal: 244; lisp: 45; csh: 12; awk: 4
file content (191 lines) | stat: -rw-r--r-- 6,644 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
import py, os, sys
from .support import setup_make, soext

from pypy.interpreter.gateway import interp2app, unwrap_spec
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.translator import platform
from rpython.translator.gensupp import uniquemodulename
from rpython.tool.udir import udir

from pypy.module.cpyext import api
from pypy.module.cpyext.state import State

currpath = py.path.local(__file__).dirpath()
test_dct = str(currpath.join("crossingDict"))+soext

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


# from pypy/module/cpyext/test/test_cpyext.py; modified to accept more external
# symbols and called directly instead of import_module
def compile_extension_module(space, modname, **kwds):
    """
    Build an extension module and return the filename of the resulting native
    code file.

    modname is the name of the module, possibly including dots if it is a module
    inside a package.

    Any extra keyword arguments are passed on to ExternalCompilationInfo to
    build the module (so specify your source with one of those).
    """
    state = space.fromcache(State)
    api_library = state.api_lib
    if sys.platform == 'win32':
        kwds["libraries"] = []#[api_library]
        # '%s' undefined; assuming extern returning int
        kwds["compile_extra"] = ["/we4013"]
        # prevent linking with PythonXX.lib
        w_maj, w_min = space.fixedview(space.sys.get('version_info'), 5)[:2]
        kwds["link_extra"] = ["/NODEFAULTLIB:Python%d%d.lib" %
                              (space.int_w(w_maj), space.int_w(w_min))]
    elif sys.platform == 'darwin':
        kwds["link_files"] = [str(api_library + '.dylib')]
    else:
        kwds["link_files"] = [str(api_library + '.so')]
        if sys.platform.startswith('linux'):
            kwds["compile_extra"]=["-Werror", "-g", "-O0"]
            kwds["link_extra"]=["-g"]

    modname = modname.split('.')[-1]
    eci = ExternalCompilationInfo(
        include_dirs=api.include_dirs,
        **kwds
        )
    eci = eci.convert_sources_to_files()
    dirname = (udir/uniquemodulename('module')).ensure(dir=1)
    soname = platform.platform.compile(
        [], eci,
        outputfilename=str(dirname/modname),
        standalone=False)
    from pypy.module.imp.importing import get_so_extension
    pydname = soname.new(purebasename=modname, ext=get_so_extension(space))
    soname.rename(pydname)
    return str(pydname)

class AppTestCrossing:
    spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools'])

    def setup_class(cls):
        # _cppyy specific additions (note that test_dct is loaded late
        # to allow the generated extension module be loaded first)
        cls.w_test_dct    = cls.space.newtext(test_dct)
        cls.w_pre_imports = cls.space.appexec([], """():
            import ctypes, _cppyy
            _cppyy._post_import_startup()""")   # early import of ctypes
                  # prevents leak-checking complaints on ctypes' statics

    def setup_method(self, func):
        @unwrap_spec(name='text', init='text', body='text')
        def create_cdll(space, name, init, body):
            # the following is loosely from test_cpyext.py import_module; it
            # is copied here to be able to tweak the call to
            # compile_extension_module and to get a different return result
            # than in that function
            code = """
            #include <Python.h>
            /* fix for cpython 2.7 Python.h if running tests with -A
               since pypy compiles with -fvisibility-hidden */
            #undef PyMODINIT_FUNC
            #define PyMODINIT_FUNC RPY_EXPORTED void

            %(body)s

            PyMODINIT_FUNC
            #if PY_MAJOR_VERSION >= 3
            PyInit_%(name)s(void)
            #else
            init%(name)s(void) 
            #endif
            {
            %(init)s
            }
            """ % dict(name=name, init=init, body=body)
            kwds = dict(separate_module_sources=[code])
            mod = compile_extension_module(space, name, **kwds)

            # explicitly load the module as a CDLL rather than as a module
            from pypy.module.imp.importing import get_so_extension
            fullmodname = os.path.join(
                os.path.dirname(mod), name + get_so_extension(space))
            return space.newtext(fullmodname)

        self.w_create_cdll = self.space.wrap(interp2app(create_cdll))

    def test01_build_bar_extension(self):
        """Test that builds the needed extension; runs as test to keep it loaded"""

        import os, ctypes

        name = 'bar'

        init = """
        #if PY_MAJOR_VERSION >= 3
            static struct PyModuleDef moduledef = {
                PyModuleDef_HEAD_INIT,
                "bar", "Module Doc", -1, methods, NULL, NULL, NULL, NULL,
            };
        #endif

        if (Py_IsInitialized()) {
        #if PY_MAJOR_VERSION >= 3
            PyObject *module = PyModule_Create(&moduledef);
        #else
            Py_InitModule("bar", methods);
        #endif
        }
        """

        # note: only the symbols are needed for C, none for python
        body = """
        RPY_EXPORTED
        long bar_unwrap(PyObject* arg)
        {
            return 13;//PyLong_AsLong(arg);
        }
        RPY_EXPORTED
        PyObject* bar_wrap(long l)
        {
            return PyLong_FromLong(l);
        }
        static PyMethodDef methods[] = {
            { NULL }
        };
        """
        # explicitly load the module as a CDLL rather than as a module
        import ctypes
        self.cmodule = ctypes.CDLL(
            self.create_cdll(name, init, body), ctypes.RTLD_GLOBAL)

    def test02_crossing_dict(self):
        """Test availability of all needed classes in the dict"""

        import _cppyy, ctypes
        lib = ctypes.CDLL(self.test_dct, ctypes.RTLD_GLOBAL)

        assert _cppyy.gbl.crossing == _cppyy.gbl.crossing
        crossing = _cppyy.gbl.crossing

        assert crossing.A == crossing.A

    @py.test.mark.dont_track_allocations("fine when running standalone, though?!")
    def test03_send_pyobject(self):
        """Test sending a true pyobject to C++"""

        import _cppyy
        crossing = _cppyy.gbl.crossing

        a = crossing.A()
        assert a.unwrap(13) == 13

    @py.test.mark.dont_track_allocations("fine when running standalone, though?!")
    def test04_send_and_receive_pyobject(self):
        """Test receiving a true pyobject from C++"""

        import _cppyy
        crossing = _cppyy.gbl.crossing

        a = crossing.A()

        assert a.wrap(41) == 41