pycall 1.5.2 → 1.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +7 -8
- data/.github/workflows/ci.yml +23 -25
- data/.github/workflows/release.yml +48 -0
- data/.github/workflows/windows.yml +18 -17
- data/CHANGES.md +16 -0
- data/README.md +20 -46
- data/Rakefile +11 -0
- data/docker/Dockerfile +1 -1
- data/ext/pycall/pycall.c +173 -39
- data/ext/pycall/pycall_internal.h +2 -3
- data/ext/pycall/ruby_wrapper.c +5 -69
- data/lib/pycall/libpython/pytypeobject_struct.rb +1 -1
- data/lib/pycall/pyobject_wrapper.rb +2 -3
- data/lib/pycall/version.rb +1 -1
- data/lib/pycall.rb +1 -1
- data/pycall.gemspec +7 -15
- metadata +15 -36
- data/bin/guard +0 -17
- data/ci/travis_before_script.sh +0 -21
- data/ci/travis_install.sh +0 -69
- data/ci/travis_retry.sh +0 -19
- data/config/Guardfile +0 -30
data/ext/pycall/pycall.c
CHANGED
|
@@ -10,28 +10,58 @@ VALUE mLibPython;
|
|
|
10
10
|
VALUE mAPI;
|
|
11
11
|
VALUE mHelpers;
|
|
12
12
|
VALUE mConversion;
|
|
13
|
-
VALUE mPyObjectWrapper;
|
|
14
|
-
VALUE mPyTypeObjectWrapper;
|
|
15
13
|
VALUE mGCGuard;
|
|
16
14
|
|
|
17
15
|
VALUE pycall_cPyPtr;
|
|
18
16
|
VALUE cPyTypePtr;
|
|
19
|
-
VALUE cTuple;
|
|
20
|
-
VALUE cPyError;
|
|
21
17
|
|
|
22
|
-
VALUE pycall_eError;
|
|
23
|
-
|
|
24
|
-
static VALUE pycall_libpython_handle;
|
|
25
18
|
static VALUE python_description;
|
|
26
19
|
static VALUE python_version_string;
|
|
27
20
|
static Py_ssize_t python_hexversion;
|
|
28
21
|
static int python_major_version;
|
|
29
22
|
static int python_has_stackless_extension;
|
|
30
23
|
static PyObject *python_builtins_module;
|
|
31
|
-
static VALUE python_type_mapping;
|
|
32
|
-
static VALUE python_type_mapping;
|
|
33
24
|
static ID id_python_type_mapping;
|
|
34
25
|
|
|
26
|
+
/* Don't keep Ruby objects that aren't pinned in C global variables.
|
|
27
|
+
* They may be moved by GC compaction. */
|
|
28
|
+
|
|
29
|
+
static inline VALUE
|
|
30
|
+
libpython_handle(void)
|
|
31
|
+
{
|
|
32
|
+
return rb_funcall(mLibPython, rb_intern("handle"), 0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static inline VALUE
|
|
36
|
+
pyobject_wrapper_module(void)
|
|
37
|
+
{
|
|
38
|
+
return rb_const_get_at(mPyCall, rb_intern("PyObjectWrapper"));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static inline VALUE
|
|
42
|
+
pytypeobject_wrapper_module(void)
|
|
43
|
+
{
|
|
44
|
+
return rb_const_get_at(mPyCall, rb_intern("PyTypeObjectWrapper"));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static inline VALUE
|
|
48
|
+
error_class(void)
|
|
49
|
+
{
|
|
50
|
+
return rb_const_get_at(mPyCall, rb_intern("Error"));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static inline VALUE
|
|
54
|
+
pyerror_class(void)
|
|
55
|
+
{
|
|
56
|
+
return rb_const_get_at(mPyCall, rb_intern("PyError"));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static inline VALUE
|
|
60
|
+
python_type_mapping(void)
|
|
61
|
+
{
|
|
62
|
+
return rb_ivar_get(mConversion, id_python_type_mapping);
|
|
63
|
+
}
|
|
64
|
+
|
|
35
65
|
int
|
|
36
66
|
pycall_python_major_version(void)
|
|
37
67
|
{
|
|
@@ -122,6 +152,58 @@ pycall_m_without_gvl(VALUE mod)
|
|
|
122
152
|
|
|
123
153
|
/* ==== PyCall::PyPtr ==== */
|
|
124
154
|
|
|
155
|
+
struct pending_decref_list {
|
|
156
|
+
rb_nativethread_lock_t lock;
|
|
157
|
+
PyObject **pyptrs;
|
|
158
|
+
size_t count;
|
|
159
|
+
size_t capacity;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
static struct pending_decref_list pending_decrefs;
|
|
163
|
+
|
|
164
|
+
static void
|
|
165
|
+
pycall_pending_decref_add(PyObject *pyobj)
|
|
166
|
+
{
|
|
167
|
+
rb_nativethread_lock_lock(&pending_decrefs.lock);
|
|
168
|
+
if (pending_decrefs.count == pending_decrefs.capacity) {
|
|
169
|
+
size_t new_capacity = pending_decrefs.capacity ? 2 * pending_decrefs.capacity : 64;
|
|
170
|
+
/* Not ruby_xrealloc: this function runs during GC, where xmalloc/xrealloc
|
|
171
|
+
* are prohibited (rb_bug "Cannot realloc during GC" since Ruby 3.3). */
|
|
172
|
+
PyObject **new_pyptrs = realloc(pending_decrefs.pyptrs, new_capacity * sizeof(PyObject *));
|
|
173
|
+
if (new_pyptrs == NULL) {
|
|
174
|
+
/* Leaking the object is preferable to blocking or crashing inside GC */
|
|
175
|
+
rb_nativethread_lock_unlock(&pending_decrefs.lock);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
pending_decrefs.pyptrs = new_pyptrs;
|
|
179
|
+
pending_decrefs.capacity = new_capacity;
|
|
180
|
+
}
|
|
181
|
+
pending_decrefs.pyptrs[pending_decrefs.count++] = pyobj;
|
|
182
|
+
rb_nativethread_lock_unlock(&pending_decrefs.lock);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
static void
|
|
186
|
+
pycall_drain_pending_decrefs(void)
|
|
187
|
+
{
|
|
188
|
+
PyObject **pyptrs;
|
|
189
|
+
size_t i, count;
|
|
190
|
+
|
|
191
|
+
if (pending_decrefs.count == 0) return;
|
|
192
|
+
|
|
193
|
+
rb_nativethread_lock_lock(&pending_decrefs.lock);
|
|
194
|
+
pyptrs = pending_decrefs.pyptrs;
|
|
195
|
+
count = pending_decrefs.count;
|
|
196
|
+
pending_decrefs.pyptrs = NULL;
|
|
197
|
+
pending_decrefs.count = 0;
|
|
198
|
+
pending_decrefs.capacity = 0;
|
|
199
|
+
rb_nativethread_lock_unlock(&pending_decrefs.lock);
|
|
200
|
+
|
|
201
|
+
for (i = 0; i < count; ++i) {
|
|
202
|
+
pycall_Py_DecRef(pyptrs[i]);
|
|
203
|
+
}
|
|
204
|
+
free(pyptrs);
|
|
205
|
+
}
|
|
206
|
+
|
|
125
207
|
const rb_data_type_t pycall_pyptr_data_type = {
|
|
126
208
|
"PyCall::PyPtr",
|
|
127
209
|
{ 0, pycall_pyptr_free, pycall_pyptr_memsize, },
|
|
@@ -130,6 +212,11 @@ const rb_data_type_t pycall_pyptr_data_type = {
|
|
|
130
212
|
#endif
|
|
131
213
|
};
|
|
132
214
|
|
|
215
|
+
/* pycall_pyptr_free may be called by the GC sweeper on a thread that does
|
|
216
|
+
* not hold the GIL. PyCall keeps the GIL held by the thread that
|
|
217
|
+
* initialized Python for the entire lifetime of the process, so waiting
|
|
218
|
+
* for the GIL there (PyGILState_Ensure) blocks forever while the sweeper
|
|
219
|
+
* holds the GVL, freezing every Ruby thread in the process. */
|
|
133
220
|
void
|
|
134
221
|
pycall_pyptr_free(void *ptr)
|
|
135
222
|
{
|
|
@@ -144,9 +231,9 @@ pycall_pyptr_free(void *ptr)
|
|
|
144
231
|
pycall_Py_DecRef(pyobj);
|
|
145
232
|
}
|
|
146
233
|
else {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
234
|
+
/* Instead of taking the GIL here, enqueue the pointer; the list is
|
|
235
|
+
* drained on the next Python call. */
|
|
236
|
+
pycall_pending_decref_add(pyobj);
|
|
150
237
|
}
|
|
151
238
|
}
|
|
152
239
|
|
|
@@ -628,6 +715,8 @@ pycall_libpython_api_PyObject_Dir(VALUE mod, VALUE pyptr)
|
|
|
628
715
|
PyObject *dir;
|
|
629
716
|
PyObject *pyobj;
|
|
630
717
|
|
|
718
|
+
pycall_drain_pending_decrefs();
|
|
719
|
+
|
|
631
720
|
if (!is_pycall_pyptr(pyptr)) {
|
|
632
721
|
rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
|
|
633
722
|
}
|
|
@@ -647,6 +736,8 @@ pycall_libpython_api_PyList_Size(VALUE mod, VALUE pyptr)
|
|
|
647
736
|
PyObject *pyobj;
|
|
648
737
|
Py_ssize_t size;
|
|
649
738
|
|
|
739
|
+
pycall_drain_pending_decrefs();
|
|
740
|
+
|
|
650
741
|
if (!is_pycall_pyptr(pyptr)) {
|
|
651
742
|
rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
|
|
652
743
|
}
|
|
@@ -667,6 +758,8 @@ pycall_libpython_api_PyList_GetItem(VALUE mod, VALUE pyptr, VALUE idx)
|
|
|
667
758
|
PyObject *pyobj_item;
|
|
668
759
|
Py_ssize_t i;
|
|
669
760
|
|
|
761
|
+
pycall_drain_pending_decrefs();
|
|
762
|
+
|
|
670
763
|
if (!is_pycall_pyptr(pyptr)) {
|
|
671
764
|
rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
|
|
672
765
|
}
|
|
@@ -732,6 +825,8 @@ pycall_libpython_helpers_m_import_module(int argc, VALUE *argv, VALUE mod)
|
|
|
732
825
|
VALUE name, globals, locals, fromlist, level;
|
|
733
826
|
char const *name_cstr;
|
|
734
827
|
|
|
828
|
+
pycall_drain_pending_decrefs();
|
|
829
|
+
|
|
735
830
|
rb_scan_args(argc, argv, "14", &name, &globals, &locals, &fromlist, &level);
|
|
736
831
|
|
|
737
832
|
if (RB_TYPE_P(name, T_SYMBOL)) {
|
|
@@ -784,6 +879,8 @@ pycall_libpython_helpers_m_compare(VALUE mod, VALUE op, VALUE pyptr_a, VALUE pyp
|
|
|
784
879
|
PyObject *pyobj_a, *pyobj_b, *res;
|
|
785
880
|
int opid;
|
|
786
881
|
|
|
882
|
+
pycall_drain_pending_decrefs();
|
|
883
|
+
|
|
787
884
|
opid = pycall_rich_compare_opid(op);
|
|
788
885
|
|
|
789
886
|
if (!is_pycall_pyptr(pyptr_a)) {
|
|
@@ -838,6 +935,8 @@ pycall_libpython_helpers_m_getattr(int argc, VALUE *argv, VALUE mod)
|
|
|
838
935
|
{
|
|
839
936
|
VALUE pyptr, name, default_value;
|
|
840
937
|
|
|
938
|
+
pycall_drain_pending_decrefs();
|
|
939
|
+
|
|
841
940
|
if (rb_scan_args(argc, argv, "21", &pyptr, &name, &default_value) == 2) {
|
|
842
941
|
default_value = Qundef;
|
|
843
942
|
}
|
|
@@ -859,6 +958,8 @@ pycall_libpython_helpers_m_hasattr_p(VALUE mod, VALUE pyptr, VALUE name)
|
|
|
859
958
|
PyObject *pyobj;
|
|
860
959
|
int res;
|
|
861
960
|
|
|
961
|
+
pycall_drain_pending_decrefs();
|
|
962
|
+
|
|
862
963
|
if (!is_pycall_pyptr(pyptr)) {
|
|
863
964
|
rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
|
|
864
965
|
}
|
|
@@ -878,6 +979,8 @@ pycall_libpython_helpers_m_setattr(VALUE mod, VALUE pyptr, VALUE name, VALUE val
|
|
|
878
979
|
{
|
|
879
980
|
PyObject *pyobj, *pyval;
|
|
880
981
|
|
|
982
|
+
pycall_drain_pending_decrefs();
|
|
983
|
+
|
|
881
984
|
if (!is_pycall_pyptr(pyptr)) {
|
|
882
985
|
rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
|
|
883
986
|
}
|
|
@@ -901,6 +1004,8 @@ pycall_libpython_helpers_m_delattr(VALUE mod, VALUE pyptr, VALUE name)
|
|
|
901
1004
|
{
|
|
902
1005
|
PyObject *pyobj;
|
|
903
1006
|
|
|
1007
|
+
pycall_drain_pending_decrefs();
|
|
1008
|
+
|
|
904
1009
|
if (!is_pycall_pyptr(pyptr)) {
|
|
905
1010
|
rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
|
|
906
1011
|
}
|
|
@@ -924,6 +1029,8 @@ pycall_libpython_helpers_m_callable_p(VALUE mod, VALUE pyptr)
|
|
|
924
1029
|
PyObject *pyobj;
|
|
925
1030
|
int res;
|
|
926
1031
|
|
|
1032
|
+
pycall_drain_pending_decrefs();
|
|
1033
|
+
|
|
927
1034
|
if (!is_pycall_pyptr(pyptr)) {
|
|
928
1035
|
rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
|
|
929
1036
|
}
|
|
@@ -940,6 +1047,8 @@ pycall_libpython_helpers_m_call_object(int argc, VALUE *argv, VALUE mod)
|
|
|
940
1047
|
VALUE pyptr;
|
|
941
1048
|
PyObject *pyobj;
|
|
942
1049
|
|
|
1050
|
+
pycall_drain_pending_decrefs();
|
|
1051
|
+
|
|
943
1052
|
if (argc < 1) {
|
|
944
1053
|
rb_raise(rb_eArgError, "too few arguments (%d for >=1)", argc);
|
|
945
1054
|
}
|
|
@@ -1089,6 +1198,8 @@ pycall_pyobject_wrapper_wrapper_method(int argc, VALUE *argv, VALUE wrapper)
|
|
|
1089
1198
|
char *name_cstr;
|
|
1090
1199
|
PyObject *pyobj, *attr;
|
|
1091
1200
|
|
|
1201
|
+
pycall_drain_pending_decrefs();
|
|
1202
|
+
|
|
1092
1203
|
pyptr = rb_attr_get(wrapper, rb_intern("@__pyptr__"));
|
|
1093
1204
|
if (NIL_P(pyptr) || !is_pycall_pyptr(pyptr)) {
|
|
1094
1205
|
rb_raise(rb_eTypeError, "Wrong wrapper object is given");
|
|
@@ -1144,6 +1255,8 @@ pycall_libpython_helpers_m_define_wrapper_method(VALUE mod, VALUE wrapper, VALUE
|
|
|
1144
1255
|
PyObject *pyobj, *attr;
|
|
1145
1256
|
char *name_cstr;
|
|
1146
1257
|
|
|
1258
|
+
pycall_drain_pending_decrefs();
|
|
1259
|
+
|
|
1147
1260
|
pyptr = rb_attr_get(wrapper, rb_intern("@__pyptr__"));
|
|
1148
1261
|
if (NIL_P(pyptr) || !is_pycall_pyptr(pyptr)) {
|
|
1149
1262
|
rb_raise(rb_eTypeError, "Wrong wrapper object is given");
|
|
@@ -1191,10 +1304,10 @@ pycall_convert_index(VALUE index)
|
|
|
1191
1304
|
}
|
|
1192
1305
|
}
|
|
1193
1306
|
else if (rb_obj_is_kind_of(index, rb_cRange)) {
|
|
1194
|
-
pyobj = pycall_pyslice_from_ruby(index); /* New
|
|
1307
|
+
pyobj = pycall_pyslice_from_ruby(index); /* New reference */
|
|
1195
1308
|
}
|
|
1196
1309
|
else if (pycall_obj_is_step_range(index)) {
|
|
1197
|
-
pyobj = pycall_pyslice_from_ruby(index); /* New
|
|
1310
|
+
pyobj = pycall_pyslice_from_ruby(index); /* New reference */
|
|
1198
1311
|
}
|
|
1199
1312
|
else {
|
|
1200
1313
|
pyobj = pycall_pyobject_from_ruby(index); /* New reference */
|
|
@@ -1209,6 +1322,8 @@ pycall_libpython_helpers_m_getitem(VALUE mod, VALUE pyptr, VALUE key)
|
|
|
1209
1322
|
PyObject *pyobj, *pyobj_key, *pyobj_v;
|
|
1210
1323
|
VALUE obj;
|
|
1211
1324
|
|
|
1325
|
+
pycall_drain_pending_decrefs();
|
|
1326
|
+
|
|
1212
1327
|
if (!is_pycall_pyptr(pyptr)) {
|
|
1213
1328
|
rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
|
|
1214
1329
|
}
|
|
@@ -1234,6 +1349,8 @@ pycall_libpython_helpers_m_setitem(VALUE mod, VALUE pyptr, VALUE key, VALUE v)
|
|
|
1234
1349
|
PyObject *pyobj, *pyobj_key, *pyobj_value;
|
|
1235
1350
|
int res;
|
|
1236
1351
|
|
|
1352
|
+
pycall_drain_pending_decrefs();
|
|
1353
|
+
|
|
1237
1354
|
pyobj = check_get_pyobj_ptr(pyptr, NULL);
|
|
1238
1355
|
pyobj_key = pycall_convert_index(key);
|
|
1239
1356
|
pyobj_value = pycall_pyobject_from_ruby(v);
|
|
@@ -1254,6 +1371,8 @@ pycall_libpython_helpers_m_delitem(VALUE mod, VALUE pyptr, VALUE key)
|
|
|
1254
1371
|
PyObject *pyobj, *pyobj_key;
|
|
1255
1372
|
int res;
|
|
1256
1373
|
|
|
1374
|
+
pycall_drain_pending_decrefs();
|
|
1375
|
+
|
|
1257
1376
|
pyobj = check_get_pyobj_ptr(pyptr, NULL);
|
|
1258
1377
|
pyobj_key = pycall_convert_index(key);
|
|
1259
1378
|
|
|
@@ -1271,6 +1390,8 @@ pycall_libpython_helpers_m_str(VALUE mod, VALUE pyptr)
|
|
|
1271
1390
|
{
|
|
1272
1391
|
PyObject *pyobj, *pyobj_str;
|
|
1273
1392
|
|
|
1393
|
+
pycall_drain_pending_decrefs();
|
|
1394
|
+
|
|
1274
1395
|
pyobj = check_get_pyobj_ptr(pyptr, NULL);
|
|
1275
1396
|
|
|
1276
1397
|
pyobj_str = Py_API(PyObject_Str)(pyobj);
|
|
@@ -1289,6 +1410,8 @@ pycall_libpython_helpers_m_dict_contains(VALUE mod, VALUE pyptr, VALUE key)
|
|
|
1289
1410
|
PyObject *pyobj, *pyobj_key;
|
|
1290
1411
|
int res;
|
|
1291
1412
|
|
|
1413
|
+
pycall_drain_pending_decrefs();
|
|
1414
|
+
|
|
1292
1415
|
pyobj = check_get_pyobj_ptr(pyptr, Py_API(PyDict_Type));
|
|
1293
1416
|
pyobj_key = pycall_pyobject_from_ruby(key);
|
|
1294
1417
|
res = Py_API(PyDict_Contains)(pyobj, pyobj_key);
|
|
@@ -1306,6 +1429,8 @@ pycall_libpython_helpers_m_dict_each(VALUE mod, VALUE pyptr)
|
|
|
1306
1429
|
PyObject *pyobj, *pyobj_key, *pyobj_value;
|
|
1307
1430
|
Py_ssize_t pos;
|
|
1308
1431
|
|
|
1432
|
+
pycall_drain_pending_decrefs();
|
|
1433
|
+
|
|
1309
1434
|
pyobj = check_get_pyobj_ptr(pyptr, Py_API(PyDict_Type));
|
|
1310
1435
|
|
|
1311
1436
|
pos = 0;
|
|
@@ -1325,6 +1450,8 @@ pycall_libpython_helpers_m_sequence_contains(VALUE mod, VALUE pyptr, VALUE key)
|
|
|
1325
1450
|
PyObject *pyobj, *pyobj_key;
|
|
1326
1451
|
int res;
|
|
1327
1452
|
|
|
1453
|
+
pycall_drain_pending_decrefs();
|
|
1454
|
+
|
|
1328
1455
|
pyobj = check_get_pyobj_ptr(pyptr, NULL);
|
|
1329
1456
|
if (!Py_API(PySequence_Check)(pyobj))
|
|
1330
1457
|
rb_raise(rb_eTypeError, "unexpected Python type %s (expected a Python sequence object)", Py_TYPE(pyobj)->tp_name);
|
|
@@ -1344,6 +1471,8 @@ pycall_libpython_helpers_m_sequence_each(VALUE mod, VALUE pyptr)
|
|
|
1344
1471
|
{
|
|
1345
1472
|
PyObject *pyobj, *pyobj_iter, *pyobj_item;
|
|
1346
1473
|
|
|
1474
|
+
pycall_drain_pending_decrefs();
|
|
1475
|
+
|
|
1347
1476
|
pyobj = check_get_pyobj_ptr(pyptr, NULL);
|
|
1348
1477
|
if (!Py_API(PySequence_Check)(pyobj))
|
|
1349
1478
|
rb_raise(rb_eTypeError, "unexpected Python type %s (expected a Python sequence object)", Py_TYPE(pyobj)->tp_name);
|
|
@@ -1372,7 +1501,7 @@ pycall_libpython_helpers_m_sequence_each(VALUE mod, VALUE pyptr)
|
|
|
1372
1501
|
static int
|
|
1373
1502
|
is_pyobject_wrapper(VALUE obj)
|
|
1374
1503
|
{
|
|
1375
|
-
return RTEST(rb_obj_is_kind_of(obj,
|
|
1504
|
+
return RTEST(rb_obj_is_kind_of(obj, pyobject_wrapper_module()));
|
|
1376
1505
|
}
|
|
1377
1506
|
|
|
1378
1507
|
static VALUE
|
|
@@ -1425,7 +1554,7 @@ pycall_python_type_mapping_get_mapped_ancestor_class(VALUE pytypeptr)
|
|
|
1425
1554
|
args[0] = pytypeptr;
|
|
1426
1555
|
args[1] = Qnil;
|
|
1427
1556
|
|
|
1428
|
-
rb_hash_foreach(python_type_mapping, get_mapped_ancestor_class_iter, (VALUE)args);
|
|
1557
|
+
rb_hash_foreach(python_type_mapping(), get_mapped_ancestor_class_iter, (VALUE)args);
|
|
1429
1558
|
|
|
1430
1559
|
return args[1];
|
|
1431
1560
|
}
|
|
@@ -1435,7 +1564,7 @@ pycall_python_type_mapping_get_mapped_class(VALUE pytypeptr)
|
|
|
1435
1564
|
{
|
|
1436
1565
|
VALUE mapped;
|
|
1437
1566
|
(void)check_get_pytypeobj_ptr(pytypeptr);
|
|
1438
|
-
mapped = rb_hash_lookup(python_type_mapping, pytypeptr);
|
|
1567
|
+
mapped = rb_hash_lookup(python_type_mapping(), pytypeptr);
|
|
1439
1568
|
if (NIL_P(mapped)) {
|
|
1440
1569
|
mapped = pycall_python_type_mapping_get_mapped_ancestor_class(pytypeptr);
|
|
1441
1570
|
}
|
|
@@ -1446,16 +1575,16 @@ static int
|
|
|
1446
1575
|
pycall_python_type_mapping_register(VALUE pytypeptr, VALUE rbcls)
|
|
1447
1576
|
{
|
|
1448
1577
|
(void)check_get_pytypeobj_ptr(pytypeptr);
|
|
1449
|
-
if (rb_hash_lookup2(python_type_mapping, pytypeptr, Qundef) != Qundef)
|
|
1578
|
+
if (rb_hash_lookup2(python_type_mapping(), pytypeptr, Qundef) != Qundef)
|
|
1450
1579
|
return 0;
|
|
1451
1580
|
|
|
1452
1581
|
Check_Type(rbcls, T_CLASS);
|
|
1453
|
-
if (!rb_obj_is_kind_of(rbcls,
|
|
1582
|
+
if (!rb_obj_is_kind_of(rbcls, pytypeobject_wrapper_module())) {
|
|
1454
1583
|
rb_raise(rb_eTypeError, "ruby class must be extended by PyCall::PyTypeObjectWrapper");
|
|
1455
1584
|
}
|
|
1456
1585
|
|
|
1457
1586
|
/* TODO: Shouldn't have to use weak reference? */
|
|
1458
|
-
rb_hash_aset(python_type_mapping, pytypeptr, rbcls);
|
|
1587
|
+
rb_hash_aset(python_type_mapping(), pytypeptr, rbcls);
|
|
1459
1588
|
|
|
1460
1589
|
return 1;
|
|
1461
1590
|
}
|
|
@@ -1464,10 +1593,10 @@ static int
|
|
|
1464
1593
|
pycall_python_type_mapping_unregister(VALUE pytypeptr)
|
|
1465
1594
|
{
|
|
1466
1595
|
(void)check_get_pytypeobj_ptr(pytypeptr);
|
|
1467
|
-
if (rb_hash_lookup2(python_type_mapping, pytypeptr, Qundef) == Qundef)
|
|
1596
|
+
if (rb_hash_lookup2(python_type_mapping(), pytypeptr, Qundef) == Qundef)
|
|
1468
1597
|
return 0;
|
|
1469
1598
|
|
|
1470
|
-
rb_hash_delete(python_type_mapping, pytypeptr);
|
|
1599
|
+
rb_hash_delete(python_type_mapping(), pytypeptr);
|
|
1471
1600
|
return 1;
|
|
1472
1601
|
}
|
|
1473
1602
|
|
|
@@ -1478,7 +1607,7 @@ pycall_pyobject_wrapper_object_new(VALUE klass, PyObject *pyobj)
|
|
|
1478
1607
|
|
|
1479
1608
|
obj = rb_obj_alloc(klass);
|
|
1480
1609
|
rb_ivar_set(obj, rb_intern("@__pyptr__"), pycall_pyptr_new(pyobj));
|
|
1481
|
-
rb_extend_object(obj,
|
|
1610
|
+
rb_extend_object(obj, pyobject_wrapper_module());
|
|
1482
1611
|
|
|
1483
1612
|
return obj;
|
|
1484
1613
|
}
|
|
@@ -1528,7 +1657,7 @@ pycall_pyobject_to_ruby(PyObject *pyobj)
|
|
|
1528
1657
|
Py_API(Py_IncRef)((PyObject *)pyobj->ob_type);
|
|
1529
1658
|
cls = pycall_python_type_mapping_get_mapped_class(pycall_pytypeptr_new((PyObject *)pyobj->ob_type));
|
|
1530
1659
|
if (NIL_P(cls)) {
|
|
1531
|
-
rb_warning("
|
|
1660
|
+
rb_warning("Currently do not support to convert %s to Ruby object", Py_TYPE(pyobj)->tp_name);
|
|
1532
1661
|
return pycall_pyobject_wrapper_object_new(rb_cObject, pyobj);
|
|
1533
1662
|
}
|
|
1534
1663
|
|
|
@@ -1663,7 +1792,7 @@ pycall_pylong_to_ruby(PyObject *pyobj)
|
|
|
1663
1792
|
}
|
|
1664
1793
|
#endif
|
|
1665
1794
|
|
|
1666
|
-
rb_warning("
|
|
1795
|
+
rb_warning("Currently do not support to convert multi-precision PyLong number to Ruby object");
|
|
1667
1796
|
|
|
1668
1797
|
return Qnil;
|
|
1669
1798
|
}
|
|
@@ -1787,7 +1916,11 @@ pycall_conv_m_unregister_python_type_mapping(VALUE mod, VALUE pytypeptr)
|
|
|
1787
1916
|
static VALUE
|
|
1788
1917
|
pycall_conv_m_from_ruby(VALUE mod, VALUE obj)
|
|
1789
1918
|
{
|
|
1790
|
-
PyObject *pyobj
|
|
1919
|
+
PyObject *pyobj;
|
|
1920
|
+
|
|
1921
|
+
pycall_drain_pending_decrefs();
|
|
1922
|
+
|
|
1923
|
+
pyobj = pycall_pyobject_from_ruby(obj);
|
|
1791
1924
|
if (PyType_Check(pyobj) || PyClass_Check(pyobj))
|
|
1792
1925
|
return pycall_pytypeptr_new(pyobj);
|
|
1793
1926
|
if (PyRuby_Check(pyobj))
|
|
@@ -1799,7 +1932,11 @@ static VALUE
|
|
|
1799
1932
|
pycall_conv_m_to_ruby(VALUE mod, VALUE pyptr)
|
|
1800
1933
|
{
|
|
1801
1934
|
VALUE obj, obj_pyptr;
|
|
1802
|
-
PyObject *pyobj
|
|
1935
|
+
PyObject *pyobj;
|
|
1936
|
+
|
|
1937
|
+
pycall_drain_pending_decrefs();
|
|
1938
|
+
|
|
1939
|
+
pyobj = check_get_pyobj_ptr(pyptr, NULL);
|
|
1803
1940
|
obj = obj_pyptr = pycall_pyobject_to_ruby(pyobj);
|
|
1804
1941
|
if (is_pyobject_wrapper(obj)) {
|
|
1805
1942
|
obj_pyptr = pycall_pyobject_wrapper_get_pyptr(obj);
|
|
@@ -2060,7 +2197,7 @@ pycall_pyerror_new(PyObject *type, PyObject *value, PyObject *traceback)
|
|
|
2060
2197
|
init_args[1] = value ? pycall_pyobject_to_ruby(value) : Qnil;
|
|
2061
2198
|
init_args[2] = traceback ? pycall_pyobject_to_ruby(traceback) : Qnil;
|
|
2062
2199
|
|
|
2063
|
-
return rb_class_new_instance(3, init_args,
|
|
2200
|
+
return rb_class_new_instance(3, init_args, pyerror_class());
|
|
2064
2201
|
}
|
|
2065
2202
|
|
|
2066
2203
|
VALUE
|
|
@@ -2094,7 +2231,7 @@ pycall_pyerror_fetch_and_raise(char const *format, ...)
|
|
|
2094
2231
|
msg = rb_vsprintf(format, args);
|
|
2095
2232
|
va_end(args);
|
|
2096
2233
|
|
|
2097
|
-
rb_exc_raise(rb_exc_new3(
|
|
2234
|
+
rb_exc_raise(rb_exc_new3(error_class(), msg));
|
|
2098
2235
|
}
|
|
2099
2236
|
|
|
2100
2237
|
unsigned long
|
|
@@ -2225,7 +2362,7 @@ init_python(void)
|
|
|
2225
2362
|
Py_API(Py_IncRef)((PyObject *)Py_API(PyUnicode_Type));
|
|
2226
2363
|
rb_define_const(mAPI, "PyUnicode_Type", pycall_pytypeptr_new((PyObject *)Py_API(PyUnicode_Type)));
|
|
2227
2364
|
|
|
2228
|
-
pycall_init_exceptions(
|
|
2365
|
+
pycall_init_exceptions(libpython_handle());
|
|
2229
2366
|
}
|
|
2230
2367
|
|
|
2231
2368
|
static VALUE
|
|
@@ -2286,6 +2423,7 @@ pycall_pyerror_s_fetch(VALUE klass)
|
|
|
2286
2423
|
static void
|
|
2287
2424
|
init_pyerror(void)
|
|
2288
2425
|
{
|
|
2426
|
+
VALUE cPyError = pyerror_class();
|
|
2289
2427
|
rb_define_singleton_method(cPyError, "occurred?", pycall_pyerror_s_occurred_p, 0);
|
|
2290
2428
|
rb_define_singleton_method(cPyError, "fetch", pycall_pyerror_s_fetch, 0);
|
|
2291
2429
|
}
|
|
@@ -2293,7 +2431,7 @@ init_pyerror(void)
|
|
|
2293
2431
|
static void
|
|
2294
2432
|
init_tuple(void)
|
|
2295
2433
|
{
|
|
2296
|
-
cTuple = rb_funcall(mPyCall, rb_intern("wrap_class"), 1, pycall_pytypeptr_new((PyObject *)Py_API(PyTuple_Type)));
|
|
2434
|
+
VALUE cTuple = rb_funcall(mPyCall, rb_intern("wrap_class"), 1, pycall_pytypeptr_new((PyObject *)Py_API(PyTuple_Type)));
|
|
2297
2435
|
rb_define_const(mPyCall, "Tuple", cTuple);
|
|
2298
2436
|
rb_funcall(cTuple, rb_intern("register_python_type_mapping"), 0);
|
|
2299
2437
|
rb_define_singleton_method(cTuple, "new", pycall_tuple_s_new, -1);
|
|
@@ -2308,11 +2446,7 @@ Init_pycall(void)
|
|
|
2308
2446
|
pycall_hash_salt = FIX2LONG(rb_hash(rb_str_new2("PyCall::PyObject")));
|
|
2309
2447
|
|
|
2310
2448
|
mPyCall = rb_define_module("PyCall");
|
|
2311
|
-
mPyObjectWrapper = rb_const_get_at(mPyCall, rb_intern("PyObjectWrapper"));
|
|
2312
|
-
mPyTypeObjectWrapper = rb_const_get_at(mPyCall, rb_intern("PyTypeObjectWrapper"));
|
|
2313
2449
|
mGCGuard = rb_define_module_under(mPyCall, "GCGuard");
|
|
2314
|
-
eError = rb_const_get_at(mPyCall, rb_intern("Error"));
|
|
2315
|
-
cPyError = rb_const_get_at(mPyCall, rb_intern("PyError"));
|
|
2316
2450
|
|
|
2317
2451
|
/* PyCall */
|
|
2318
2452
|
|
|
@@ -2321,6 +2455,8 @@ Init_pycall(void)
|
|
|
2321
2455
|
pycall_tls_create((pycall_tls_key *)&without_gvl_key);
|
|
2322
2456
|
rb_define_module_function(mPyCall, "without_gvl", pycall_m_without_gvl, 0);
|
|
2323
2457
|
|
|
2458
|
+
rb_nativethread_lock_initialize(&pending_decrefs.lock);
|
|
2459
|
+
|
|
2324
2460
|
/* PyCall::PyPtr */
|
|
2325
2461
|
|
|
2326
2462
|
cPyPtr = rb_define_class_under(mPyCall, "PyPtr", rb_cBasicObject);
|
|
@@ -2362,8 +2498,7 @@ Init_pycall(void)
|
|
|
2362
2498
|
/* PyCall::LibPython::API */
|
|
2363
2499
|
|
|
2364
2500
|
mLibPython = rb_define_module_under(mPyCall, "LibPython");
|
|
2365
|
-
|
|
2366
|
-
pycall_init_libpython_api_table(pycall_libpython_handle);
|
|
2501
|
+
pycall_init_libpython_api_table(libpython_handle());
|
|
2367
2502
|
|
|
2368
2503
|
mAPI = rb_define_module_under(mLibPython, "API");
|
|
2369
2504
|
|
|
@@ -2405,9 +2540,8 @@ Init_pycall(void)
|
|
|
2405
2540
|
rb_define_module_function(mConversion, "from_ruby", pycall_conv_m_from_ruby, 1);
|
|
2406
2541
|
rb_define_module_function(mConversion, "to_ruby", pycall_conv_m_to_ruby, 1);
|
|
2407
2542
|
|
|
2408
|
-
python_type_mapping = rb_hash_new();
|
|
2409
2543
|
id_python_type_mapping = rb_intern("__python_type_mapping__");
|
|
2410
|
-
rb_ivar_set(mConversion, id_python_type_mapping,
|
|
2544
|
+
rb_ivar_set(mConversion, id_python_type_mapping, rb_hash_new());
|
|
2411
2545
|
|
|
2412
2546
|
/* initialize the constat PYTHON_VERSION */
|
|
2413
2547
|
|
|
@@ -11,6 +11,7 @@ extern "C" {
|
|
|
11
11
|
#include <ruby.h>
|
|
12
12
|
#include <ruby/encoding.h>
|
|
13
13
|
#include <ruby/thread.h>
|
|
14
|
+
#include <ruby/thread_native.h>
|
|
14
15
|
|
|
15
16
|
#include <assert.h>
|
|
16
17
|
#include <inttypes.h>
|
|
@@ -71,7 +72,7 @@ typedef intptr_t Py_intptr_t;
|
|
|
71
72
|
#ifdef HAVE_SSIZE_T
|
|
72
73
|
typedef ssize_t Py_ssize_t;
|
|
73
74
|
#elif SIZEOF_SIZE_T == SIZEOF_VOIDP
|
|
74
|
-
typedef
|
|
75
|
+
typedef Py_intptr_t Py_ssize_t;
|
|
75
76
|
#elif SIZEOF_SIZE_T == SIZEOF_INT
|
|
76
77
|
typedef int Py_ssize_t;
|
|
77
78
|
#elif SIZEOF_SIZE_T == SIZEOF_LONG
|
|
@@ -745,11 +746,9 @@ void pycall_init_ruby_wrapper(void);
|
|
|
745
746
|
extern intptr_t pycall_hash_salt;
|
|
746
747
|
extern VALUE pycall_mPyCall;
|
|
747
748
|
extern VALUE pycall_cPyPtr;
|
|
748
|
-
extern VALUE pycall_eError;
|
|
749
749
|
|
|
750
750
|
#define mPyCall pycall_mPyCall
|
|
751
751
|
#define cPyPtr pycall_cPyPtr
|
|
752
|
-
#define eError pycall_eError
|
|
753
752
|
|
|
754
753
|
/* #define PYCALL_DEBUG_DUMP_REFCNT */
|
|
755
754
|
|
data/ext/pycall/ruby_wrapper.c
CHANGED
|
@@ -6,7 +6,6 @@ static PyMemberDef PyRuby_members[] = {
|
|
|
6
6
|
{NULL} /* sentinel */
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
static VALUE PyRuby_get_ruby_object_and_set_pyerr(PyObject *pyobj);
|
|
10
9
|
static void PyRuby_dealloc_with_gvl(PyRubyObject *);
|
|
11
10
|
static PyObject * PyRuby_repr_with_gvl(PyRubyObject *);
|
|
12
11
|
static PyObject * PyRuby_call_with_gvl(PyRubyObject *, PyObject *, PyObject *);
|
|
@@ -102,9 +101,7 @@ PyRuby_repr(PyRubyObject *pyro)
|
|
|
102
101
|
VALUE obj, str;
|
|
103
102
|
PyObject *res;
|
|
104
103
|
|
|
105
|
-
obj =
|
|
106
|
-
if (obj == Qundef)
|
|
107
|
-
return NULL;
|
|
104
|
+
obj = PyRuby_get_ruby_object((PyObject *)pyro);
|
|
108
105
|
|
|
109
106
|
str = rb_inspect(obj);
|
|
110
107
|
res = pycall_pystring_from_format("<PyCall.ruby_object %s>", StringValueCStr(str));
|
|
@@ -143,9 +140,7 @@ PyRuby_hash_long(PyRubyObject *pyro)
|
|
|
143
140
|
VALUE obj, rbhash;
|
|
144
141
|
intptr_t h;
|
|
145
142
|
|
|
146
|
-
obj =
|
|
147
|
-
if (obj == Qundef)
|
|
148
|
-
return (void *)-1;
|
|
143
|
+
obj = PyRuby_get_ruby_object((PyObject *)pyro);
|
|
149
144
|
|
|
150
145
|
rbhash = rb_hash(obj);
|
|
151
146
|
h = FIX2LONG(rbhash); /* Ruby's hash value is a Fixnum */
|
|
@@ -170,9 +165,7 @@ PyRuby_hash_hash_t(PyRubyObject *pyro)
|
|
|
170
165
|
VALUE obj, rbhash;
|
|
171
166
|
Py_hash_t h;
|
|
172
167
|
|
|
173
|
-
obj =
|
|
174
|
-
if (obj == Qundef)
|
|
175
|
-
return (void *)-1;
|
|
168
|
+
obj = PyRuby_get_ruby_object((PyObject *)pyro);
|
|
176
169
|
|
|
177
170
|
rbhash = rb_hash(obj);
|
|
178
171
|
#if SIZEOF_PY_HASH_T == SIZEOF_LONG
|
|
@@ -242,9 +235,7 @@ PyRuby_call(struct PyRuby_call_params *params)
|
|
|
242
235
|
PyObject *pyobj_res;
|
|
243
236
|
int state;
|
|
244
237
|
|
|
245
|
-
obj =
|
|
246
|
-
if (obj == Qundef)
|
|
247
|
-
return NULL;
|
|
238
|
+
obj = PyRuby_get_ruby_object((PyObject *)params->pyro);
|
|
248
239
|
|
|
249
240
|
id_call = rb_intern("call");
|
|
250
241
|
if (!rb_respond_to(obj, id_call)) {
|
|
@@ -296,9 +287,7 @@ PyRuby_getattro(struct PyRuby_getattro_params *params)
|
|
|
296
287
|
ID name_id;
|
|
297
288
|
PyObject *pyobj_res;
|
|
298
289
|
|
|
299
|
-
obj =
|
|
300
|
-
if (obj == Qundef)
|
|
301
|
-
return NULL;
|
|
290
|
+
obj = PyRuby_get_ruby_object((PyObject *)params->pyro);
|
|
302
291
|
|
|
303
292
|
name = pycall_pyobject_to_ruby(params->pyobj_name);
|
|
304
293
|
name_cstr = StringValueCStr(name);
|
|
@@ -489,56 +478,3 @@ pycall_init_ruby_wrapper(void)
|
|
|
489
478
|
rb_define_module_function(mPyCall, "wrap_ruby_object", pycall_m_wrap_ruby_object, 1);
|
|
490
479
|
}
|
|
491
480
|
|
|
492
|
-
/* --- File internal utilities --- */
|
|
493
|
-
|
|
494
|
-
static VALUE
|
|
495
|
-
funcall_id2ref(VALUE object_id)
|
|
496
|
-
{
|
|
497
|
-
VALUE rb_mObjSpace;
|
|
498
|
-
object_id = rb_check_to_integer(object_id, "to_int");
|
|
499
|
-
rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
|
|
500
|
-
return rb_funcall(rb_mObjSpace, rb_intern("_id2ref"), 1, object_id);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
static VALUE
|
|
504
|
-
protect_id2ref(VALUE object_id)
|
|
505
|
-
{
|
|
506
|
-
VALUE obj;
|
|
507
|
-
int state;
|
|
508
|
-
|
|
509
|
-
obj = rb_protect((VALUE (*)(VALUE))funcall_id2ref, object_id, &state);
|
|
510
|
-
if (state)
|
|
511
|
-
return Qundef;
|
|
512
|
-
|
|
513
|
-
return obj;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
static VALUE
|
|
517
|
-
protect_id2ref_and_set_pyerr(VALUE object_id)
|
|
518
|
-
{
|
|
519
|
-
VALUE obj = protect_id2ref(object_id);
|
|
520
|
-
if (obj != Qundef)
|
|
521
|
-
return obj;
|
|
522
|
-
|
|
523
|
-
obj = rb_errinfo();
|
|
524
|
-
if (RTEST(rb_obj_is_kind_of(obj, rb_eRangeError))) {
|
|
525
|
-
Py_API(PyErr_SetString)(Py_API(PyExc_RuntimeError), "[BUG] referenced object was garbage-collected");
|
|
526
|
-
}
|
|
527
|
-
else {
|
|
528
|
-
VALUE emesg = rb_check_funcall(obj, rb_intern("message"), 0, 0);
|
|
529
|
-
Py_API(PyErr_Format)(Py_API(PyExc_RuntimeError),
|
|
530
|
-
"[BUG] Unable to obtain ruby object from ID: %s (%s)",
|
|
531
|
-
StringValueCStr(emesg), rb_class2name(CLASS_OF(obj)));
|
|
532
|
-
}
|
|
533
|
-
return Qundef;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
static VALUE
|
|
537
|
-
PyRuby_get_ruby_object_and_set_pyerr(PyObject *pyobj)
|
|
538
|
-
{
|
|
539
|
-
VALUE obj_id;
|
|
540
|
-
if (!PyRuby_Check(pyobj))
|
|
541
|
-
return Qundef;
|
|
542
|
-
obj_id = rb_obj_id(PyRuby_get_ruby_object(pyobj));
|
|
543
|
-
return protect_id2ref_and_set_pyerr(obj_id);
|
|
544
|
-
}
|
|
@@ -231,7 +231,7 @@ module PyCall
|
|
|
231
231
|
else
|
|
232
232
|
name, basic_size = *args
|
|
233
233
|
new.tap do |t|
|
|
234
|
-
# NOTE: Disable autorelease for avoiding SEGV
|
|
234
|
+
# NOTE: Disable autorelease for avoiding SEGV occurrence in Python's GC collect function
|
|
235
235
|
# at which the __new__ method object of this type object is freed.
|
|
236
236
|
t.pointer.autorelease = false
|
|
237
237
|
|