Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
_test_extension.c274 linesDownload Raw Back to tests
1/* This is a set of functions used by test_extension_interface.py to test the
2 * Greenlet C API.
3 */
4
5#include "../greenlet.h"
6
7#ifndef Py_RETURN_NONE
8#    define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
9#endif
10
11#define TEST_MODULE_NAME "_test_extension"
12
13// CAUTION: MSVC is stupidly picky:
14//
15// "The compiler ignores, without warning, any __declspec keywords
16// placed after * or & and in front of the variable identifier in a
17// declaration."
18// (https://docs.microsoft.com/en-us/cpp/cpp/declspec?view=msvc-160)
19//
20// So pointer return types must be handled differently (because of the
21// trailing *), or you get inscrutable compiler warnings like "error
22// C2059: syntax error: ''"
23//
24// In C23, there is a standard syntax for attributes, and
25// GCC defines an attribute to use with this: [[gnu:noinline]].
26// In the future, this is expected to become standard.
27
28#if defined(__GNUC__) || defined(__clang__)
29/* We used to check for GCC 4+ or 3.4+, but those compilers are
30   laughably out of date. Just assume they support it. */
31#    define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
32#elif defined(_MSC_VER)
33/* We used to check for  && (_MSC_VER >= 1300) but that's also out of date. */
34#    define UNUSED(x) UNUSED_ ## x
35#endif
36
37static PyObject*
38test_switch(PyObject* UNUSED(self), PyObject* greenlet)
39{
40    PyObject* result = NULL;
41
42    if (greenlet == NULL || !PyGreenlet_Check(greenlet)) {
43        PyErr_BadArgument();
44        return NULL;
45    }
46
47    result = PyGreenlet_Switch((PyGreenlet*)greenlet, NULL, NULL);
48    if (result == NULL) {
49        if (!PyErr_Occurred()) {
50            PyErr_SetString(PyExc_AssertionError,
51                            "greenlet.switch() failed for some reason.");
52        }
53        return NULL;
54    }
55    return result;
56}
57
58static PyObject*
59test_switch_kwargs(PyObject* UNUSED(self), PyObject* args, PyObject* kwargs)
60{
61    PyGreenlet* g = NULL;
62    PyObject* result = NULL;
63
64    if (!PyArg_ParseTuple(args, "O!", &PyGreenlet_Type, &g)) {
65        return NULL;
66    }
67
68    if (g == NULL || !PyGreenlet_Check(g)) {
69        PyErr_BadArgument();
70        return NULL;
71    }
72
73    result = PyGreenlet_Switch(g, NULL, kwargs);
74    if (result == NULL) {
75        if (!PyErr_Occurred()) {
76            PyErr_SetString(PyExc_AssertionError,
77                            "greenlet.switch() failed for some reason.");
78        }
79        return NULL;
80    }
81    return result;
82}
83
84static PyObject*
85test_getcurrent(PyObject* UNUSED(self))
86{
87    PyGreenlet* g = PyGreenlet_GetCurrent();
88    if (g == NULL || !PyGreenlet_Check(g) || !PyGreenlet_ACTIVE(g)) {
89        PyErr_SetString(PyExc_AssertionError,
90                        "getcurrent() returned an invalid greenlet");
91        Py_XDECREF(g);
92        return NULL;
93    }
94    Py_DECREF(g);
95    Py_RETURN_NONE;
96}
97
98static PyObject*
99test_setparent(PyObject* UNUSED(self), PyObject* arg)
100{
101    PyGreenlet* current;
102    PyGreenlet* greenlet = NULL;
103    PyObject* switch_result = NULL;
104
105    if (arg == NULL || !PyGreenlet_Check(arg)) {
106        PyErr_BadArgument();
107        return NULL;
108    }
109    if ((current = PyGreenlet_GetCurrent()) == NULL) {
110        return NULL;
111    }
112    greenlet = (PyGreenlet*)arg;
113    if (PyGreenlet_SetParent(greenlet, current)) {
114        Py_DECREF(current);
115        return NULL;
116    }
117    Py_DECREF(current);
118
119    switch_result = PyGreenlet_Switch(greenlet, NULL, NULL);
120    if (switch_result == NULL) {
121        return NULL;
122    }
123    Py_DECREF(switch_result);
124    Py_RETURN_NONE;
125}
126
127static PyObject*
128test_new_greenlet(PyObject* UNUSED(self), PyObject* callable)
129{
130    PyObject* result = NULL;
131    PyGreenlet* greenlet = PyGreenlet_New(callable, NULL);
132
133    if (!greenlet) {
134        return NULL;
135    }
136
137    result = PyGreenlet_Switch(greenlet, NULL, NULL);
138    Py_CLEAR(greenlet);
139    if (result == NULL) {
140        return NULL;
141    }
142
143    return result;
144}
145
146static PyObject*
147test_raise_dead_greenlet(PyObject* UNUSED(self))
148{
149    PyErr_SetString(PyExc_GreenletExit, "test GreenletExit exception.");
150    return NULL;
151}
152
153static PyObject*
154test_raise_greenlet_error(PyObject* UNUSED(self))
155{
156    PyErr_SetString(PyExc_GreenletError, "test greenlet.error exception");
157    return NULL;
158}
159
160static PyObject*
161test_throw(PyObject* UNUSED(self), PyGreenlet* g)
162{
163    const char msg[] = "take that sucka!";
164    PyObject* msg_obj = Py_BuildValue("s", msg);
165    PyGreenlet_Throw(g, PyExc_ValueError, msg_obj, NULL);
166    Py_DECREF(msg_obj);
167    if (PyErr_Occurred()) {
168        return NULL;
169    }
170    Py_RETURN_NONE;
171}
172
173static PyObject*
174test_throw_exact(PyObject* UNUSED(self), PyObject* args)
175{
176    PyGreenlet* g = NULL;
177    PyObject* typ = NULL;
178    PyObject* val = NULL;
179    PyObject* tb = NULL;
180
181    if (!PyArg_ParseTuple(args, "OOOO:throw", &g, &typ, &val, &tb)) {
182        return NULL;
183    }
184
185    PyGreenlet_Throw(g, typ, val, tb);
186    if (PyErr_Occurred()) {
187        return NULL;
188    }
189    Py_RETURN_NONE;
190}
191
192static PyObject*
193getcurrent_api(PyObject* UNUSED(self))
194{
195    return (PyObject*)PyGreenlet_GetCurrent();
196
197}
198
199static PyMethodDef test_methods[] = {
200    {"test_switch",
201     (PyCFunction)test_switch,
202     METH_O,
203     "Switch to the provided greenlet sending provided arguments, and \n"
204     "return the results."},
205    {"test_switch_kwargs",
206     (PyCFunction)test_switch_kwargs,
207     METH_VARARGS | METH_KEYWORDS,
208     "Switch to the provided greenlet sending the provided keyword args."},
209    {"test_getcurrent",
210     (PyCFunction)test_getcurrent,
211     METH_NOARGS,
212     "Test PyGreenlet_GetCurrent()"},
213    {"test_setparent",
214     (PyCFunction)test_setparent,
215     METH_O,
216     "Se the parent of the provided greenlet and switch to it."},
217    {"test_new_greenlet",
218     (PyCFunction)test_new_greenlet,
219     METH_O,
220     "Test PyGreenlet_New()"},
221    {"test_raise_dead_greenlet",
222     (PyCFunction)test_raise_dead_greenlet,
223     METH_NOARGS,
224     "Just raise greenlet.GreenletExit"},
225    {"test_raise_greenlet_error",
226     (PyCFunction)test_raise_greenlet_error,
227     METH_NOARGS,
228     "Just raise greenlet.error"},
229    {"test_throw",
230     (PyCFunction)test_throw,
231     METH_O,
232     "Throw a ValueError at the provided greenlet"},
233    {"test_throw_exact",
234     (PyCFunction)test_throw_exact,
235     METH_VARARGS,
236     "Throw exactly the arguments given at the provided greenlet"},
237    {
238        "getcurrent_api",
239        (PyCFunction)getcurrent_api,
240        METH_NOARGS,
241        "Direct call to the PyGreenlet_GetCurrent API."},
242    {NULL, NULL, 0, NULL}
243};
244
245
246#define INITERROR return NULL
247
248static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT,
249                                       TEST_MODULE_NAME,
250                                       NULL,
251                                       0,
252                                       test_methods,
253                                       NULL,
254                                       NULL,
255                                       NULL,
256                                       NULL};
257
258PyMODINIT_FUNC
259PyInit__test_extension(void)
260{
261    PyObject* module = NULL;
262    module = PyModule_Create(&moduledef);
263
264    if (module == NULL) {
265        return NULL;
266    }
267
268    PyGreenlet_Import();
269#ifdef Py_GIL_DISABLED
270    PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED);
271#endif
272    return module;
273}
274 
codekingpro/portable-devtools · Team Ai