pycall 0.1.0.alpha.20170711 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +13 -1
  4. data/CHANGES.md +35 -0
  5. data/Gemfile +0 -5
  6. data/README.md +41 -49
  7. data/Rakefile +22 -1
  8. data/appveyor.yml +9 -26
  9. data/examples/classifier_comparison.rb +52 -52
  10. data/examples/hist.rb +11 -11
  11. data/examples/notebooks/classifier_comparison.ipynb +51 -66
  12. data/examples/notebooks/forest_importances.ipynb +26 -49
  13. data/examples/notebooks/iruby_integration.ipynb +15 -36
  14. data/examples/notebooks/lorenz_attractor.ipynb +16 -47
  15. data/examples/notebooks/polar_axes.ipynb +29 -64
  16. data/examples/notebooks/sum_benchmarking.ipynb +109 -103
  17. data/examples/notebooks/xkcd_style.ipynb +12 -12
  18. data/examples/plot_forest_importances_faces.rb +8 -8
  19. data/examples/sum_benchmarking.rb +15 -19
  20. data/ext/pycall/extconf.rb +3 -0
  21. data/ext/pycall/gc.c +74 -0
  22. data/ext/pycall/libpython.c +217 -0
  23. data/ext/pycall/pycall.c +2184 -0
  24. data/ext/pycall/pycall_internal.h +700 -0
  25. data/ext/pycall/range.c +69 -0
  26. data/ext/pycall/ruby_wrapper.c +432 -0
  27. data/lib/pycall.rb +91 -19
  28. data/lib/pycall/dict.rb +28 -82
  29. data/lib/pycall/error.rb +10 -0
  30. data/lib/pycall/import.rb +45 -40
  31. data/lib/pycall/init.rb +44 -20
  32. data/lib/pycall/libpython.rb +6 -380
  33. data/lib/pycall/libpython/finder.rb +170 -0
  34. data/lib/pycall/list.rb +21 -51
  35. data/lib/pycall/pretty_print.rb +9 -0
  36. data/lib/pycall/pyerror.rb +14 -20
  37. data/lib/pycall/pyobject_wrapper.rb +157 -158
  38. data/lib/pycall/python/PyCall/__init__.py +1 -0
  39. data/lib/pycall/python/PyCall/six.py +23 -0
  40. data/lib/pycall/pytypeobject_wrapper.rb +79 -0
  41. data/lib/pycall/slice.rb +3 -22
  42. data/lib/pycall/tuple.rb +1 -7
  43. data/lib/pycall/version.rb +1 -1
  44. data/lib/pycall/wrapper_object_cache.rb +61 -0
  45. data/pycall.gemspec +4 -2
  46. data/tasks/pycall.rake +7 -0
  47. metadata +65 -27
  48. data/lib/pycall/eval.rb +0 -57
  49. data/lib/pycall/exception.rb +0 -13
  50. data/lib/pycall/pyobject.rb +0 -58
  51. data/lib/pycall/ruby_wrapper.rb +0 -137
  52. data/lib/pycall/type_object.rb +0 -11
  53. data/lib/pycall/types.rb +0 -19
  54. data/lib/pycall/utils.rb +0 -106
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile('pycall')
data/ext/pycall/gc.c ADDED
@@ -0,0 +1,74 @@
1
+ #include "pycall_internal.h"
2
+
3
+ static ID id_gcguard_table;
4
+ static PyObject *weakref_callback_pyobj;
5
+ static PyObject *gcguard_weakref_destroyed(PyObject *self, PyObject *weakref);
6
+
7
+ PyMethodDef gcguard_weakref_callback_def = {
8
+ "_gcguard_weakref_destroyed", (PyCFunction) gcguard_weakref_destroyed, Py_METH_O
9
+ };
10
+
11
+ static PyObject *
12
+ gcguard_weakref_destroyed(PyObject *self, PyObject *weakref)
13
+ {
14
+ pycall_gcguard_delete(weakref);
15
+ Py_API(Py_DecRef)(weakref);
16
+
17
+ Py_API(Py_IncRef)(Py_API(_Py_NoneStruct));
18
+ return Py_API(_Py_NoneStruct);
19
+ }
20
+
21
+ void
22
+ pycall_gcguard_aset(PyObject *pyobj, VALUE rbobj)
23
+ {
24
+ VALUE table = rb_ivar_get(mPyCall, id_gcguard_table);
25
+ rb_hash_aset(table, PTR2NUM(pyobj), rbobj);
26
+ }
27
+
28
+ void
29
+ pycall_gcguard_delete(PyObject *pyobj)
30
+ {
31
+ VALUE table = rb_ivar_get(mPyCall, id_gcguard_table);
32
+ rb_hash_delete(table, PTR2NUM(pyobj));
33
+ }
34
+
35
+ void
36
+ pycall_gcguard_register_pyrubyobj(PyObject *pyobj)
37
+ {
38
+ VALUE rbobj;
39
+
40
+ if (!PyRuby_Check(pyobj)) {
41
+ rb_raise(rb_eTypeError, "wrong type of python object %s (expect PyCall.ruby_object)", Py_TYPE(pyobj)->tp_name);
42
+ }
43
+
44
+ rbobj = PyRuby_get_ruby_object(pyobj);
45
+ pycall_gcguard_aset(pyobj, rbobj);
46
+ }
47
+
48
+ void
49
+ pycall_gcguard_unregister_pyrubyobj(PyObject *pyobj)
50
+ {
51
+ if (!PyRuby_Check(pyobj)) {
52
+ rb_raise(rb_eTypeError, "wrong type of python object %s (expect PyCall.ruby_object)", Py_TYPE(pyobj)->tp_name);
53
+ }
54
+
55
+ pycall_gcguard_delete(pyobj);
56
+ }
57
+
58
+ void
59
+ pycall_gcguard_register(PyObject *pyobj, VALUE obj)
60
+ {
61
+ PyObject *wref;
62
+
63
+ wref = Py_API(PyWeakref_NewRef)(pyobj, weakref_callback_pyobj);
64
+ pycall_gcguard_aset(wref, obj);
65
+ }
66
+
67
+ void
68
+ pycall_init_gcguard(void)
69
+ {
70
+ id_gcguard_table = rb_intern("gcguard_table");
71
+ rb_ivar_set(mPyCall, id_gcguard_table, rb_hash_new());
72
+
73
+ weakref_callback_pyobj = Py_API(PyCFunction_NewEx)(&gcguard_weakref_callback_def, NULL, NULL);
74
+ }
@@ -0,0 +1,217 @@
1
+ #include "pycall_internal.h"
2
+
3
+ static pycall_libpython_api_table_t api_table = { NULL, };
4
+ static int python_string_as_bytes;
5
+
6
+ pycall_libpython_api_table_t *
7
+ pycall_libpython_api_table(void)
8
+ {
9
+ return &api_table;
10
+ }
11
+
12
+ struct lookup_libpython_api_args {
13
+ VALUE libpython_handle;
14
+ char const *name;
15
+ };
16
+
17
+ static VALUE
18
+ lookup_libpython_api_0(struct lookup_libpython_api_args *args)
19
+ {
20
+ return rb_funcall(args->libpython_handle, rb_intern("sym"), 1, rb_str_new2(args->name));
21
+ }
22
+
23
+ static void *
24
+ lookup_libpython_api(VALUE libpython_handle, char const *name)
25
+ {
26
+ struct lookup_libpython_api_args arg;
27
+ VALUE addr;
28
+ int state;
29
+
30
+ arg.libpython_handle = libpython_handle;
31
+ arg.name = name;
32
+ addr = rb_protect((VALUE (*)(VALUE))lookup_libpython_api_0, (VALUE)&arg, &state);
33
+ return (state || NIL_P(addr)) ? NULL : NUM2PTR(addr);
34
+ }
35
+
36
+ #define LOOKUP_API_ENTRY(api_name) lookup_libpython_api(libpython_handle, #api_name)
37
+ #define CHECK_API_ENTRY(api_name) (LOOKUP_API_ENTRY(api_name) != NULL)
38
+
39
+ #define required 1
40
+ #define optional 0
41
+
42
+ #define INIT_API_TABLE_ENTRY2(member_name, api_name, required) do { \
43
+ void *fptr = LOOKUP_API_ENTRY(api_name); \
44
+ if (!fptr && required) { \
45
+ rb_raise(eLibPythonFunctionNotFound, "Unable to find the required symbol in libpython: %s", #api_name); \
46
+ } \
47
+ (api_table.member_name) = fptr; \
48
+ } while (0)
49
+
50
+ #define INIT_API_TABLE_ENTRY(api_name, required) INIT_API_TABLE_ENTRY2(api_name, api_name, required)
51
+
52
+ #define INIT_API_TABLE_ENTRY_PTR(api_name, required) do { \
53
+ INIT_API_TABLE_ENTRY(api_name, required); \
54
+ (api_table.api_name) = *(void **)(api_table.api_name); \
55
+ } while (0)
56
+
57
+ void
58
+ pycall_init_libpython_api_table(VALUE libpython_handle)
59
+ {
60
+ VALUE eLibPythonFunctionNotFound = rb_const_get_at(pycall_mPyCall, rb_intern("LibPythonFunctionNotFound"));
61
+
62
+ INIT_API_TABLE_ENTRY(_Py_NoneStruct, required);
63
+
64
+ INIT_API_TABLE_ENTRY(PyBool_Type, required);
65
+ INIT_API_TABLE_ENTRY(PyClass_Type, optional);
66
+ INIT_API_TABLE_ENTRY(PyComplex_Type, required);
67
+ INIT_API_TABLE_ENTRY(PyDict_Type, required);
68
+ INIT_API_TABLE_ENTRY(PyFloat_Type, required);
69
+ INIT_API_TABLE_ENTRY(PyList_Type, required);
70
+ INIT_API_TABLE_ENTRY(PyInstance_Type, optional);
71
+ INIT_API_TABLE_ENTRY(PyInt_Type, optional);
72
+ INIT_API_TABLE_ENTRY(PyLong_Type, required);
73
+ INIT_API_TABLE_ENTRY(PyModule_Type, required);
74
+ python_string_as_bytes = !CHECK_API_ENTRY(PyString_Type);
75
+ if (python_string_as_bytes) {
76
+ INIT_API_TABLE_ENTRY2(PyString_Type, PyBytes_Type, required);
77
+ }
78
+ else {
79
+ INIT_API_TABLE_ENTRY(PyString_Type, required);
80
+ }
81
+ INIT_API_TABLE_ENTRY(PyTuple_Type, required);
82
+ INIT_API_TABLE_ENTRY(PyType_Type, required);
83
+ INIT_API_TABLE_ENTRY(PyUnicode_Type, required);
84
+
85
+ INIT_API_TABLE_ENTRY(Py_InitializeEx, required);
86
+ INIT_API_TABLE_ENTRY(Py_IsInitialized, required);
87
+ INIT_API_TABLE_ENTRY(Py_GetVersion, required);
88
+
89
+ INIT_API_TABLE_ENTRY(PySys_SetArgvEx, required);
90
+
91
+ INIT_API_TABLE_ENTRY(Py_IncRef, required);
92
+ INIT_API_TABLE_ENTRY(Py_DecRef, required);
93
+
94
+ INIT_API_TABLE_ENTRY(_PyObject_New, required);
95
+ INIT_API_TABLE_ENTRY(PyCallable_Check, required);
96
+ INIT_API_TABLE_ENTRY(PyObject_IsInstance, required);
97
+ INIT_API_TABLE_ENTRY2(PyObject_Hash._hash_t, PyObject_Hash, required);
98
+ INIT_API_TABLE_ENTRY(PyObject_RichCompare, required);
99
+ INIT_API_TABLE_ENTRY(PyObject_Call, required);
100
+ INIT_API_TABLE_ENTRY(PyObject_CallMethod, required);
101
+ INIT_API_TABLE_ENTRY(PyObject_Dir, required);
102
+ INIT_API_TABLE_ENTRY(PyObject_GenericGetAttr, required);
103
+ INIT_API_TABLE_ENTRY(PyObject_GetAttrString, required);
104
+ INIT_API_TABLE_ENTRY(PyObject_SetAttrString, required);
105
+ INIT_API_TABLE_ENTRY(PyObject_HasAttrString, required);
106
+ INIT_API_TABLE_ENTRY(PyObject_GetItem, required);
107
+ INIT_API_TABLE_ENTRY(PyObject_SetItem, required);
108
+ INIT_API_TABLE_ENTRY(PyObject_DelItem, required);
109
+ INIT_API_TABLE_ENTRY(PyObject_GetIter, required);
110
+ INIT_API_TABLE_ENTRY(PyObject_Str, required);
111
+ INIT_API_TABLE_ENTRY(PyObject_Repr, required);
112
+
113
+ INIT_API_TABLE_ENTRY(PyType_Ready, required);
114
+ INIT_API_TABLE_ENTRY(PyType_GenericNew, required);
115
+
116
+ INIT_API_TABLE_ENTRY(PyCFunction_NewEx, required);
117
+
118
+ INIT_API_TABLE_ENTRY(PyWeakref_NewRef, required);
119
+
120
+ INIT_API_TABLE_ENTRY(PyBool_FromLong, required);
121
+
122
+ INIT_API_TABLE_ENTRY(PyComplex_RealAsDouble, required);
123
+ INIT_API_TABLE_ENTRY(PyComplex_ImagAsDouble, required);
124
+ INIT_API_TABLE_ENTRY(PyComplex_FromDoubles, required);
125
+
126
+ INIT_API_TABLE_ENTRY(PyFloat_AsDouble, required);
127
+ INIT_API_TABLE_ENTRY(PyFloat_FromDouble, required);
128
+
129
+ INIT_API_TABLE_ENTRY(PyList_New, required);
130
+ INIT_API_TABLE_ENTRY(PyList_Size, required);
131
+ INIT_API_TABLE_ENTRY(PyList_GetItem, required);
132
+ INIT_API_TABLE_ENTRY(PyList_SetItem, required);
133
+ INIT_API_TABLE_ENTRY(PyList_Insert, required);
134
+ INIT_API_TABLE_ENTRY(PyList_Append, required);
135
+
136
+ INIT_API_TABLE_ENTRY(PyInt_FromLong, optional);
137
+ INIT_API_TABLE_ENTRY(PyInt_FromSsize_t, optional);
138
+ INIT_API_TABLE_ENTRY(PyInt_AsSsize_t, optional);
139
+
140
+ INIT_API_TABLE_ENTRY(PyLong_AsLongAndOverflow, required);
141
+ INIT_API_TABLE_ENTRY(PyLong_FromLong, required);
142
+ #ifdef HAVE_LONG_LONG
143
+ INIT_API_TABLE_ENTRY(PyLong_AsLongLongAndOverflow, required);
144
+ INIT_API_TABLE_ENTRY(PyLong_FromLongLong, required);
145
+ #endif
146
+ INIT_API_TABLE_ENTRY(PyLong_AsSsize_t, required);
147
+
148
+ INIT_API_TABLE_ENTRY(PyTuple_New, required);
149
+ INIT_API_TABLE_ENTRY(PyTuple_Size, required);
150
+ INIT_API_TABLE_ENTRY(PyTuple_GetItem, required);
151
+ INIT_API_TABLE_ENTRY(PyTuple_SetItem, required);
152
+
153
+ INIT_API_TABLE_ENTRY(PySlice_New, required);
154
+
155
+ INIT_API_TABLE_ENTRY(PyIter_Next, required);
156
+
157
+ INIT_API_TABLE_ENTRY(PyErr_Occurred, required);
158
+ INIT_API_TABLE_ENTRY(PyErr_Fetch, required);
159
+ INIT_API_TABLE_ENTRY(PyErr_Restore, required);
160
+ INIT_API_TABLE_ENTRY(PyErr_Clear, required);
161
+ INIT_API_TABLE_ENTRY(PyErr_SetString, required);
162
+ INIT_API_TABLE_ENTRY(PyErr_Format, required);
163
+
164
+ INIT_API_TABLE_ENTRY(PyImport_ImportModule, required);
165
+ INIT_API_TABLE_ENTRY(PyImport_ImportModuleLevel, required);
166
+
167
+ INIT_API_TABLE_ENTRY(PyOS_AfterFork, required);
168
+
169
+ INIT_API_TABLE_ENTRY(PyList_Size, required);
170
+ INIT_API_TABLE_ENTRY(PyList_GetItem, required);
171
+
172
+ INIT_API_TABLE_ENTRY(PyDict_New, required);
173
+ INIT_API_TABLE_ENTRY(PyDict_Contains, required);
174
+ INIT_API_TABLE_ENTRY(PyDict_SetItemString, required);
175
+ INIT_API_TABLE_ENTRY(PyDict_Next, required);
176
+
177
+ INIT_API_TABLE_ENTRY(PySequence_Check, required);
178
+ INIT_API_TABLE_ENTRY(PySequence_Size, required);
179
+ INIT_API_TABLE_ENTRY(PySequence_Contains, required);
180
+ INIT_API_TABLE_ENTRY(PySequence_GetItem, required);
181
+
182
+ if (python_string_as_bytes) {
183
+ INIT_API_TABLE_ENTRY2(PyString_AsStringAndSize, PyBytes_AsStringAndSize, required);
184
+ INIT_API_TABLE_ENTRY2(PyString_FromStringAndSize, PyBytes_FromStringAndSize, required);
185
+ INIT_API_TABLE_ENTRY2(PyString_FromFormatV, PyBytes_FromFormat, required);
186
+ }
187
+ else {
188
+ INIT_API_TABLE_ENTRY(PyString_AsStringAndSize, required);
189
+ INIT_API_TABLE_ENTRY(PyString_FromStringAndSize, required);
190
+ INIT_API_TABLE_ENTRY(PyString_FromFormatV, required);
191
+ }
192
+
193
+ if (CHECK_API_ENTRY(PyUnicode_DecodeUTF8)) {
194
+ INIT_API_TABLE_ENTRY(PyUnicode_AsUTF8String, required);
195
+ INIT_API_TABLE_ENTRY(PyUnicode_DecodeUTF8, required);
196
+ INIT_API_TABLE_ENTRY(PyUnicode_FromFormatV, required);
197
+ }
198
+ else if (CHECK_API_ENTRY(PyUnicodeUCS4_DecodeUTF8)) {
199
+ INIT_API_TABLE_ENTRY2(PyUnicode_AsUTF8String, PyUnicodeUCS4_AsUTF8String, required);
200
+ INIT_API_TABLE_ENTRY2(PyUnicode_DecodeUTF8, PyUnicodeUCS4_DecodeUTF8, required);
201
+ INIT_API_TABLE_ENTRY2(PyUnicode_FromFormatV, PyUnicodeUCS4_FromFormatV, required);
202
+ }
203
+ else if (CHECK_API_ENTRY(PyUnicodeUCS2_DecodeUTF8)) {
204
+ INIT_API_TABLE_ENTRY2(PyUnicode_AsUTF8String, PyUnicodeUCS2_AsUTF8String, required);
205
+ INIT_API_TABLE_ENTRY2(PyUnicode_DecodeUTF8, PyUnicodeUCS2_DecodeUTF8, required);
206
+ INIT_API_TABLE_ENTRY2(PyUnicode_FromFormatV, PyUnicodeUCS2_FromFormatV, required);
207
+ }
208
+ }
209
+
210
+ void
211
+ pycall_init_exceptions(VALUE libpython_handle)
212
+ {
213
+ VALUE eLibPythonFunctionNotFound = rb_const_get_at(pycall_mPyCall, rb_intern("LibPythonFunctionNotFound"));
214
+
215
+ INIT_API_TABLE_ENTRY_PTR(PyExc_RuntimeError, required);
216
+ INIT_API_TABLE_ENTRY_PTR(PyExc_TypeError, required);
217
+ }
@@ -0,0 +1,2184 @@
1
+ #include "pycall_internal.h"
2
+
3
+ #include <stdarg.h>
4
+
5
+ VALUE pycall_mPyCall;
6
+
7
+ VALUE mLibPython;
8
+ VALUE mAPI;
9
+ VALUE mHelpers;
10
+ VALUE mConversion;
11
+ VALUE mPyObjectWrapper;
12
+ VALUE mPyTypeObjectWrapper;
13
+ VALUE mGCGuard;
14
+
15
+ VALUE pycall_cPyPtr;
16
+ VALUE cPyTypePtr;
17
+ VALUE cTuple;
18
+ VALUE cPyError;
19
+
20
+ VALUE pycall_eError;
21
+
22
+ static VALUE pycall_libpython_handle;
23
+ static VALUE python_description;
24
+ static VALUE python_version_string;
25
+ static Py_ssize_t python_hexversion;
26
+ static int python_major_version;
27
+ static int python_has_stackless_extension;
28
+ static PyObject *python_builtins_module;
29
+ static VALUE python_type_mapping;
30
+ static VALUE python_type_mapping;
31
+ static ID id_python_type_mapping;
32
+
33
+ int
34
+ pycall_python_major_version(void)
35
+ {
36
+ return python_major_version;
37
+ }
38
+
39
+ Py_ssize_t
40
+ pycall_python_hexversion(void)
41
+ {
42
+ return python_hexversion;
43
+ }
44
+
45
+ #undef pycall_python_major_version
46
+ #define pycall_python_major_version() python_major_version
47
+
48
+ #undef pycall_python_hexversion
49
+ #define pycall_python_hexversion() python_hexversion
50
+
51
+ #define python_is_unicode_literals (python_major_version >= 3)
52
+
53
+ long pycall_hash_salt;
54
+
55
+ static VALUE pycall_call_python_callable(PyObject *pycallable, int argc, VALUE *argv);
56
+
57
+ #define PyType_Check(pyobj) PyType_FastSubclass(Py_TYPE(pyobj), Py_TPFLAGS_TYPE_SUBCLASS)
58
+ #define PyClass_Check(pyobj) (Py_API(PyClass_Type) && (pyobj)->ob_type == Py_API(PyClass_Type))
59
+
60
+ #define PyObject_Hash(pyobj) (pycall_python_long_hash ? Py_API(PyObject_Hash._long)(pyobj) : Py_API(PyObject_Hash._hash_t)(pyobj))
61
+
62
+ /* ==== PyCall ==== */
63
+
64
+ VALUE
65
+ pycall_after_fork(VALUE mod)
66
+ {
67
+ Py_API(PyOS_AfterFork)();
68
+ return Qnil;
69
+ }
70
+
71
+ /* ==== PyCall::PyPtr ==== */
72
+
73
+ const rb_data_type_t pycall_pyptr_data_type = {
74
+ "PyCall::PyPtr",
75
+ { 0, pycall_pyptr_free, pycall_pyptr_memsize, },
76
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
77
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
78
+ #endif
79
+ };
80
+
81
+ void
82
+ pycall_pyptr_free(void *ptr)
83
+ {
84
+ PyObject *pyobj = ptr;
85
+ #ifdef PYCALL_DEBUG_DUMP_REFCNT
86
+ if (pyobj->ob_refcnt == 0) {
87
+ fprintf(stderr, "zero refcnt object %p of type %s\n", pyobj, Py_TYPE(pyobj)->tp_name);
88
+ }
89
+ #endif /* PYCALL_DEBUG_DUMP_REFCNT */
90
+ pycall_Py_DecRef(pyobj);
91
+ }
92
+
93
+ static size_t _PySys_GetSizeOf(PyObject *);
94
+
95
+ size_t
96
+ pycall_pyptr_memsize(void const *ptr)
97
+ {
98
+ if (ptr)
99
+ return _PySys_GetSizeOf((PyObject *)ptr);
100
+
101
+ return 0;
102
+ }
103
+
104
+ static size_t
105
+ _PySys_GetSizeOf(PyObject *o)
106
+ {
107
+ PyObject *res = NULL;
108
+ Py_ssize_t size;
109
+
110
+ if (Py_API(PyType_Ready)(Py_TYPE(o)) < 0)
111
+ return (size_t)-1;
112
+
113
+ res = Py_API(PyObject_CallMethod)(o, "__sizeof__", "");
114
+ if (res == NULL)
115
+ return (size_t)-1;
116
+
117
+ size = Py_API(PyLong_AsSsize_t)(res);
118
+ pycall_Py_DecRef(res);
119
+ if (size == -1 && Py_API(PyErr_Occurred)())
120
+ return (size_t)-1;
121
+
122
+ if (size < 0)
123
+ return (size_t)-1;
124
+
125
+ if (PyObject_IS_GC(o)) {
126
+ size += sizeof(PyGC_Head);
127
+ }
128
+ return (size_t)size;
129
+ }
130
+
131
+ static inline int
132
+ is_pycall_pyptr(VALUE obj)
133
+ {
134
+ return rb_typeddata_is_kind_of(obj, &pycall_pyptr_data_type);
135
+ }
136
+
137
+ static inline PyObject*
138
+ get_pyobj_ptr(VALUE obj)
139
+ {
140
+ PyObject *pyobj;
141
+ TypedData_Get_Struct(obj, PyObject, &pycall_pyptr_data_type, pyobj);
142
+ return pyobj;
143
+ }
144
+
145
+ static inline PyObject*
146
+ try_get_pyobj_ptr(VALUE obj)
147
+ {
148
+ if (!is_pycall_pyptr(obj)) return NULL;
149
+ return (PyObject*)DATA_PTR(obj);
150
+ }
151
+
152
+ static inline PyObject *
153
+ check_get_pyobj_ptr(VALUE obj, PyTypeObject *pytypeobj)
154
+ {
155
+ PyObject *pyobj;
156
+
157
+ if (!is_pycall_pyptr(obj))
158
+ rb_raise(rb_eTypeError, "unexpected type %s (expected PyCall::PyPtr)", rb_class2name(CLASS_OF(obj)));
159
+
160
+ pyobj = get_pyobj_ptr(obj);
161
+ if (pytypeobj && Py_TYPE(pyobj) != pytypeobj)
162
+ rb_raise(rb_eTypeError, "unexpected Python type %s (expected %s)", Py_TYPE(pyobj)->tp_name, pytypeobj->tp_name);
163
+
164
+ return pyobj;
165
+ }
166
+
167
+ VALUE
168
+ pycall_pyptr_incref(VALUE pyptr)
169
+ {
170
+ PyObject *pyobj;
171
+
172
+ pyobj = try_get_pyobj_ptr(pyptr);
173
+ if (pyobj)
174
+ Py_API(Py_IncRef)(pyobj);
175
+ return pyptr;
176
+ }
177
+
178
+ static VALUE
179
+ pycall_pyptr_s_incref(VALUE klass, VALUE pyptr)
180
+ {
181
+ return pycall_pyptr_incref(pyptr);
182
+ }
183
+
184
+ void
185
+ pycall_Py_DecRef(PyObject *pyobj)
186
+ {
187
+ #ifdef PYCALL_DEBUG_DUMP_REFCNT
188
+ fprintf(stderr, "decref object %p of type %s, refcnt %"PRIdSIZE"\n",
189
+ pyobj,
190
+ pyobj ? Py_TYPE(pyobj)->tp_name : "nullptr",
191
+ pyobj ? pyobj->ob_refcnt : -1);
192
+ #endif /* PYCALL_DEBUG_DUMP_REFCNT */
193
+ Py_API(Py_DecRef)(pyobj);
194
+ }
195
+
196
+ VALUE
197
+ pycall_pyptr_decref(VALUE pyptr)
198
+ {
199
+ PyObject *pyobj;
200
+
201
+ pyobj = try_get_pyobj_ptr(pyptr);
202
+ if (pyobj) {
203
+ pycall_Py_DecRef(pyobj);
204
+ DATA_PTR(pyptr) = NULL;
205
+ }
206
+ return pyptr;
207
+ }
208
+
209
+ static VALUE
210
+ pycall_pyptr_s_decref(VALUE klass, VALUE pyptr)
211
+ {
212
+ return pycall_pyptr_decref(pyptr);
213
+ }
214
+
215
+ static VALUE
216
+ pycall_pyptr_s_sizeof(VALUE klass, VALUE pyptr)
217
+ {
218
+ size_t size;
219
+ PyObject *pyobj;
220
+
221
+ pyobj = try_get_pyobj_ptr(pyptr);
222
+ if (pyobj == NULL) return Qnil;
223
+
224
+ size = _PySys_GetSizeOf(pyobj);
225
+ return SIZET2NUM(size);
226
+ }
227
+
228
+ static VALUE
229
+ pycall_pyptr_allocate(VALUE klass)
230
+ {
231
+ return TypedData_Wrap_Struct(klass, &pycall_pyptr_data_type, NULL);
232
+ }
233
+
234
+ static inline VALUE
235
+ pycall_pyptr_new_with_klass(VALUE klass, PyObject *pyobj)
236
+ {
237
+ VALUE obj = pycall_pyptr_allocate(klass);
238
+ DATA_PTR(obj) = pyobj;
239
+ #ifdef PYCALL_DEBUG_DUMP_REFCNT
240
+ fprintf(stderr, "%s: object %p of type %s, refcnt=%"PRIdSIZE" (%s:%d)\n",
241
+ rb_class2name(klass), pyobj,
242
+ (pyobj ? Py_TYPE(pyobj)->tp_name : "(nullptr)"),
243
+ (pyobj ? pyobj->ob_refcnt : -1),
244
+ rb_sourcefile(), rb_sourceline());
245
+ #endif /* PYCALL_DEBUG_DUMP_REFCNT */
246
+ return obj;
247
+ }
248
+
249
+ VALUE
250
+ pycall_pyptr_new(PyObject *pyobj)
251
+ {
252
+ return pycall_pyptr_new_with_klass(cPyPtr, pyobj);
253
+ }
254
+
255
+ static VALUE
256
+ pycall_pyptr_initialize(VALUE pyptr, VALUE val)
257
+ {
258
+ VALUE addr;
259
+ PyObject *pyobj;
260
+
261
+ addr = rb_check_to_integer(val, "to_int");
262
+ if (NIL_P(addr)) {
263
+ rb_raise(rb_eTypeError, "Invalid PyObject address: %"PRIsVALUE, val);
264
+ }
265
+
266
+ pyobj = (PyObject *)NUM2PTR(addr);
267
+ DATA_PTR(pyptr) = pyobj;
268
+ return pyptr;
269
+ }
270
+
271
+ static VALUE
272
+ pycall_pyptr_is_null(VALUE obj)
273
+ {
274
+ PyObject* pyobj = get_pyobj_ptr(obj);
275
+ return pyobj ? Qfalse : Qtrue;
276
+ }
277
+
278
+ static VALUE
279
+ pycall_pyptr_is_none(VALUE obj)
280
+ {
281
+ PyObject* pyobj = get_pyobj_ptr(obj);
282
+ return pyobj == Py_API(_Py_NoneStruct) ? Qtrue : Qfalse;
283
+ }
284
+
285
+ static VALUE
286
+ pycall_pyptr_is_nil(VALUE obj)
287
+ {
288
+ PyObject* pyobj = get_pyobj_ptr(obj);
289
+ return (pyobj == Py_API(_Py_NoneStruct)) || (pyobj == NULL) ? Qtrue : Qfalse;
290
+ }
291
+
292
+ static VALUE
293
+ pycall_pyptr_eq(VALUE obj, VALUE other)
294
+ {
295
+ PyObject* pyobj;
296
+ PyObject* pyobj_other;
297
+
298
+ if (!is_pycall_pyptr(other)) return Qfalse;
299
+
300
+ pyobj = get_pyobj_ptr(obj);
301
+ pyobj_other = get_pyobj_ptr(other);
302
+
303
+ return pyobj == pyobj_other ? Qtrue : Qfalse;
304
+ }
305
+
306
+ static VALUE
307
+ pycall_pyptr_get_ptr_address(VALUE obj)
308
+ {
309
+ PyObject* pyobj = get_pyobj_ptr(obj);
310
+ return PTR2NUM(pyobj);
311
+ }
312
+
313
+ static VALUE
314
+ pycall_pyptr_get_ob_refcnt(VALUE obj)
315
+ {
316
+ PyObject* pyobj = get_pyobj_ptr(obj);
317
+ if (pyobj)
318
+ return SSIZET2NUM(pyobj->ob_refcnt);
319
+ return Qnil;
320
+ }
321
+
322
+ VALUE pycall_pytypeptr_new(PyObject *pytype);
323
+
324
+ static VALUE
325
+ pycall_pyptr_get_ob_type(VALUE obj)
326
+ {
327
+ PyObject* pyobj = get_pyobj_ptr(obj);
328
+ if (pyobj) {
329
+ VALUE res;
330
+ if (Py_TYPE(pyobj) == Py_API(PyInstance_Type))
331
+ res = pycall_pytype_to_ruby((PyObject *)((PyInstanceObject *)pyobj)->in_class);
332
+ else
333
+ res = pycall_pytype_to_ruby((PyObject *)pyobj->ob_type);
334
+ return res;
335
+ }
336
+ return Qnil;
337
+ }
338
+
339
+ static VALUE
340
+ pycall_pyptr_object_id(VALUE obj)
341
+ {
342
+ return rb_obj_id(obj);
343
+ }
344
+
345
+ static VALUE
346
+ pycall_pyptr_class(VALUE obj)
347
+ {
348
+ return CLASS_OF(obj);
349
+ }
350
+
351
+ static VALUE
352
+ pycall_pyptr_inspect(VALUE obj)
353
+ {
354
+ VALUE cname, str;
355
+ PyObject* pyobj = get_pyobj_ptr(obj);
356
+
357
+ cname = rb_class_name(CLASS_OF(obj));
358
+ str = rb_sprintf("#<%"PRIsVALUE":%p type=%s addr=%p>", cname, (void*)obj, Py_TYPE(pyobj)->tp_name, pyobj);
359
+ OBJ_INFECT(str, obj);
360
+
361
+ return str;
362
+ }
363
+
364
+ static VALUE
365
+ class_or_module_required(VALUE klass)
366
+ {
367
+ if (SPECIAL_CONST_P(klass)) goto not_class;
368
+ switch (BUILTIN_TYPE(klass)) {
369
+ case T_MODULE:
370
+ case T_CLASS:
371
+ case T_ICLASS:
372
+ break;
373
+
374
+ default:
375
+ not_class:
376
+ rb_raise(rb_eTypeError, "class or module required");
377
+ }
378
+ return klass;
379
+ }
380
+
381
+ static VALUE
382
+ pycall_pyptr_is_kind_of(VALUE obj, VALUE klass)
383
+ {
384
+ PyObject* pyobj = get_pyobj_ptr(obj);
385
+ VALUE res;
386
+
387
+ if (is_pycall_pyptr(klass)) {
388
+ int res;
389
+ PyObject* pyobj_klass = get_pyobj_ptr(klass);
390
+ res = Py_API(PyObject_IsInstance)(pyobj, pyobj_klass);
391
+ if (res >= 0) {
392
+ return res ? Qtrue : Qfalse;
393
+ }
394
+ Py_API(PyErr_Clear)();
395
+ }
396
+
397
+ klass = class_or_module_required(klass);
398
+ res = rb_class_inherited_p(CLASS_OF(obj), klass);
399
+ return NIL_P(res) ? Qfalse : res;
400
+ }
401
+
402
+ static VALUE
403
+ pycall_pyptr_hash(VALUE obj)
404
+ {
405
+ PyObject *pyobj = get_pyobj_ptr(obj);
406
+ Py_hash_t h;
407
+
408
+ if (!pyobj)
409
+ return PTR2NUM(pyobj);
410
+
411
+ h = PyObject_Hash(pyobj);
412
+ if (h == -1) {
413
+ Py_API(PyErr_Clear)();
414
+ return PTR2NUM(pyobj);
415
+ }
416
+
417
+ return SSIZET2NUM(h);
418
+ }
419
+
420
+ /* ==== PyTypePtr ==== */
421
+
422
+ const rb_data_type_t pycall_pytypeptr_data_type = {
423
+ "PyCall::PyTypePtr",
424
+ { 0, pycall_pyptr_free, pycall_pyptr_memsize, },
425
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
426
+ &pycall_pyptr_data_type, 0, RUBY_TYPED_FREE_IMMEDIATELY
427
+ #endif
428
+ };
429
+
430
+ static inline int
431
+ is_pycall_pytypeptr(VALUE obj)
432
+ {
433
+ return rb_typeddata_is_kind_of(obj, &pycall_pytypeptr_data_type);
434
+ }
435
+
436
+ static inline PyTypeObject*
437
+ get_pytypeobj_ptr(VALUE obj)
438
+ {
439
+ PyTypeObject *pytype;
440
+ TypedData_Get_Struct(obj, PyTypeObject, &pycall_pytypeptr_data_type, pytype);
441
+ return pytype;
442
+ }
443
+
444
+ static inline PyTypeObject*
445
+ try_get_pytypeobj_ptr(VALUE obj)
446
+ {
447
+ if (is_pycall_pytypeptr(obj)) return NULL;
448
+ return (PyTypeObject*)DATA_PTR(obj);
449
+ }
450
+
451
+ static inline PyTypeObject *
452
+ check_get_pytypeobj_ptr(VALUE obj)
453
+ {
454
+ PyTypeObject *pytypeobj;
455
+ if (!is_pycall_pytypeptr(obj))
456
+ rb_raise(rb_eTypeError, "unexpected type %s (expected PyCall::PyTypePtr)", rb_class2name(CLASS_OF(obj)));
457
+
458
+ pytypeobj = get_pytypeobj_ptr(obj);
459
+ if (!PyType_Check(pytypeobj))
460
+ rb_raise(rb_eTypeError, "unexpected Python type %s (expected type or class)", Py_TYPE(pytypeobj)->tp_name);
461
+
462
+ return pytypeobj;
463
+ }
464
+
465
+ static VALUE
466
+ pycall_pytypeptr_allocate(VALUE klass)
467
+ {
468
+ return TypedData_Wrap_Struct(klass, &pycall_pytypeptr_data_type, NULL);
469
+ }
470
+
471
+ static inline VALUE
472
+ pycall_pytypeptr_new_with_klass(VALUE klass, PyObject *pytypeobj)
473
+ {
474
+ VALUE obj = pycall_pytypeptr_allocate(klass);
475
+ DATA_PTR(obj) = pytypeobj;
476
+ return obj;
477
+ }
478
+
479
+ VALUE
480
+ pycall_pytypeptr_new(PyObject *pytypeobj)
481
+ {
482
+ return pycall_pytypeptr_new_with_klass(cPyTypePtr, pytypeobj);
483
+ }
484
+
485
+ static VALUE
486
+ pycall_pytypeptr_get_ob_size(VALUE obj)
487
+ {
488
+ PyTypeObject* pytype = get_pytypeobj_ptr(obj);
489
+ if (pytype)
490
+ return SSIZET2NUM(pytype->ob_size);
491
+ return Qnil;
492
+ }
493
+
494
+ static VALUE
495
+ pycall_pytypeptr_get_tp_name(VALUE obj)
496
+ {
497
+ PyTypeObject* pytype = get_pytypeobj_ptr(obj);
498
+ if (pytype) {
499
+ if (Py_TYPE(pytype) == Py_API(PyType_Type))
500
+ return rb_str_new2(pytype->tp_name);
501
+ return pycall_pyobject_to_ruby(((PyClassObject *)pytype)->cl_name);
502
+ }
503
+ return Qnil;
504
+ }
505
+
506
+ static VALUE
507
+ pycall_pytypeptr_get_tp_basicsize(VALUE obj)
508
+ {
509
+ PyTypeObject* pytype = get_pytypeobj_ptr(obj);
510
+ if (pytype) {
511
+ if (Py_TYPE(pytype) == Py_API(PyType_Type))
512
+ return SSIZET2NUM(pytype->tp_basicsize);
513
+ }
514
+ return Qnil;
515
+ }
516
+
517
+ static VALUE
518
+ pycall_pytypeptr_get_tp_flags(VALUE obj)
519
+ {
520
+ PyTypeObject* pytype = get_pytypeobj_ptr(obj);
521
+ if (pytype) {
522
+ if (Py_TYPE(pytype) == Py_API(PyType_Type))
523
+ return ULONG2NUM(pytype->tp_flags);
524
+ }
525
+ return Qnil;
526
+ }
527
+
528
+ static VALUE
529
+ pycall_pytypeptr_eqq(VALUE obj, VALUE other)
530
+ {
531
+ if (is_pycall_pyptr(other))
532
+ return pycall_pyptr_is_kind_of(other, obj);
533
+ return Qfalse;
534
+ }
535
+
536
+ /* ==== PyCall::LibPython::API ==== */
537
+
538
+ static VALUE
539
+ pycall_libpython_api_get_builtins_module_ptr(VALUE mod)
540
+ {
541
+ VALUE pyptr = pycall_pyptr_new(python_builtins_module);
542
+ Py_API(Py_IncRef)(python_builtins_module);
543
+ return pyptr;
544
+ }
545
+
546
+ static VALUE
547
+ pycall_libpython_api_PyObject_Dir(VALUE mod, VALUE pyptr)
548
+ {
549
+ PyObject *dir;
550
+ PyObject *pyobj;
551
+
552
+ if (!is_pycall_pyptr(pyptr)) {
553
+ rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
554
+ }
555
+
556
+ pyobj = get_pyobj_ptr(pyptr);
557
+ dir = Py_API(PyObject_Dir)(pyobj);
558
+ if (pyobj && !dir) {
559
+ pycall_pyerror_fetch_and_raise("PyObject_Dir in pycall_libpython_api_PyObject_Dir");
560
+ }
561
+
562
+ return dir ? pycall_pyptr_new(dir) : Qnil;
563
+ }
564
+
565
+ static VALUE
566
+ pycall_libpython_api_PyList_Size(VALUE mod, VALUE pyptr)
567
+ {
568
+ PyObject *pyobj;
569
+ Py_ssize_t size;
570
+
571
+ if (!is_pycall_pyptr(pyptr)) {
572
+ rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
573
+ }
574
+
575
+ pyobj = get_pyobj_ptr(pyptr);
576
+ size = Py_API(PyList_Size)(pyobj);
577
+ if (size < 0) {
578
+ pycall_pyerror_fetch_and_raise("PyList_Size in pycall_libpython_api_PyList_Size");
579
+ }
580
+
581
+ return SSIZET2NUM(size);
582
+ }
583
+
584
+ static VALUE
585
+ pycall_libpython_api_PyList_GetItem(VALUE mod, VALUE pyptr, VALUE idx)
586
+ {
587
+ PyObject *pyobj;
588
+ PyObject *pyobj_item;
589
+ Py_ssize_t i;
590
+
591
+ if (!is_pycall_pyptr(pyptr)) {
592
+ rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
593
+ }
594
+
595
+ pyobj = get_pyobj_ptr(pyptr);
596
+ i = NUM2SSIZET(idx);
597
+ pyobj_item = Py_API(PyList_GetItem)(pyobj, i);
598
+ if (!pyobj_item) {
599
+ pycall_pyerror_fetch_and_raise("PyList_GetItem in pycall_libpython_api_PyList_GetItem");
600
+ }
601
+
602
+ return pycall_pyptr_new(pyobj_item);
603
+ }
604
+
605
+ /* ==== PyCall::Helpers ==== */
606
+
607
+ static VALUE
608
+ pycall_libpython_helpers_m_unicode_literals_p(VALUE mod)
609
+ {
610
+ return python_is_unicode_literals ? Qtrue : Qfalse;
611
+ }
612
+
613
+ VALUE
614
+ pycall_import_module(char const *name)
615
+ {
616
+ PyObject *pymod = Py_API(PyImport_ImportModule)(name);
617
+ if (!pymod) {
618
+ pycall_pyerror_fetch_and_raise("PyImport_ImportModule in pycall_libpython_helpers_m_import_module");
619
+ }
620
+ return pycall_pyobject_to_ruby(pymod);
621
+ }
622
+
623
+ VALUE
624
+ pycall_import_module_level(char const *name, VALUE globals, VALUE locals, VALUE fromlist, int level)
625
+ {
626
+ PyObject *pyglobals = NULL, *pylocals = NULL, *pyfromlist = NULL, *pymod;
627
+
628
+ if (!NIL_P(globals)) {
629
+ pyglobals = check_get_pyobj_ptr(globals, Py_API(PyDict_Type));
630
+ }
631
+ if (!NIL_P(locals)) {
632
+ pylocals = check_get_pyobj_ptr(locals, Py_API(PyDict_Type));
633
+ }
634
+ if (!NIL_P(fromlist)) {
635
+ fromlist = rb_convert_type(fromlist, T_ARRAY, "Array", "to_ary");
636
+ pyfromlist = pycall_pyobject_from_ruby(fromlist);
637
+ }
638
+ else {
639
+ /* TODO: set the default fromlist to ['*'] */
640
+ }
641
+
642
+ pymod = Py_API(PyImport_ImportModuleLevel)(name, pyglobals, pylocals, pyfromlist, level);
643
+ if (!pymod) {
644
+ pycall_pyerror_fetch_and_raise("PyImport_ImportModuleLevel in pycall_libpython_helpers_m_import_module");
645
+ }
646
+
647
+ return pycall_pyobject_to_ruby(pymod);
648
+ }
649
+
650
+ static VALUE
651
+ pycall_libpython_helpers_m_import_module(int argc, VALUE *argv, VALUE mod)
652
+ {
653
+ VALUE name, globals, locals, fromlist, level;
654
+ char const *name_cstr;
655
+
656
+ rb_scan_args(argc, argv, "14", &name, &globals, &locals, &fromlist, &level);
657
+
658
+ if (RB_TYPE_P(name, T_SYMBOL)) {
659
+ name = rb_sym_to_s(name);
660
+ }
661
+
662
+ name_cstr = StringValueCStr(name);
663
+
664
+ if (argc == 1) {
665
+ return pycall_import_module(name_cstr);
666
+ }
667
+
668
+ if (argc == 5) {
669
+ level = rb_check_to_integer(level, "to_int");
670
+ }
671
+ else {
672
+ /* TODO: set the default level to 0 */
673
+ }
674
+
675
+ return pycall_import_module_level(name_cstr, globals, locals, fromlist, NUM2INT(level));
676
+ }
677
+
678
+ static int
679
+ pycall_rich_compare_opid(VALUE op)
680
+ {
681
+ ID rb_opid;
682
+
683
+ Check_Type(op, T_SYMBOL);
684
+ rb_opid = SYM2ID(op);
685
+
686
+ if (rb_opid == '>')
687
+ return Py_GT;
688
+ if (rb_opid == '<')
689
+ return Py_LT;
690
+ if (rb_opid == rb_intern("=="))
691
+ return Py_EQ;
692
+ if (rb_opid == rb_intern("!="))
693
+ return Py_NE;
694
+ if (rb_opid == rb_intern(">="))
695
+ return Py_GE;
696
+ if (rb_opid == rb_intern("<="))
697
+ return Py_LE;
698
+
699
+ rb_raise(rb_eArgError, "invalid compare operator: %"PRIsVALUE, op);
700
+ }
701
+
702
+ static VALUE
703
+ pycall_libpython_helpers_m_compare(VALUE mod, VALUE op, VALUE pyptr_a, VALUE pyptr_b)
704
+ {
705
+ PyObject *pyobj_a, *pyobj_b, *res;
706
+ int opid;
707
+
708
+ opid = pycall_rich_compare_opid(op);
709
+
710
+ if (!is_pycall_pyptr(pyptr_a)) {
711
+ rb_raise(rb_eTypeError, "unexpected 2nd argument type %s (expected PyCall::PyPtr)", rb_class2name(CLASS_OF(pyptr_a)));
712
+ }
713
+ if (!is_pycall_pyptr(pyptr_b)) {
714
+ rb_raise(rb_eTypeError, "unexpected 3rd argument type %s (expected PyCall::PyPtr)", rb_class2name(CLASS_OF(pyptr_b)));
715
+ }
716
+
717
+ pyobj_a = get_pyobj_ptr(pyptr_a);
718
+ pyobj_b = get_pyobj_ptr(pyptr_b);
719
+
720
+ res = Py_API(PyObject_RichCompare)(pyobj_a, pyobj_b, opid);
721
+ if (!res) {
722
+ pycall_pyerror_fetch_and_raise("PyObject_RichCompare in pycall_libpython_helpers_m_compare");
723
+ }
724
+
725
+ return pycall_pyobject_to_ruby(res);
726
+ }
727
+
728
+ static int is_pyobject_wrapper(VALUE obj);
729
+ static PyObject * pycall_pyobject_wrapper_get_pyobj_ptr(VALUE obj);
730
+
731
+ VALUE
732
+ pycall_getattr_default(VALUE obj, char const *name, VALUE default_value)
733
+ {
734
+ PyObject *pyobj, *res;
735
+
736
+ if (is_pyobject_wrapper(obj)) {
737
+ pyobj = pycall_pyobject_wrapper_get_pyobj_ptr(obj);
738
+ }
739
+ else {
740
+ pyobj = check_get_pyobj_ptr(obj, NULL);
741
+ }
742
+
743
+ res = Py_API(PyObject_GetAttrString)(pyobj, name);
744
+ if (!res && default_value == Qundef) {
745
+ pycall_pyerror_fetch_and_raise("PyObject_GetAttrString in pycall_libpython_helpers_m_getattr");
746
+ }
747
+ Py_API(PyErr_Clear)();
748
+ return res ? pycall_pyobject_to_ruby(res) : default_value;
749
+ }
750
+
751
+ VALUE
752
+ pycall_getattr(VALUE pyptr, char const *name)
753
+ {
754
+ return pycall_getattr_default(pyptr, name, Qundef);
755
+ }
756
+
757
+ static VALUE
758
+ pycall_libpython_helpers_m_getattr(int argc, VALUE *argv, VALUE mod)
759
+ {
760
+ VALUE pyptr, name, default_value;
761
+
762
+ if (rb_scan_args(argc, argv, "21", &pyptr, &name, &default_value) == 2) {
763
+ default_value = Qundef;
764
+ }
765
+
766
+ if (!is_pycall_pyptr(pyptr)) {
767
+ rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
768
+ }
769
+
770
+ if (RB_TYPE_P(name, T_SYMBOL)) {
771
+ name = rb_sym_to_s(name);
772
+ }
773
+
774
+ return pycall_getattr_default(pyptr, StringValueCStr(name), default_value);
775
+ }
776
+
777
+ static VALUE
778
+ pycall_libpython_helpers_m_hasattr_p(VALUE mod, VALUE pyptr, VALUE name)
779
+ {
780
+ PyObject *pyobj;
781
+ int res;
782
+
783
+ if (!is_pycall_pyptr(pyptr)) {
784
+ rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
785
+ }
786
+
787
+ pyobj = get_pyobj_ptr(pyptr);
788
+
789
+ if (RB_TYPE_P(name, T_SYMBOL)) {
790
+ name = rb_sym_to_s(name);
791
+ }
792
+
793
+ res = Py_API(PyObject_HasAttrString)(pyobj, StringValueCStr(name));
794
+ return res ? Qtrue : Qfalse;
795
+ }
796
+
797
+ static VALUE
798
+ pycall_libpython_helpers_m_callable_p(VALUE mod, VALUE pyptr)
799
+ {
800
+ PyObject *pyobj;
801
+ int res;
802
+
803
+ if (!is_pycall_pyptr(pyptr)) {
804
+ rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
805
+ }
806
+
807
+ pyobj = get_pyobj_ptr(pyptr);
808
+
809
+ res = Py_API(PyCallable_Check)(pyobj);
810
+ return res ? Qtrue : Qfalse;
811
+ }
812
+
813
+ static VALUE
814
+ pycall_libpython_helpers_m_call_object(int argc, VALUE *argv, VALUE mod)
815
+ {
816
+ VALUE pyptr;
817
+ PyObject *pyobj;
818
+
819
+ if (argc < 1) {
820
+ rb_raise(rb_eArgError, "too few arguments (%d for >=1)", argc);
821
+ }
822
+
823
+ pyptr = argv[0];
824
+ if (!is_pycall_pyptr(pyptr)) {
825
+ rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
826
+ }
827
+
828
+ pyobj = get_pyobj_ptr(pyptr);
829
+ if (!Py_API(PyCallable_Check)(pyobj)) {
830
+ rb_raise(rb_eTypeError, "Non-callable Python object was given");
831
+ }
832
+
833
+ if (argc == 1) {
834
+ return pycall_call_python_callable(pyobj, 0, NULL);
835
+ }
836
+ else {
837
+ return pycall_call_python_callable(pyobj, argc - 1, argv + 1);
838
+ }
839
+ }
840
+
841
+ static int
842
+ pycall_extract_kwargs_from_ruby_hash(VALUE key, VALUE value, VALUE arg)
843
+ {
844
+ PyObject *kwargs = (PyObject *)arg;
845
+ char const *key_cstr;
846
+ PyObject *pyvalue;
847
+
848
+ if (RB_TYPE_P(key, T_SYMBOL)) {
849
+ key = rb_sym_to_s(key);
850
+ }
851
+ key_cstr = StringValueCStr(key);
852
+ pyvalue = pycall_pyobject_from_ruby(value);
853
+
854
+ if (Py_API(PyDict_SetItemString)(kwargs, key_cstr, pyvalue) < 0) {
855
+ return ST_STOP;
856
+ }
857
+ return ST_CONTINUE;
858
+ }
859
+
860
+ static VALUE
861
+ pycall_call_python_callable(PyObject *pycallable, int argc, VALUE *argv)
862
+ {
863
+ PyObject *args, *res;
864
+ PyObject *kwargs = NULL;
865
+ Py_ssize_t i, n;
866
+ VALUE hash, obj;
867
+
868
+ /* TODO: Use inspect.getfullargspec */
869
+
870
+ if (argc > 0) {
871
+ n = argc - RB_TYPE_P(argv[argc - 1], T_HASH);
872
+ }
873
+ else {
874
+ n = 0;
875
+ }
876
+
877
+ args = Py_API(PyTuple_New)(n);
878
+ if (!args) {
879
+ pycall_pyerror_fetch_and_raise("PyTuple_New in pycall_call_python_callable");
880
+ }
881
+
882
+ for (i = 0; i < n; ++i) {
883
+ PyObject *pytem = pycall_pyobject_from_ruby(argv[i]);
884
+ if (Py_API(PyTuple_SetItem)(args, i, pytem) == -1) {
885
+ pycall_Py_DecRef(pytem);
886
+ pycall_Py_DecRef(args);
887
+ pycall_pyerror_fetch_and_raise("PyTuple_SetItem in pycall_call_python_callable");
888
+ }
889
+ /* NOTE: Although PyTuple_SetItem steals the item reference,
890
+ * it is unnecessary to call Py_IncRef for the item because
891
+ * pycall_pyobject_from_ruby increments the reference count
892
+ * of its result. */
893
+ }
894
+
895
+ if (n < argc) {
896
+ hash = argv[argc - 1];
897
+ kwargs = Py_API(PyDict_New)();
898
+ if (!RHASH_EMPTY_P(hash)) {
899
+ rb_hash_foreach(hash, pycall_extract_kwargs_from_ruby_hash, (VALUE)kwargs);
900
+ if (Py_API(PyErr_Occurred)() != NULL) {
901
+ pycall_Py_DecRef(args);
902
+ pycall_pyerror_fetch_and_raise("PyDict_SetItemString in pycall_extract_kwargs_from_ruby_hash");
903
+ }
904
+ }
905
+ }
906
+
907
+ res = Py_API(PyObject_Call)(pycallable, args, kwargs); /* New reference */
908
+ if (!res) {
909
+ pycall_pyerror_fetch_and_raise("PyObject_Call in pycall_call_python_callable");
910
+ }
911
+ obj = pycall_pyobject_to_ruby(res);
912
+ pycall_Py_DecRef(res);
913
+ return obj;
914
+ }
915
+
916
+ static VALUE
917
+ pycall_pyobject_wrapper_wrapper_method(int argc, VALUE *argv, VALUE wrapper)
918
+ {
919
+ VALUE pyptr, name;
920
+ char *name_cstr;
921
+ PyObject *pyobj, *attr;
922
+
923
+ pyptr = rb_attr_get(wrapper, rb_intern("@__pyptr__"));
924
+ if (NIL_P(pyptr) || !is_pycall_pyptr(pyptr)) {
925
+ rb_raise(rb_eTypeError, "Wrong wrapper object is given");
926
+ }
927
+
928
+ pyobj = get_pyobj_ptr(pyptr);
929
+
930
+ name = rb_id2str(rb_frame_this_func());
931
+ name_cstr = StringValueCStr(name);
932
+
933
+ if (name_cstr[RSTRING_LEN(name) - 1] == '=') {
934
+ int res;
935
+ VALUE val;
936
+
937
+ rb_scan_args(argc, argv, "1", &val);
938
+
939
+ attr = pycall_pyobject_from_ruby(val);
940
+ if (!attr) {
941
+ pycall_pyerror_fetch_and_raise("pycall_pyobject_from_ruby in pycall_pyobject_wrapper_wrapper_method");
942
+ }
943
+
944
+ name_cstr[RSTRING_LEN(name) - 1] = '\0';
945
+ res = Py_API(PyObject_SetAttrString)(pyobj, name_cstr, attr);
946
+ name_cstr[RSTRING_LEN(name) - 1] = '=';
947
+ if (res == -1) {
948
+ pycall_Py_DecRef(attr);
949
+ pycall_pyerror_fetch_and_raise("PyObject_SetAttrString in pycall_pyobject_wrapper_wrapper_method");
950
+ }
951
+
952
+ return val;
953
+ }
954
+
955
+ attr = Py_API(PyObject_GetAttrString)(pyobj, name_cstr);
956
+ if (!attr) {
957
+ pycall_pyerror_fetch_and_raise("PyObject_GetAttrString in pycall_pyobject_wrapper_wrapper_method");
958
+ }
959
+
960
+ if (!Py_API(PyCallable_Check)(attr))
961
+ return pycall_pyobject_to_ruby(attr);
962
+
963
+ if (PyType_Check(attr) || PyClass_Check(attr))
964
+ return pycall_pyobject_to_ruby(attr);
965
+
966
+ return pycall_call_python_callable(attr, argc, argv);
967
+ }
968
+
969
+ static VALUE
970
+ pycall_libpython_helpers_m_define_wrapper_method(VALUE mod, VALUE wrapper, VALUE name)
971
+ {
972
+ VALUE pyptr, name_sym;
973
+ PyObject *pyobj, *attr;
974
+ char *name_cstr;
975
+
976
+ pyptr = rb_attr_get(wrapper, rb_intern("@__pyptr__"));
977
+ if (NIL_P(pyptr) || !is_pycall_pyptr(pyptr)) {
978
+ rb_raise(rb_eTypeError, "Wrong wrapper object is given");
979
+ }
980
+
981
+ pyobj = get_pyobj_ptr(pyptr);
982
+
983
+ if (RB_TYPE_P(name, T_SYMBOL)) {
984
+ name_sym = name;
985
+ name = rb_sym_to_s(name);
986
+ }
987
+ else if (RB_TYPE_P(name, T_STRING)) {
988
+ name_sym = rb_str_intern(name);
989
+ }
990
+
991
+ name_cstr = StringValueCStr(name);
992
+ if (name_cstr[RSTRING_LEN(name) - 1] == '=') {
993
+ name_cstr[RSTRING_LEN(name) - 1] = '\0';
994
+ attr = Py_API(PyObject_GetAttrString)(pyobj, name_cstr);
995
+ name_cstr[RSTRING_LEN(name) - 1] = '=';
996
+ }
997
+ else {
998
+ attr = Py_API(PyObject_GetAttrString)(pyobj, name_cstr);
999
+ }
1000
+ if (!attr) {
1001
+ pycall_pyerror_fetch_and_raise("PyObject_GetAttrString in pycall_libpython_helpers_m_define_wrapper_method");
1002
+ }
1003
+
1004
+ pycall_Py_DecRef(attr);
1005
+ rb_define_singleton_method(wrapper, name_cstr, pycall_pyobject_wrapper_wrapper_method, -1);
1006
+
1007
+ return Qnil;
1008
+ }
1009
+
1010
+ static PyObject *
1011
+ pycall_convert_index(VALUE index)
1012
+ {
1013
+ PyObject *pyobj;
1014
+
1015
+ if (RB_TYPE_P(index, T_ARRAY) && RARRAY_LEN(index) == 1) {
1016
+ index = RARRAY_AREF(index, 0);
1017
+ }
1018
+ if (RB_TYPE_P(index, T_ARRAY)) {
1019
+ long i, n = RARRAY_LEN(index);
1020
+ pyobj = Py_API(PyTuple_New)(n);
1021
+ for (i = 0; i < n; ++i) {
1022
+ PyObject *pytem = pycall_convert_index(RARRAY_AREF(index, i)); /* New reference */
1023
+ Py_API(PyTuple_SetItem)(pyobj, i, pytem); /* Steal reference */
1024
+ }
1025
+ }
1026
+ else if (rb_obj_is_kind_of(index, rb_cRange)) {
1027
+ pyobj = pycall_pyslice_from_ruby(index); /* New refrence */
1028
+ }
1029
+ else if (pycall_obj_is_step_range(index)) {
1030
+ pyobj = pycall_pyslice_from_ruby(index); /* New refrence */
1031
+ }
1032
+ else {
1033
+ pyobj = pycall_pyobject_from_ruby(index); /* New reference */
1034
+ }
1035
+
1036
+ return pyobj;
1037
+ }
1038
+
1039
+ static VALUE
1040
+ pycall_libpython_helpers_m_getitem(VALUE mod, VALUE pyptr, VALUE key)
1041
+ {
1042
+ PyObject *pyobj, *pyobj_key, *pyobj_v;
1043
+ VALUE obj;
1044
+
1045
+ if (!is_pycall_pyptr(pyptr)) {
1046
+ rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
1047
+ }
1048
+
1049
+ pyobj = get_pyobj_ptr(pyptr);
1050
+
1051
+ pyobj_key = pycall_convert_index(key);
1052
+
1053
+ pyobj_v = Py_API(PyObject_GetItem)(pyobj, pyobj_key);
1054
+ if (!pyobj_v) {
1055
+ pycall_pyerror_fetch_and_raise("PyObject_GetItem in pycall_libpython_helpers_m_getitem");
1056
+ }
1057
+
1058
+ obj = pycall_pyobject_to_ruby(pyobj_v);
1059
+ pycall_Py_DecRef(pyobj_v);
1060
+ return obj;
1061
+ }
1062
+
1063
+ static VALUE
1064
+ pycall_libpython_helpers_m_setitem(VALUE mod, VALUE pyptr, VALUE key, VALUE v)
1065
+ {
1066
+ PyObject *pyobj, *pyobj_key, *pyobj_value;
1067
+ int res;
1068
+
1069
+ pyobj = check_get_pyobj_ptr(pyptr, NULL);
1070
+ pyobj_key = pycall_convert_index(key);
1071
+ pyobj_value = pycall_pyobject_from_ruby(v);
1072
+
1073
+ res = Py_API(PyObject_SetItem)(pyobj, pyobj_key, pyobj_value);
1074
+ if (res == -1) {
1075
+ pycall_pyerror_fetch_and_raise("PyObject_SetItem in pycall_libpython_helpers_m_setitem");
1076
+ }
1077
+ Py_API(Py_DecRef(pyobj_key));
1078
+ Py_API(Py_DecRef(pyobj_value));
1079
+
1080
+ return v;
1081
+ }
1082
+
1083
+ static VALUE
1084
+ pycall_libpython_helpers_m_delitem(VALUE mod, VALUE pyptr, VALUE key, VALUE v)
1085
+ {
1086
+ PyObject *pyobj, *pyobj_key;
1087
+ int res;
1088
+
1089
+ pyobj = check_get_pyobj_ptr(pyptr, NULL);
1090
+ pyobj_key = pycall_convert_index(key);
1091
+
1092
+ res = Py_API(PyObject_DelItem)(pyobj, pyobj_key);
1093
+ if (res == -1) {
1094
+ pycall_pyerror_fetch_and_raise("PyObject_DelItem");
1095
+ }
1096
+
1097
+ return v;
1098
+ }
1099
+
1100
+ static VALUE
1101
+ pycall_libpython_helpers_m_str(VALUE mod, VALUE pyptr)
1102
+ {
1103
+ PyObject *pyobj, *pyobj_str;
1104
+
1105
+ pyobj = check_get_pyobj_ptr(pyptr, NULL);
1106
+
1107
+ pyobj_str = Py_API(PyObject_Str)(pyobj);
1108
+ if (!pyobj_str) {
1109
+ pycall_pyerror_fetch_and_raise("PyObject_Str");
1110
+ }
1111
+
1112
+ return pycall_pyobject_to_ruby(pyobj_str);
1113
+ }
1114
+
1115
+ static VALUE
1116
+ pycall_libpython_helpers_m_dict_contains(VALUE mod, VALUE pyptr, VALUE key)
1117
+ {
1118
+ PyObject *pyobj, *pyobj_key;
1119
+ int res;
1120
+
1121
+ pyobj = check_get_pyobj_ptr(pyptr, Py_API(PyDict_Type));
1122
+ pyobj_key = pycall_pyobject_from_ruby(key);
1123
+ res = Py_API(PyDict_Contains)(pyobj, pyobj_key);
1124
+ if (res == -1) {
1125
+ pycall_pyerror_fetch_and_raise("PyDict_Contains");
1126
+ }
1127
+
1128
+ return res ? Qtrue : Qfalse;
1129
+ }
1130
+
1131
+ static VALUE
1132
+ pycall_libpython_helpers_m_dict_each(VALUE mod, VALUE pyptr)
1133
+ {
1134
+ PyObject *pyobj, *pyobj_key, *pyobj_value;
1135
+ Py_ssize_t pos;
1136
+
1137
+ pyobj = check_get_pyobj_ptr(pyptr, Py_API(PyDict_Type));
1138
+
1139
+ pos = 0;
1140
+ while (Py_API(PyDict_Next)(pyobj, &pos, &pyobj_key, &pyobj_value)) {
1141
+ VALUE key, value;
1142
+ key = pycall_pyobject_to_ruby(pyobj_key);
1143
+ value = pycall_pyobject_to_ruby(pyobj_value);
1144
+ rb_yield(rb_assoc_new(key, value));
1145
+ }
1146
+
1147
+ return Qnil;
1148
+ }
1149
+
1150
+ static VALUE
1151
+ pycall_libpython_helpers_m_sequence_contains(VALUE mod, VALUE pyptr, VALUE key)
1152
+ {
1153
+ PyObject *pyobj, *pyobj_key;
1154
+ int res;
1155
+
1156
+ pyobj = check_get_pyobj_ptr(pyptr, NULL);
1157
+ if (!Py_API(PySequence_Check)(pyobj))
1158
+ rb_raise(rb_eTypeError, "unexpected Python type %s (expected a Python sequence object)", Py_TYPE(pyobj)->tp_name);
1159
+
1160
+ pyobj_key = pycall_pyobject_from_ruby(key);
1161
+ res = Py_API(PySequence_Contains)(pyobj, pyobj_key);
1162
+ if (res == -1) {
1163
+ pycall_pyerror_fetch_and_raise("PySequence_Contains");
1164
+ }
1165
+
1166
+ return res ? Qtrue : Qfalse;
1167
+ }
1168
+
1169
+ static VALUE
1170
+ pycall_libpython_helpers_m_sequence_each(VALUE mod, VALUE pyptr)
1171
+ {
1172
+ PyObject *pyobj, *pyobj_iter, *pyobj_item;
1173
+
1174
+ pyobj = check_get_pyobj_ptr(pyptr, NULL);
1175
+ if (!Py_API(PySequence_Check)(pyobj))
1176
+ rb_raise(rb_eTypeError, "unexpected Python type %s (expected a Python sequence object)", Py_TYPE(pyobj)->tp_name);
1177
+
1178
+ pyobj_iter = Py_API(PyObject_GetIter)(pyobj);
1179
+ if (!pyobj_iter) {
1180
+ pycall_pyerror_fetch_and_raise("PyObject_GetIter in pycall_libpython_helpers_m_sequence_each");
1181
+ }
1182
+
1183
+ while ((pyobj_item = Py_API(PyIter_Next)(pyobj_iter))) {
1184
+ rb_yield(pycall_pyobject_to_ruby(pyobj_item));
1185
+ pycall_Py_DecRef(pyobj_item);
1186
+ }
1187
+
1188
+ pycall_Py_DecRef(pyobj_iter);
1189
+
1190
+ if (Py_API(PyErr_Occurred)() != NULL) {
1191
+ pycall_pyerror_fetch_and_raise("checking error just in case at the end of pycall_libpython_helpers_m_sequence_each");
1192
+ }
1193
+
1194
+ return Qnil;
1195
+ }
1196
+
1197
+ /* ==== PyCall::PyObjectWrapper ==== */
1198
+
1199
+ static int
1200
+ is_pyobject_wrapper(VALUE obj)
1201
+ {
1202
+ return RTEST(rb_obj_is_kind_of(obj, mPyObjectWrapper));
1203
+ }
1204
+
1205
+ static VALUE
1206
+ pycall_pyobject_wrapper_get_pyptr(VALUE obj)
1207
+ {
1208
+ if (!is_pyobject_wrapper(obj)) {
1209
+ rb_raise(rb_eTypeError, "PyCal::PyObjectWrapper is required");
1210
+ }
1211
+
1212
+ return rb_funcall(obj, rb_intern("__pyptr__"), 0);
1213
+ }
1214
+
1215
+ static PyObject *
1216
+ pycall_pyobject_wrapper_get_pyobj_ptr(VALUE obj)
1217
+ {
1218
+ VALUE pyptr = pycall_pyobject_wrapper_get_pyptr(obj);
1219
+ return get_pyobj_ptr(pyptr);
1220
+ }
1221
+
1222
+ static PyObject *
1223
+ pycall_pyobject_wrapper_check_get_pyobj_ptr(VALUE obj, PyTypeObject *pytypeobj)
1224
+ {
1225
+ PyObject *pyobj;
1226
+
1227
+ pyobj = pycall_pyobject_wrapper_get_pyobj_ptr(obj);
1228
+ if (Py_TYPE(pyobj) != pytypeobj) {
1229
+ rb_raise(rb_eTypeError, "unexpected Python type %s (expected %s)", Py_TYPE(pyobj)->tp_name, pytypeobj->tp_name);
1230
+ }
1231
+
1232
+ return pyobj;
1233
+ }
1234
+
1235
+ /* ==== PyCall::Conversion ==== */
1236
+
1237
+ static VALUE
1238
+ pycall_python_type_mapping_get_mapped_class(VALUE pytypeptr)
1239
+ {
1240
+ (void)check_get_pytypeobj_ptr(pytypeptr);
1241
+ return rb_hash_lookup(python_type_mapping, pytypeptr);
1242
+ }
1243
+
1244
+ static int
1245
+ pycall_python_type_mapping_register(VALUE pytypeptr, VALUE rbcls)
1246
+ {
1247
+ (void)check_get_pytypeobj_ptr(pytypeptr);
1248
+ if (rb_hash_lookup2(python_type_mapping, pytypeptr, Qundef) != Qundef)
1249
+ return 0;
1250
+
1251
+ Check_Type(rbcls, T_CLASS);
1252
+ if (!rb_obj_is_kind_of(rbcls, mPyTypeObjectWrapper)) {
1253
+ rb_raise(rb_eTypeError, "ruby class must be extended by PyCall::PyTypeObjectWrapper");
1254
+ }
1255
+
1256
+ /* TODO: Shouldn't have to use weak reference? */
1257
+ rb_hash_aset(python_type_mapping, pytypeptr, rbcls);
1258
+
1259
+ return 1;
1260
+ }
1261
+
1262
+ static int
1263
+ pycall_python_type_mapping_unregister(VALUE pytypeptr)
1264
+ {
1265
+ (void)check_get_pytypeobj_ptr(pytypeptr);
1266
+ if (rb_hash_lookup2(python_type_mapping, pytypeptr, Qundef) == Qundef)
1267
+ return 0;
1268
+
1269
+ rb_hash_delete(python_type_mapping, pytypeptr);
1270
+ return 1;
1271
+ }
1272
+
1273
+ VALUE
1274
+ pycall_pyobject_wrapper_object_new(VALUE klass, PyObject *pyobj)
1275
+ {
1276
+ VALUE obj;
1277
+
1278
+ obj = rb_obj_alloc(klass);
1279
+ rb_ivar_set(obj, rb_intern("@__pyptr__"), pycall_pyptr_new(pyobj));
1280
+ rb_extend_object(obj, mPyObjectWrapper);
1281
+
1282
+ return obj;
1283
+ }
1284
+
1285
+ VALUE
1286
+ pycall_pyobject_to_ruby(PyObject *pyobj)
1287
+ {
1288
+ VALUE cls;
1289
+
1290
+ if (pyobj == Py_API(_Py_NoneStruct))
1291
+ return Qnil;
1292
+
1293
+ if (PyRuby_Check(pyobj))
1294
+ return PyRuby_get_ruby_object(pyobj);
1295
+
1296
+ if (PyType_Check(pyobj))
1297
+ return pycall_pytype_to_ruby(pyobj); /* Increment pyobj refcnt */
1298
+
1299
+ if (PyClass_Check(pyobj))
1300
+ return pycall_pytype_to_ruby(pyobj); /* Increment pyobj refcnt */
1301
+
1302
+ if (pyobj->ob_type == Py_API(PyModule_Type))
1303
+ return pycall_pymodule_to_ruby(pyobj); /* Increment pyobj refcnt */
1304
+
1305
+ if (pyobj->ob_type == Py_API(PyBool_Type))
1306
+ return pycall_pybool_to_ruby(pyobj);
1307
+
1308
+ if (pyobj->ob_type == Py_API(PyComplex_Type))
1309
+ return pycall_pycomplex_to_ruby(pyobj);
1310
+
1311
+ if (pyobj->ob_type == Py_API(PyFloat_Type))
1312
+ return pycall_pyfloat_to_ruby(pyobj);
1313
+
1314
+ if (pyobj->ob_type == Py_API(PyInt_Type))
1315
+ return pycall_pyint_to_ruby(pyobj);
1316
+
1317
+ if (pyobj->ob_type == Py_API(PyLong_Type))
1318
+ return pycall_pylong_to_ruby(pyobj);
1319
+
1320
+ if (pyobj->ob_type == Py_API(PyUnicode_Type) || pyobj->ob_type == Py_API(PyString_Type))
1321
+ return pycall_pystring_to_ruby(pyobj);
1322
+
1323
+ Py_API(Py_IncRef)(pyobj);
1324
+ Py_API(Py_IncRef)((PyObject *)pyobj->ob_type);
1325
+ cls = pycall_python_type_mapping_get_mapped_class(pycall_pytypeptr_new((PyObject *)pyobj->ob_type));
1326
+ if (NIL_P(cls)) {
1327
+ rb_warning("Currentry do not support to convert %s to Ruby object", Py_TYPE(pyobj)->tp_name);
1328
+ return pycall_pyobject_wrapper_object_new(rb_cObject, pyobj);
1329
+ }
1330
+
1331
+ return rb_funcall(cls, rb_intern("wrap_pyptr"), 1, pycall_pyptr_new(pyobj));
1332
+ }
1333
+
1334
+ VALUE
1335
+ pycall_pytype_to_ruby(PyObject *pyobj)
1336
+ {
1337
+ VALUE pytypeptr = Qnil, wrapper_class;
1338
+ /* TODO: should look up wrapper class table instead of directly returning PyTypePtr */
1339
+
1340
+ if (PyType_Check(pyobj))
1341
+ pytypeptr = pycall_pytypeptr_new(pyobj);
1342
+ else if (PyClass_Check(pyobj))
1343
+ pytypeptr = pycall_pytypeptr_new(pyobj);
1344
+
1345
+ if (NIL_P(pytypeptr))
1346
+ return Qnil;
1347
+
1348
+ Py_API(Py_IncRef)(pyobj);
1349
+
1350
+ wrapper_class = rb_funcall(mPyCall, rb_intern("wrap_class"), 1, pytypeptr);
1351
+ return wrapper_class;
1352
+ }
1353
+
1354
+ VALUE
1355
+ pycall_pymodule_to_ruby(PyObject *pyobj)
1356
+ {
1357
+ VALUE pymodptr = Qnil, wrapper_module;
1358
+
1359
+ if (Py_TYPE(pyobj) != Py_API(PyModule_Type))
1360
+ return Qnil;
1361
+
1362
+ pymodptr = pycall_pyptr_new(pyobj);
1363
+ Py_API(Py_IncRef)(pyobj);
1364
+
1365
+ wrapper_module = rb_funcall(mPyCall, rb_intern("wrap_module"), 1, pymodptr);
1366
+ return wrapper_module;
1367
+ }
1368
+
1369
+ VALUE
1370
+ pycall_pybool_to_ruby(PyObject *pyobj)
1371
+ {
1372
+ if (pyobj->ob_type != Py_API(PyBool_Type))
1373
+ return Qnil;
1374
+
1375
+ if (Py_API(PyInt_Type))
1376
+ return Py_API(PyInt_AsSsize_t)(pyobj) ? Qtrue : Qfalse;
1377
+
1378
+ return Py_API(PyLong_AsSsize_t)(pyobj) ? Qtrue : Qfalse;
1379
+ }
1380
+
1381
+ VALUE
1382
+ pycall_pycomplex_to_ruby(PyObject *pyobj)
1383
+ {
1384
+ double real, imag;
1385
+
1386
+ if (pyobj->ob_type != Py_API(PyComplex_Type))
1387
+ return Qnil;
1388
+
1389
+ real = Py_API(PyComplex_RealAsDouble)(pyobj);
1390
+ imag = Py_API(PyComplex_ImagAsDouble)(pyobj);
1391
+
1392
+ return rb_complex_new(DBL2NUM(real), DBL2NUM(imag));
1393
+ }
1394
+
1395
+ VALUE
1396
+ pycall_pyfloat_to_ruby(PyObject *pyobj)
1397
+ {
1398
+ double d;
1399
+
1400
+ if (pyobj->ob_type != Py_API(PyFloat_Type))
1401
+ return Qnil;
1402
+
1403
+ {
1404
+ PyObject *type, *value, *tb;
1405
+ Py_API(PyErr_Fetch)(&type, &value, &tb);
1406
+
1407
+ d = Py_API(PyFloat_AsDouble)(pyobj);
1408
+ if (d == -1.0) {
1409
+ if (Py_API(PyErr_Occurred)()) {
1410
+ pycall_pyerror_fetch_and_raise("PyFloat_AsDouble");
1411
+ }
1412
+ }
1413
+
1414
+ Py_API(PyErr_Restore)(type, value, tb);
1415
+ }
1416
+
1417
+ return DBL2NUM(d);
1418
+ }
1419
+
1420
+ VALUE
1421
+ pycall_pyint_to_ruby(PyObject *pyobj)
1422
+ {
1423
+ Py_ssize_t n;
1424
+
1425
+ if (pyobj->ob_type != Py_API(PyInt_Type))
1426
+ return Qnil;
1427
+
1428
+ n = Py_API(PyInt_AsSsize_t)(pyobj);
1429
+ return SSIZET2NUM(n);
1430
+ }
1431
+
1432
+ VALUE
1433
+ pycall_pylong_to_ruby(PyObject *pyobj)
1434
+ {
1435
+ int overflow;
1436
+
1437
+ if (pyobj->ob_type != Py_API(PyLong_Type))
1438
+ return Qnil;
1439
+
1440
+ {
1441
+ long n = Py_API(PyLong_AsLongAndOverflow)(pyobj, &overflow);
1442
+ if (overflow == 0) {
1443
+ if (Py_API(PyErr_Occurred)()) {
1444
+ pycall_pyerror_fetch_and_raise("PyLong_AsLongAndOverflow");
1445
+ }
1446
+ return LONG2FIX(n);
1447
+ }
1448
+ }
1449
+
1450
+ #if HAVE_LONG_LONG
1451
+ {
1452
+ LONG_LONG n = Py_API(PyLong_AsLongLongAndOverflow)(pyobj, &overflow);
1453
+ if (overflow == 0) {
1454
+ if (Py_API(PyErr_Occurred)()) {
1455
+ pycall_pyerror_fetch_and_raise("PyLong_AsLongLongAndOverflow");
1456
+ }
1457
+ return LL2NUM(n);
1458
+ }
1459
+ }
1460
+ #endif
1461
+
1462
+ rb_warning("Currentry do not support to convert multi-precision PyLong number to Ruby object");
1463
+
1464
+ return Qnil;
1465
+ }
1466
+
1467
+ VALUE
1468
+ pycall_pystring_to_ruby(PyObject *pyobj)
1469
+ {
1470
+ char *str = NULL;
1471
+ Py_ssize_t len = 0;
1472
+ int res = -1;
1473
+
1474
+ /* TODO: PyUnicode_Check */
1475
+ if (pyobj->ob_type == Py_API(PyUnicode_Type)) {
1476
+ pyobj = Py_API(PyUnicode_AsUTF8String)(pyobj);
1477
+ res = Py_API(PyString_AsStringAndSize)(pyobj, &str, &len);
1478
+ pycall_Py_DecRef(pyobj);
1479
+ }
1480
+ /* TODO: PyString_Check */
1481
+ else if (pyobj->ob_type == Py_API(PyString_Type)) {
1482
+ res = Py_API(PyString_AsStringAndSize)(pyobj, &str, &len);
1483
+ }
1484
+
1485
+ if (res < 0) {
1486
+ return Qnil;
1487
+ }
1488
+
1489
+ return rb_str_new(str, len);
1490
+ }
1491
+
1492
+ static VALUE
1493
+ pycall_pytuple_to_a(PyObject *pyobj)
1494
+ {
1495
+ VALUE ary;
1496
+ Py_ssize_t i, n;
1497
+
1498
+ assert(Py_TYPE(pyobj) == Py_API(PyTuple_Type));
1499
+
1500
+ n = Py_API(PyTuple_Size)(pyobj);
1501
+ ary = rb_ary_new_capa(n);
1502
+ for (i = 0; i < n; ++i) {
1503
+ PyObject *pytem = Py_API(PyTuple_GetItem)(pyobj, i);
1504
+ Py_API(Py_IncRef)(pytem);
1505
+ rb_ary_push(ary, pycall_pyobject_to_ruby(pytem));
1506
+ }
1507
+
1508
+ return ary;
1509
+ }
1510
+
1511
+ static VALUE
1512
+ pycall_pysequence_to_a(PyObject *pyobj)
1513
+ {
1514
+ Py_ssize_t n, i;
1515
+ VALUE ary;
1516
+
1517
+ assert(Py_API(PySequence_Check)(pyobj));
1518
+
1519
+ n = Py_API(PySequence_Size)(pyobj);
1520
+ ary = rb_ary_new_capa(n);
1521
+ for (i = 0; i < n; ++i) {
1522
+ PyObject *pytem = Py_API(PySequence_GetItem)(pyobj, i);
1523
+ rb_ary_push(ary, pycall_pyobject_to_ruby(pytem));
1524
+ }
1525
+
1526
+ return ary;
1527
+ }
1528
+
1529
+ VALUE
1530
+ pycall_pyobject_to_a(PyObject *pyobj)
1531
+ {
1532
+ if (Py_TYPE(pyobj) == Py_API(PyTuple_Type)) {
1533
+ return pycall_pytuple_to_a(pyobj);
1534
+ }
1535
+
1536
+ if (Py_API(PySequence_Check)(pyobj)) {
1537
+ return pycall_pysequence_to_a(pyobj);
1538
+ }
1539
+
1540
+ /* TODO: PyDict_Type to assoc array */
1541
+
1542
+ return rb_Array(pycall_pyobject_to_ruby(pyobj));
1543
+ }
1544
+
1545
+ static VALUE
1546
+ pycall_conv_m_register_python_type_mapping(VALUE mod, VALUE pytypeptr, VALUE rbcls)
1547
+ {
1548
+ return pycall_python_type_mapping_register(pytypeptr, rbcls) ? Qtrue : Qfalse;
1549
+ }
1550
+
1551
+ static VALUE
1552
+ pycall_conv_m_unregister_python_type_mapping(VALUE mod, VALUE pytypeptr)
1553
+ {
1554
+ return pycall_python_type_mapping_unregister(pytypeptr) ? Qtrue : Qfalse;
1555
+ }
1556
+
1557
+ static VALUE
1558
+ pycall_conv_m_from_ruby(VALUE mod, VALUE obj)
1559
+ {
1560
+ PyObject *pyobj = pycall_pyobject_from_ruby(obj);
1561
+ if (PyType_Check(pyobj) || PyClass_Check(pyobj))
1562
+ return pycall_pytypeptr_new(pyobj);
1563
+ if (PyRuby_Check(pyobj))
1564
+ return pycall_pyrubyptr_new(pyobj);
1565
+ return pycall_pyptr_new(pyobj);
1566
+ }
1567
+
1568
+ static VALUE
1569
+ pycall_conv_m_to_ruby(VALUE mod, VALUE pyptr)
1570
+ {
1571
+ VALUE obj, obj_pyptr;
1572
+ PyObject *pyobj = check_get_pyobj_ptr(pyptr, NULL);
1573
+ obj = obj_pyptr = pycall_pyobject_to_ruby(pyobj);
1574
+ if (is_pyobject_wrapper(obj)) {
1575
+ obj_pyptr = pycall_pyobject_wrapper_get_pyptr(obj);
1576
+ }
1577
+ if (is_pycall_pyptr(obj_pyptr) && obj_pyptr != pyptr && DATA_PTR(obj_pyptr) == pyobj) {
1578
+ Py_API(Py_IncRef)(pyobj);
1579
+ }
1580
+ return obj;
1581
+ }
1582
+
1583
+ PyObject *
1584
+ pycall_pyobject_from_ruby(VALUE obj)
1585
+ {
1586
+ if (is_pycall_pyptr(obj)) {
1587
+ PyObject *pyobj = get_pyobj_ptr(obj);
1588
+ Py_API(Py_IncRef)(pyobj);
1589
+ return pyobj;
1590
+ }
1591
+ if (is_pyobject_wrapper(obj)) {
1592
+ PyObject *pyobj = pycall_pyobject_wrapper_get_pyobj_ptr(obj);
1593
+ Py_API(Py_IncRef)(pyobj);
1594
+ return pyobj;
1595
+ }
1596
+ if (obj == Qnil) {
1597
+ Py_API(Py_IncRef)(Py_API(_Py_NoneStruct));
1598
+ return Py_API(_Py_NoneStruct);
1599
+ }
1600
+ if (obj == Qtrue || obj == Qfalse) {
1601
+ return Py_API(PyBool_FromLong)(RTEST(obj));
1602
+ }
1603
+ if (RB_INTEGER_TYPE_P(obj)) {
1604
+ if (FIXNUM_P(obj)) {
1605
+ if (Py_API(PyInt_FromLong))
1606
+ return Py_API(PyInt_FromLong)(FIX2LONG(obj));
1607
+ return Py_API(PyLong_FromLong)(FIX2LONG(obj));
1608
+ }
1609
+ #ifdef HAVE_LONG_LONG
1610
+ else {
1611
+ LONG_LONG ll;
1612
+ int state = 0;
1613
+ ll = (LONG_LONG)rb_protect((VALUE (*)(VALUE))rb_big2ll, obj, &state);
1614
+ if (!state) {
1615
+ if (Py_API(PyInt_FromSsize_t) && SSIZE_MIN <= ll && ll <= SSIZE_MAX)
1616
+ Py_API(PyInt_FromSsize_t)((Py_ssize_t)ll);
1617
+ return Py_API(PyLong_FromLongLong)(ll);
1618
+ }
1619
+ }
1620
+ #endif
1621
+ rb_warn("Currently do not support to convert large integer values to PyLong");
1622
+ Py_API(Py_IncRef)(Py_API(_Py_NoneStruct));
1623
+ return Py_API(_Py_NoneStruct); /* FIXME */
1624
+ }
1625
+ if (RB_FLOAT_TYPE_P(obj)) {
1626
+ return Py_API(PyFloat_FromDouble)(RFLOAT_VALUE(obj));
1627
+ }
1628
+ if (RB_TYPE_P(obj, T_COMPLEX)) {
1629
+ VALUE re, im;
1630
+ re = rb_funcall(obj, rb_intern("real"), 0);
1631
+ im = rb_funcall(obj, rb_intern("imag"), 0);
1632
+ return Py_API(PyComplex_FromDoubles)(NUM2DBL(re), NUM2DBL(im));
1633
+ }
1634
+ if (RB_TYPE_P(obj, T_STRING) || RB_TYPE_P(obj, T_SYMBOL)) {
1635
+ return pycall_pystring_from_ruby(obj);
1636
+ }
1637
+ if (RB_TYPE_P(obj, T_ARRAY)) {
1638
+ return pycall_pylist_from_ruby(obj);
1639
+ }
1640
+ if (RB_TYPE_P(obj, T_HASH)) {
1641
+ return pycall_pydict_from_ruby(obj);
1642
+ }
1643
+
1644
+ return PyRuby_New(obj);
1645
+ }
1646
+
1647
+ PyObject *
1648
+ pycall_pystring_from_ruby(VALUE obj)
1649
+ {
1650
+ int is_binary, is_ascii_only;
1651
+
1652
+ if (RB_TYPE_P(obj, T_SYMBOL)) {
1653
+ obj = rb_sym_to_s(obj);
1654
+ }
1655
+
1656
+ StringValue(obj);
1657
+
1658
+ is_binary = (rb_enc_get_index(obj) == rb_ascii8bit_encindex());
1659
+ is_ascii_only = (ENC_CODERANGE_7BIT == rb_enc_str_coderange(obj));
1660
+
1661
+ if (is_binary || (!python_is_unicode_literals && is_ascii_only)) {
1662
+ return Py_API(PyString_FromStringAndSize)(RSTRING_PTR(obj), RSTRING_LEN(obj));
1663
+ }
1664
+ return Py_API(PyUnicode_DecodeUTF8)(RSTRING_PTR(obj), RSTRING_LEN(obj), NULL);
1665
+ }
1666
+
1667
+ PyObject *
1668
+ pycall_pytuple_from_ruby(VALUE obj)
1669
+ {
1670
+ PyObject *pytupleobj;
1671
+ long i, n;
1672
+
1673
+ obj = rb_convert_type(obj, T_ARRAY, "Array", "to_ary");
1674
+ n = RARRAY_LEN(obj);
1675
+ pytupleobj = Py_API(PyTuple_New)(n);
1676
+ if (!pytupleobj) {
1677
+ pycall_pyerror_fetch_and_raise("PyTuple_New in pycall_pytuple_from_ruby");
1678
+ }
1679
+
1680
+ for (i = 0; i < n; ++i) {
1681
+ int res;
1682
+ PyObject *pytem;
1683
+
1684
+ pytem = pycall_pyobject_from_ruby(RARRAY_AREF(obj, i));
1685
+ res = Py_API(PyTuple_SetItem)(pytupleobj, i, pytem);
1686
+ if (res == -1) {
1687
+ pycall_Py_DecRef(pytem);
1688
+ pycall_Py_DecRef(pytupleobj);
1689
+ pycall_pyerror_fetch_and_raise("PyTuple_SetItem");
1690
+ }
1691
+ }
1692
+
1693
+ return pytupleobj;
1694
+ }
1695
+
1696
+ PyObject *
1697
+ pycall_pylist_from_ruby(VALUE obj)
1698
+ {
1699
+ PyObject *pylistobj;
1700
+ long i, n;
1701
+
1702
+ obj = rb_convert_type(obj, T_ARRAY, "Array", "to_ary");
1703
+ n = RARRAY_LEN(obj);
1704
+ pylistobj = Py_API(PyList_New)(n);
1705
+ if (!pylistobj) {
1706
+ pycall_pyerror_fetch_and_raise("PyList_New in pcall_pylist_from_ruby");
1707
+ }
1708
+
1709
+ for (i = 0; i < n; ++i) {
1710
+ int res;
1711
+ PyObject *pytem;
1712
+
1713
+ pytem = pycall_pyobject_from_ruby(RARRAY_AREF(obj, i));
1714
+ res = Py_API(PyList_SetItem)(pylistobj, i, pytem);
1715
+
1716
+ if (res == -1) {
1717
+ pycall_Py_DecRef(pytem);
1718
+ pycall_Py_DecRef(pylistobj);
1719
+ pycall_pyerror_fetch_and_raise("PyList_SetItem in pycall_pylist_from_ruby");
1720
+ }
1721
+ }
1722
+
1723
+ return pylistobj;
1724
+ }
1725
+
1726
+ static int
1727
+ pycall_pydict_from_ruby_iter(VALUE key, VALUE value, VALUE arg)
1728
+ {
1729
+ PyObject *pydictobj = (PyObject *)arg;
1730
+ PyObject *pyobj_key, *pyobj_value;
1731
+ int res;
1732
+
1733
+ pyobj_key = pycall_pyobject_from_ruby(key);
1734
+ pyobj_value = pycall_pyobject_from_ruby(value);
1735
+ res = Py_API(PyObject_SetItem)(pydictobj, pyobj_key, pyobj_value);
1736
+ if (res == -1) {
1737
+ return ST_STOP;
1738
+ }
1739
+ Py_API(Py_DecRef)(pyobj_key);
1740
+ Py_API(Py_DecRef)(pyobj_value);
1741
+ return ST_CONTINUE;
1742
+ }
1743
+
1744
+ PyObject *
1745
+ pycall_pydict_from_ruby(VALUE obj)
1746
+ {
1747
+ PyObject *pydictobj;
1748
+
1749
+ obj = rb_convert_type(obj, T_HASH, "Hash", "to_hash");
1750
+ pydictobj = Py_API(PyDict_New)();
1751
+ if (!pydictobj) {
1752
+ pycall_pyerror_fetch_and_raise("PyDict_New in pycall_pydict_from_ruby");
1753
+ }
1754
+
1755
+ rb_hash_foreach(obj, pycall_pydict_from_ruby_iter, (VALUE)pydictobj);
1756
+ if (Py_API(PyErr_Occurred)()) {
1757
+ pycall_pyerror_fetch_and_raise("PyObject_SetItem in pycall_pydict_from_ruby_iter");
1758
+ }
1759
+
1760
+ return pydictobj;
1761
+ }
1762
+
1763
+ PyObject *
1764
+ pycall_pyslice_from_ruby(VALUE obj)
1765
+ {
1766
+ VALUE begin, end, step = Qnil;
1767
+ int exclude_end;
1768
+ PyObject *pystart, *pystop, *pystep, *pyslice;
1769
+
1770
+ if (rb_obj_is_kind_of(obj, rb_cRange)) {
1771
+ pycall_extract_range(obj, &begin, &end, &exclude_end, NULL);
1772
+ }
1773
+ else if (pycall_obj_is_step_range(obj)) {
1774
+ pycall_extract_range(obj, &begin, &end, &exclude_end, &step);
1775
+ }
1776
+ else {
1777
+ rb_raise(rb_eTypeError, "unexpected argument type %s (expected Range or Enumerator generated by Range#step)", rb_class2name(CLASS_OF(obj)));
1778
+ }
1779
+
1780
+ if (!NIL_P(step) && NUM2SSIZET(step) < 0) {
1781
+ if (!NIL_P(end)) {
1782
+ if (!exclude_end) {
1783
+ ssize_t end_i = NUM2SSIZET(end);
1784
+ switch (end_i) {
1785
+ case 0:
1786
+ end = Qnil;
1787
+ break;
1788
+
1789
+ default:
1790
+ end = SSIZET2NUM(end_i - 1); /* TODO: limit check */
1791
+ break;
1792
+ }
1793
+ }
1794
+ }
1795
+ }
1796
+ else {
1797
+ if (!NIL_P(end)) {
1798
+ if (!exclude_end) {
1799
+ ssize_t end_i = NUM2SSIZET(end);
1800
+ switch (end_i) {
1801
+ case -1:
1802
+ end = Qnil;
1803
+ break;
1804
+
1805
+ default:
1806
+ end = SSIZET2NUM(end_i + 1); /* TODO: limit check */
1807
+ break;
1808
+ }
1809
+ }
1810
+ }
1811
+ }
1812
+
1813
+ pystart = pycall_pyobject_from_ruby(begin);
1814
+ pystop = pycall_pyobject_from_ruby(end);
1815
+ pystep = pycall_pyobject_from_ruby(step);
1816
+
1817
+ pyslice = Py_API(PySlice_New)(pystart, pystop, pystep);
1818
+ /* PySlice_New increments reference counts of pystart, pystop, and pystep */
1819
+ pycall_Py_DecRef(pystart);
1820
+ pycall_Py_DecRef(pystop);
1821
+ pycall_Py_DecRef(pystep);
1822
+
1823
+ return pyslice;
1824
+ }
1825
+
1826
+ VALUE
1827
+ pycall_pyerror_new(PyObject *type, PyObject *value, PyObject *traceback)
1828
+ {
1829
+ VALUE init_args[3];
1830
+
1831
+ init_args[0] = pycall_pyobject_to_ruby(type);
1832
+ init_args[1] = value ? pycall_pyobject_to_ruby(value) : Qnil;
1833
+ init_args[2] = traceback ? pycall_pyobject_to_ruby(traceback) : Qnil;
1834
+
1835
+ return rb_class_new_instance(3, init_args, cPyError);
1836
+ }
1837
+
1838
+ VALUE
1839
+ pycall_pyerror_fetch(void)
1840
+ {
1841
+ PyObject *type, *value, *traceback;
1842
+
1843
+ if (Py_API(PyErr_Occurred)() == NULL)
1844
+ return Qnil;
1845
+
1846
+ Py_API(PyErr_Fetch)(&type, &value, &traceback);
1847
+ if (type == NULL)
1848
+ return Qnil;
1849
+
1850
+ return pycall_pyerror_new(type, value, traceback);
1851
+ }
1852
+
1853
+ void
1854
+ pycall_pyerror_fetch_and_raise(char const *format, ...)
1855
+ {
1856
+ va_list args;
1857
+ VALUE pyerror, msg;
1858
+
1859
+ pyerror = pycall_pyerror_fetch();
1860
+ if (!NIL_P(pyerror))
1861
+ rb_exc_raise(pyerror);
1862
+
1863
+ va_start(args, format);
1864
+ msg = rb_vsprintf(format, args);
1865
+ va_end(args);
1866
+
1867
+ rb_exc_raise(rb_exc_new3(eError, msg));
1868
+ }
1869
+
1870
+ unsigned long
1871
+ pycall_default_tp_flags(void)
1872
+ {
1873
+ unsigned long const stackless_extension_flag = python_has_stackless_extension ? Py_TPFLAGS_HAVE_STACKLESS_EXTENSION : 0;
1874
+
1875
+ if (python_major_version >= 3) {
1876
+ return stackless_extension_flag | Py_TPFLAGS_HAVE_VERSION_TAG;
1877
+ }
1878
+ else {
1879
+ return stackless_extension_flag |
1880
+ Py_TPFLAGS_HAVE_GETCHARBUFFER |
1881
+ Py_TPFLAGS_HAVE_SEQUENCE_IN |
1882
+ Py_TPFLAGS_HAVE_INPLACEOPS |
1883
+ Py_TPFLAGS_HAVE_RICHCOMPARE |
1884
+ Py_TPFLAGS_HAVE_WEAKREFS |
1885
+ Py_TPFLAGS_HAVE_ITER |
1886
+ Py_TPFLAGS_HAVE_CLASS |
1887
+ Py_TPFLAGS_HAVE_INDEX
1888
+ ;
1889
+ }
1890
+ }
1891
+
1892
+ PyObject *
1893
+ pycall_pystring_from_format(char const *format, ...)
1894
+ {
1895
+ va_list vargs;
1896
+ PyObject *res;
1897
+
1898
+ va_start(vargs, format);
1899
+ res = pycall_pystring_from_formatv(format, vargs);
1900
+ va_end(vargs);
1901
+
1902
+ return res;
1903
+ }
1904
+
1905
+ PyObject *
1906
+ pycall_pystring_from_formatv(char const *format, va_list vargs)
1907
+ {
1908
+ if (python_is_unicode_literals)
1909
+ return Py_API(PyUnicode_FromFormatV)(format, vargs);
1910
+ else
1911
+ return Py_API(PyString_FromFormatV)(format, vargs);
1912
+ }
1913
+
1914
+ /* ==== Python ==== */
1915
+
1916
+ static void
1917
+ init_python(void)
1918
+ {
1919
+ static char const *argv[1] = { "" };
1920
+
1921
+ Py_API(Py_InitializeEx)(0);
1922
+ Py_API(PySys_SetArgvEx)(0, (char **)argv, 0);
1923
+
1924
+ /* check the availability of stackless extension */
1925
+ python_has_stackless_extension = (Py_API(PyImport_ImportModule)("stackless") != NULL);
1926
+ if (!python_has_stackless_extension) {
1927
+ Py_API(PyErr_Clear)();
1928
+ }
1929
+
1930
+ /* builtins module */
1931
+ {
1932
+ char const *builtins_module_name = (python_major_version < 3) ? "__builtin__" : "builtins";
1933
+ python_builtins_module = Py_API(PyImport_ImportModule)(builtins_module_name);
1934
+ }
1935
+
1936
+ /* sys module */
1937
+
1938
+ {
1939
+ PyObject *sys, *hexversion;
1940
+ sys = Py_API(PyImport_ImportModule)("sys");
1941
+
1942
+ /* hexversion */
1943
+
1944
+ hexversion = Py_API(PyObject_GetAttrString)(sys, "hexversion");
1945
+ if (Py_API(PyInt_Type))
1946
+ python_hexversion = Py_API(PyInt_AsSsize_t)(hexversion);
1947
+ else
1948
+ python_hexversion = Py_API(PyLong_AsSsize_t)(hexversion);
1949
+ }
1950
+
1951
+ /* constants */
1952
+
1953
+ Py_API(Py_IncRef)(Py_API(_Py_NoneStruct));
1954
+ rb_define_const(mAPI, "None", pycall_pyptr_new(Py_API(_Py_NoneStruct)));
1955
+
1956
+ Py_API(Py_IncRef)((PyObject *)Py_API(PyBool_Type));
1957
+ rb_define_const(mAPI, "PyBool_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyBool_Type)));
1958
+ if (Py_API(PyClass_Type)) {
1959
+ Py_API(Py_IncRef)((PyObject *)Py_API(PyClass_Type));
1960
+ rb_define_const(mAPI, "PyClass_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyClass_Type)));
1961
+ }
1962
+ Py_API(Py_IncRef)((PyObject *)Py_API(PyDict_Type));
1963
+ rb_define_const(mAPI, "PyDict_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyDict_Type)));
1964
+ Py_API(Py_IncRef)((PyObject *)Py_API(PyFloat_Type));
1965
+ rb_define_const(mAPI, "PyFloat_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyFloat_Type)));
1966
+ Py_API(Py_IncRef)((PyObject *)Py_API(PyInt_Type));
1967
+ rb_define_const(mAPI, "PyInt_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyInt_Type)));
1968
+ Py_API(Py_IncRef)((PyObject *)Py_API(PyList_Type));
1969
+ rb_define_const(mAPI, "PyList_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyList_Type)));
1970
+ Py_API(Py_IncRef)((PyObject *)Py_API(PyLong_Type));
1971
+ rb_define_const(mAPI, "PyLong_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyLong_Type)));
1972
+ Py_API(Py_IncRef)((PyObject *)Py_API(PyModule_Type));
1973
+ rb_define_const(mAPI, "PyModule_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyModule_Type)));
1974
+ Py_API(Py_IncRef)((PyObject *)Py_API(PyString_Type));
1975
+ rb_define_const(mAPI, "PyString_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyString_Type)));
1976
+ Py_API(Py_IncRef)((PyObject *)Py_API(PyType_Type));
1977
+ rb_define_const(mAPI, "PyType_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyType_Type)));
1978
+ Py_API(Py_IncRef)((PyObject *)Py_API(PyUnicode_Type));
1979
+ rb_define_const(mAPI, "PyUnicode_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyUnicode_Type)));
1980
+
1981
+ pycall_init_exceptions(pycall_libpython_handle);
1982
+ }
1983
+
1984
+ static VALUE
1985
+ pycall_tuple_s_new(int argc, VALUE *argv, VALUE klass)
1986
+ {
1987
+ VALUE obj;
1988
+ PyObject *pyobj;
1989
+ int i;
1990
+
1991
+ pyobj = Py_API(PyTuple_New)(argc);
1992
+ for (i = 0; i < argc; ++i) {
1993
+ Py_API(PyTuple_SetItem)(pyobj, i, pycall_pyobject_from_ruby(argv[i]));
1994
+
1995
+ /* NOTE: Although PyTuple_SetItem steals the item reference,
1996
+ * it is unnecessary to call Py_IncRef for the item because
1997
+ * pycall_pyobject_from_ruby increments the reference count
1998
+ * of its result. */
1999
+ }
2000
+
2001
+ obj = pycall_pyobject_wrapper_object_new(klass, pyobj);
2002
+ return obj;
2003
+ }
2004
+
2005
+ static VALUE
2006
+ pycall_tuple_length(VALUE obj)
2007
+ {
2008
+ PyObject *pyobj;
2009
+ Py_ssize_t n;
2010
+
2011
+ pyobj = pycall_pyobject_wrapper_check_get_pyobj_ptr(obj, Py_API(PyTuple_Type));
2012
+
2013
+ n = Py_API(PyTuple_Size)(pyobj);
2014
+ return SSIZET2NUM(n);
2015
+ }
2016
+
2017
+ static VALUE
2018
+ pycall_tuple_to_a(VALUE obj)
2019
+ {
2020
+ PyObject *pyobj;
2021
+
2022
+ pyobj = pycall_pyobject_wrapper_check_get_pyobj_ptr(obj, Py_API(PyTuple_Type));
2023
+
2024
+ return pycall_pytuple_to_a(pyobj);
2025
+ }
2026
+
2027
+ static VALUE
2028
+ pycall_pyerror_s_occurred_p(VALUE klass)
2029
+ {
2030
+ return Py_API(PyErr_Occurred)() != NULL ? Qtrue : Qfalse;
2031
+ }
2032
+
2033
+ static VALUE
2034
+ pycall_pyerror_s_fetch(VALUE klass)
2035
+ {
2036
+ return pycall_pyerror_fetch();
2037
+ }
2038
+
2039
+ static void
2040
+ init_pyerror(void)
2041
+ {
2042
+ rb_define_singleton_method(cPyError, "occurred?", pycall_pyerror_s_occurred_p, 0);
2043
+ rb_define_singleton_method(cPyError, "fetch", pycall_pyerror_s_fetch, 0);
2044
+ }
2045
+
2046
+ static void
2047
+ init_tuple(void)
2048
+ {
2049
+ cTuple = rb_funcall(mPyCall, rb_intern("wrap_class"), 1, pycall_pytypeptr_new((PyObject *)Py_API(PyTuple_Type)));
2050
+ rb_define_const(mPyCall, "Tuple", cTuple);
2051
+ rb_funcall(cTuple, rb_intern("register_python_type_mapping"), 0);
2052
+ rb_define_singleton_method(cTuple, "new", pycall_tuple_s_new, -1);
2053
+ rb_define_method(cTuple, "length", pycall_tuple_length, 0);
2054
+ rb_define_method(cTuple, "to_a", pycall_tuple_to_a, 0);
2055
+ }
2056
+
2057
+ void
2058
+ Init_pycall(void)
2059
+ {
2060
+ pycall_hash_salt = FIX2LONG(rb_hash(rb_str_new2("PyCall::PyObject")));
2061
+
2062
+ mPyCall = rb_define_module("PyCall");
2063
+ mPyObjectWrapper = rb_const_get_at(mPyCall, rb_intern("PyObjectWrapper"));
2064
+ mPyTypeObjectWrapper = rb_const_get_at(mPyCall, rb_intern("PyTypeObjectWrapper"));
2065
+ mGCGuard = rb_define_module_under(mPyCall, "GCGuard");
2066
+ eError = rb_const_get_at(mPyCall, rb_intern("Error"));
2067
+ cPyError = rb_const_get_at(mPyCall, rb_intern("PyError"));
2068
+
2069
+ /* PyCall */
2070
+
2071
+ rb_define_module_function(mPyCall, "after_fork", pycall_after_fork, 0);
2072
+
2073
+ /* PyCall::PyPtr */
2074
+
2075
+ cPyPtr = rb_define_class_under(mPyCall, "PyPtr", rb_cBasicObject);
2076
+ rb_define_singleton_method(cPyPtr, "incref", pycall_pyptr_s_incref, 1);
2077
+ rb_define_singleton_method(cPyPtr, "decref", pycall_pyptr_s_decref, 1);
2078
+ rb_define_singleton_method(cPyPtr, "sizeof", pycall_pyptr_s_sizeof, 1);
2079
+
2080
+ rb_define_alloc_func(cPyPtr, pycall_pyptr_allocate);
2081
+ rb_define_method(cPyPtr, "initialize", pycall_pyptr_initialize, 1);
2082
+ rb_define_method(cPyPtr, "null?", pycall_pyptr_is_null, 0);
2083
+ rb_define_method(cPyPtr, "none?", pycall_pyptr_is_none, 0);
2084
+ rb_define_method(cPyPtr, "nil?", pycall_pyptr_is_nil, 0);
2085
+ rb_define_method(cPyPtr, "==", pycall_pyptr_eq, 1);
2086
+ rb_define_method(cPyPtr, "===", pycall_pyptr_eq, 1);
2087
+ rb_define_method(cPyPtr, "eql?", pycall_pyptr_eq, 1);
2088
+ rb_define_method(cPyPtr, "hash", pycall_pyptr_hash, 0);
2089
+ rb_define_method(cPyPtr, "__address__", pycall_pyptr_get_ptr_address, 0);
2090
+ rb_define_method(cPyPtr, "__ob_refcnt__", pycall_pyptr_get_ob_refcnt, 0);
2091
+ rb_define_method(cPyPtr, "__ob_type__", pycall_pyptr_get_ob_type, 0);
2092
+ rb_define_method(cPyPtr, "object_id", pycall_pyptr_object_id, 0);
2093
+ rb_define_method(cPyPtr, "class", pycall_pyptr_class, 0);
2094
+ rb_define_method(cPyPtr, "inspect", pycall_pyptr_inspect, 0);
2095
+ rb_define_method(cPyPtr, "kind_of?", pycall_pyptr_is_kind_of, 1);
2096
+ rb_define_method(cPyPtr, "is_a?", pycall_pyptr_is_kind_of, 1);
2097
+
2098
+ rb_define_const(cPyPtr, "NULL", pycall_pyptr_new(NULL));
2099
+
2100
+ /* PyCall::PyTypePtr */
2101
+
2102
+ cPyTypePtr = rb_define_class_under(mPyCall, "PyTypePtr", cPyPtr);
2103
+ rb_define_alloc_func(cPyTypePtr, pycall_pytypeptr_allocate);
2104
+ rb_define_method(cPyTypePtr, "__ob_size__", pycall_pytypeptr_get_ob_size, 0);
2105
+ rb_define_method(cPyTypePtr, "__tp_name__", pycall_pytypeptr_get_tp_name, 0);
2106
+ rb_define_method(cPyTypePtr, "__tp_basicsize__", pycall_pytypeptr_get_tp_basicsize, 0);
2107
+ rb_define_method(cPyTypePtr, "__tp_flags__", pycall_pytypeptr_get_tp_flags, 0);
2108
+ rb_define_method(cPyTypePtr, "===", pycall_pytypeptr_eqq, 1);
2109
+
2110
+ /* PyCall::LibPython::API */
2111
+
2112
+ mLibPython = rb_define_module_under(mPyCall, "LibPython");
2113
+ pycall_libpython_handle = rb_funcall(mLibPython, rb_intern("handle"), 0);
2114
+ pycall_init_libpython_api_table(pycall_libpython_handle);
2115
+
2116
+ mAPI = rb_define_module_under(mLibPython, "API");
2117
+
2118
+ rb_define_module_function(mAPI, "builtins_module_ptr", pycall_libpython_api_get_builtins_module_ptr, 0);
2119
+
2120
+ rb_define_module_function(mAPI, "PyObject_Dir", pycall_libpython_api_PyObject_Dir, 1);
2121
+ rb_define_module_function(mAPI, "PyList_Size", pycall_libpython_api_PyList_Size, 1);
2122
+ rb_define_module_function(mAPI, "PyList_GetItem", pycall_libpython_api_PyList_GetItem, 2);
2123
+
2124
+ /* PyCall::LibPython::Helpers */
2125
+
2126
+ mHelpers = rb_define_module_under(mLibPython, "Helpers");
2127
+
2128
+ rb_define_module_function(mHelpers, "unicode_literals?", pycall_libpython_helpers_m_unicode_literals_p, 0);
2129
+ rb_define_module_function(mHelpers, "import_module", pycall_libpython_helpers_m_import_module, -1);
2130
+ rb_define_module_function(mHelpers, "define_wrapper_method", pycall_libpython_helpers_m_define_wrapper_method, 2);
2131
+ rb_define_module_function(mHelpers, "compare", pycall_libpython_helpers_m_compare, 3);
2132
+ rb_define_module_function(mHelpers, "getattr", pycall_libpython_helpers_m_getattr, -1);
2133
+ rb_define_module_function(mHelpers, "hasattr?", pycall_libpython_helpers_m_hasattr_p, 2);
2134
+ rb_define_module_function(mHelpers, "callable?", pycall_libpython_helpers_m_callable_p, 1);
2135
+ rb_define_module_function(mHelpers, "call_object", pycall_libpython_helpers_m_call_object, -1);
2136
+ rb_define_module_function(mHelpers, "getitem", pycall_libpython_helpers_m_getitem, 2);
2137
+ rb_define_module_function(mHelpers, "setitem", pycall_libpython_helpers_m_setitem, 3);
2138
+ rb_define_module_function(mHelpers, "delitem", pycall_libpython_helpers_m_delitem, 2);
2139
+ rb_define_module_function(mHelpers, "str", pycall_libpython_helpers_m_str, 1);
2140
+ rb_define_module_function(mHelpers, "dict_contains", pycall_libpython_helpers_m_dict_contains, 2);
2141
+ rb_define_module_function(mHelpers, "dict_each", pycall_libpython_helpers_m_dict_each, 1);
2142
+ rb_define_module_function(mHelpers, "sequence_contains", pycall_libpython_helpers_m_sequence_contains, 2);
2143
+ rb_define_module_function(mHelpers, "sequence_each", pycall_libpython_helpers_m_sequence_each, 1);
2144
+
2145
+ /* PyCall::Conversion */
2146
+
2147
+ mConversion = rb_define_module_under(mPyCall, "Conversion");
2148
+
2149
+ rb_define_module_function(mConversion, "register_python_type_mapping", pycall_conv_m_register_python_type_mapping, 2);
2150
+ rb_define_module_function(mConversion, "unregister_python_type_mapping", pycall_conv_m_unregister_python_type_mapping, 1);
2151
+ rb_define_module_function(mConversion, "from_ruby", pycall_conv_m_from_ruby, 1);
2152
+ rb_define_module_function(mConversion, "to_ruby", pycall_conv_m_to_ruby, 1);
2153
+
2154
+ python_type_mapping = rb_hash_new();
2155
+ id_python_type_mapping = rb_intern("__python_type_mapping__");
2156
+ rb_ivar_set(mConversion, id_python_type_mapping, python_type_mapping);
2157
+
2158
+ /* initialize the constat PYTHON_VERSION */
2159
+
2160
+ python_description = rb_str_new2(Py_API(Py_GetVersion)());
2161
+ rb_define_const(mLibPython, "PYTHON_DESCRIPTION", python_description);
2162
+
2163
+ {
2164
+ char *space_pos, *first_dot_pos;
2165
+
2166
+ space_pos = memchr(RSTRING_PTR(python_description), ' ', RSTRING_LEN(python_description));
2167
+ python_version_string = rb_str_subseq(python_description, 0, space_pos - RSTRING_PTR(python_description));
2168
+
2169
+ /* extract major version */
2170
+ first_dot_pos = memchr(RSTRING_PTR(python_version_string), '.', RSTRING_LEN(python_version_string));
2171
+ *first_dot_pos = '\0';
2172
+ python_major_version = (int)strtol(RSTRING_PTR(python_version_string), (char **)NULL, 10);
2173
+ *first_dot_pos = '.';
2174
+ }
2175
+ rb_define_const(mLibPython, "PYTHON_VERSION", python_version_string);
2176
+
2177
+ /* initialize Python interpreter */
2178
+
2179
+ init_python();
2180
+ init_pyerror();
2181
+ init_tuple();
2182
+ pycall_init_gcguard();
2183
+ pycall_init_ruby_wrapper();
2184
+ }