pycall 1.5.1 → 1.5.3

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.
data/ext/pycall/pycall.c CHANGED
@@ -29,7 +29,6 @@ static int python_major_version;
29
29
  static int python_has_stackless_extension;
30
30
  static PyObject *python_builtins_module;
31
31
  static VALUE python_type_mapping;
32
- static VALUE python_type_mapping;
33
32
  static ID id_python_type_mapping;
34
33
 
35
34
  int
@@ -122,6 +121,58 @@ pycall_m_without_gvl(VALUE mod)
122
121
 
123
122
  /* ==== PyCall::PyPtr ==== */
124
123
 
124
+ struct pending_decref_list {
125
+ rb_nativethread_lock_t lock;
126
+ PyObject **pyptrs;
127
+ size_t count;
128
+ size_t capacity;
129
+ };
130
+
131
+ static struct pending_decref_list pending_decrefs;
132
+
133
+ static void
134
+ pycall_pending_decref_add(PyObject *pyobj)
135
+ {
136
+ rb_nativethread_lock_lock(&pending_decrefs.lock);
137
+ if (pending_decrefs.count == pending_decrefs.capacity) {
138
+ size_t new_capacity = pending_decrefs.capacity ? 2 * pending_decrefs.capacity : 64;
139
+ /* Not ruby_xrealloc: this function runs during GC, where xmalloc/xrealloc
140
+ * are prohibited (rb_bug "Cannot realloc during GC" since Ruby 3.3). */
141
+ PyObject **new_pyptrs = realloc(pending_decrefs.pyptrs, new_capacity * sizeof(PyObject *));
142
+ if (new_pyptrs == NULL) {
143
+ /* Leaking the object is preferable to blocking or crashing inside GC */
144
+ rb_nativethread_lock_unlock(&pending_decrefs.lock);
145
+ return;
146
+ }
147
+ pending_decrefs.pyptrs = new_pyptrs;
148
+ pending_decrefs.capacity = new_capacity;
149
+ }
150
+ pending_decrefs.pyptrs[pending_decrefs.count++] = pyobj;
151
+ rb_nativethread_lock_unlock(&pending_decrefs.lock);
152
+ }
153
+
154
+ static void
155
+ pycall_drain_pending_decrefs(void)
156
+ {
157
+ PyObject **pyptrs;
158
+ size_t i, count;
159
+
160
+ if (pending_decrefs.count == 0) return;
161
+
162
+ rb_nativethread_lock_lock(&pending_decrefs.lock);
163
+ pyptrs = pending_decrefs.pyptrs;
164
+ count = pending_decrefs.count;
165
+ pending_decrefs.pyptrs = NULL;
166
+ pending_decrefs.count = 0;
167
+ pending_decrefs.capacity = 0;
168
+ rb_nativethread_lock_unlock(&pending_decrefs.lock);
169
+
170
+ for (i = 0; i < count; ++i) {
171
+ pycall_Py_DecRef(pyptrs[i]);
172
+ }
173
+ free(pyptrs);
174
+ }
175
+
125
176
  const rb_data_type_t pycall_pyptr_data_type = {
126
177
  "PyCall::PyPtr",
127
178
  { 0, pycall_pyptr_free, pycall_pyptr_memsize, },
@@ -130,6 +181,11 @@ const rb_data_type_t pycall_pyptr_data_type = {
130
181
  #endif
131
182
  };
132
183
 
184
+ /* pycall_pyptr_free may be called by the GC sweeper on a thread that does
185
+ * not hold the GIL. PyCall keeps the GIL held by the thread that
186
+ * initialized Python for the entire lifetime of the process, so waiting
187
+ * for the GIL there (PyGILState_Ensure) blocks forever while the sweeper
188
+ * holds the GVL, freezing every Ruby thread in the process. */
133
189
  void
134
190
  pycall_pyptr_free(void *ptr)
135
191
  {
@@ -139,7 +195,15 @@ pycall_pyptr_free(void *ptr)
139
195
  fprintf(stderr, "zero refcnt object %p of type %s\n", pyobj, Py_TYPE(pyobj)->tp_name);
140
196
  }
141
197
  #endif /* PYCALL_DEBUG_DUMP_REFCNT */
142
- pycall_Py_DecRef(pyobj);
198
+
199
+ if (Py_API(PyGILState_Check())) {
200
+ pycall_Py_DecRef(pyobj);
201
+ }
202
+ else {
203
+ /* Instead of taking the GIL here, enqueue the pointer; the list is
204
+ * drained on the next Python call. */
205
+ pycall_pending_decref_add(pyobj);
206
+ }
143
207
  }
144
208
 
145
209
  static size_t _PySys_GetSizeOf(PyObject *);
@@ -620,6 +684,8 @@ pycall_libpython_api_PyObject_Dir(VALUE mod, VALUE pyptr)
620
684
  PyObject *dir;
621
685
  PyObject *pyobj;
622
686
 
687
+ pycall_drain_pending_decrefs();
688
+
623
689
  if (!is_pycall_pyptr(pyptr)) {
624
690
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
625
691
  }
@@ -639,6 +705,8 @@ pycall_libpython_api_PyList_Size(VALUE mod, VALUE pyptr)
639
705
  PyObject *pyobj;
640
706
  Py_ssize_t size;
641
707
 
708
+ pycall_drain_pending_decrefs();
709
+
642
710
  if (!is_pycall_pyptr(pyptr)) {
643
711
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
644
712
  }
@@ -659,6 +727,8 @@ pycall_libpython_api_PyList_GetItem(VALUE mod, VALUE pyptr, VALUE idx)
659
727
  PyObject *pyobj_item;
660
728
  Py_ssize_t i;
661
729
 
730
+ pycall_drain_pending_decrefs();
731
+
662
732
  if (!is_pycall_pyptr(pyptr)) {
663
733
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
664
734
  }
@@ -724,6 +794,8 @@ pycall_libpython_helpers_m_import_module(int argc, VALUE *argv, VALUE mod)
724
794
  VALUE name, globals, locals, fromlist, level;
725
795
  char const *name_cstr;
726
796
 
797
+ pycall_drain_pending_decrefs();
798
+
727
799
  rb_scan_args(argc, argv, "14", &name, &globals, &locals, &fromlist, &level);
728
800
 
729
801
  if (RB_TYPE_P(name, T_SYMBOL)) {
@@ -776,6 +848,8 @@ pycall_libpython_helpers_m_compare(VALUE mod, VALUE op, VALUE pyptr_a, VALUE pyp
776
848
  PyObject *pyobj_a, *pyobj_b, *res;
777
849
  int opid;
778
850
 
851
+ pycall_drain_pending_decrefs();
852
+
779
853
  opid = pycall_rich_compare_opid(op);
780
854
 
781
855
  if (!is_pycall_pyptr(pyptr_a)) {
@@ -830,6 +904,8 @@ pycall_libpython_helpers_m_getattr(int argc, VALUE *argv, VALUE mod)
830
904
  {
831
905
  VALUE pyptr, name, default_value;
832
906
 
907
+ pycall_drain_pending_decrefs();
908
+
833
909
  if (rb_scan_args(argc, argv, "21", &pyptr, &name, &default_value) == 2) {
834
910
  default_value = Qundef;
835
911
  }
@@ -851,6 +927,8 @@ pycall_libpython_helpers_m_hasattr_p(VALUE mod, VALUE pyptr, VALUE name)
851
927
  PyObject *pyobj;
852
928
  int res;
853
929
 
930
+ pycall_drain_pending_decrefs();
931
+
854
932
  if (!is_pycall_pyptr(pyptr)) {
855
933
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
856
934
  }
@@ -870,6 +948,8 @@ pycall_libpython_helpers_m_setattr(VALUE mod, VALUE pyptr, VALUE name, VALUE val
870
948
  {
871
949
  PyObject *pyobj, *pyval;
872
950
 
951
+ pycall_drain_pending_decrefs();
952
+
873
953
  if (!is_pycall_pyptr(pyptr)) {
874
954
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
875
955
  }
@@ -893,6 +973,8 @@ pycall_libpython_helpers_m_delattr(VALUE mod, VALUE pyptr, VALUE name)
893
973
  {
894
974
  PyObject *pyobj;
895
975
 
976
+ pycall_drain_pending_decrefs();
977
+
896
978
  if (!is_pycall_pyptr(pyptr)) {
897
979
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
898
980
  }
@@ -916,6 +998,8 @@ pycall_libpython_helpers_m_callable_p(VALUE mod, VALUE pyptr)
916
998
  PyObject *pyobj;
917
999
  int res;
918
1000
 
1001
+ pycall_drain_pending_decrefs();
1002
+
919
1003
  if (!is_pycall_pyptr(pyptr)) {
920
1004
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
921
1005
  }
@@ -932,6 +1016,8 @@ pycall_libpython_helpers_m_call_object(int argc, VALUE *argv, VALUE mod)
932
1016
  VALUE pyptr;
933
1017
  PyObject *pyobj;
934
1018
 
1019
+ pycall_drain_pending_decrefs();
1020
+
935
1021
  if (argc < 1) {
936
1022
  rb_raise(rb_eArgError, "too few arguments (%d for >=1)", argc);
937
1023
  }
@@ -1081,6 +1167,8 @@ pycall_pyobject_wrapper_wrapper_method(int argc, VALUE *argv, VALUE wrapper)
1081
1167
  char *name_cstr;
1082
1168
  PyObject *pyobj, *attr;
1083
1169
 
1170
+ pycall_drain_pending_decrefs();
1171
+
1084
1172
  pyptr = rb_attr_get(wrapper, rb_intern("@__pyptr__"));
1085
1173
  if (NIL_P(pyptr) || !is_pycall_pyptr(pyptr)) {
1086
1174
  rb_raise(rb_eTypeError, "Wrong wrapper object is given");
@@ -1136,6 +1224,8 @@ pycall_libpython_helpers_m_define_wrapper_method(VALUE mod, VALUE wrapper, VALUE
1136
1224
  PyObject *pyobj, *attr;
1137
1225
  char *name_cstr;
1138
1226
 
1227
+ pycall_drain_pending_decrefs();
1228
+
1139
1229
  pyptr = rb_attr_get(wrapper, rb_intern("@__pyptr__"));
1140
1230
  if (NIL_P(pyptr) || !is_pycall_pyptr(pyptr)) {
1141
1231
  rb_raise(rb_eTypeError, "Wrong wrapper object is given");
@@ -1183,10 +1273,10 @@ pycall_convert_index(VALUE index)
1183
1273
  }
1184
1274
  }
1185
1275
  else if (rb_obj_is_kind_of(index, rb_cRange)) {
1186
- pyobj = pycall_pyslice_from_ruby(index); /* New refrence */
1276
+ pyobj = pycall_pyslice_from_ruby(index); /* New reference */
1187
1277
  }
1188
1278
  else if (pycall_obj_is_step_range(index)) {
1189
- pyobj = pycall_pyslice_from_ruby(index); /* New refrence */
1279
+ pyobj = pycall_pyslice_from_ruby(index); /* New reference */
1190
1280
  }
1191
1281
  else {
1192
1282
  pyobj = pycall_pyobject_from_ruby(index); /* New reference */
@@ -1201,6 +1291,8 @@ pycall_libpython_helpers_m_getitem(VALUE mod, VALUE pyptr, VALUE key)
1201
1291
  PyObject *pyobj, *pyobj_key, *pyobj_v;
1202
1292
  VALUE obj;
1203
1293
 
1294
+ pycall_drain_pending_decrefs();
1295
+
1204
1296
  if (!is_pycall_pyptr(pyptr)) {
1205
1297
  rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
1206
1298
  }
@@ -1226,6 +1318,8 @@ pycall_libpython_helpers_m_setitem(VALUE mod, VALUE pyptr, VALUE key, VALUE v)
1226
1318
  PyObject *pyobj, *pyobj_key, *pyobj_value;
1227
1319
  int res;
1228
1320
 
1321
+ pycall_drain_pending_decrefs();
1322
+
1229
1323
  pyobj = check_get_pyobj_ptr(pyptr, NULL);
1230
1324
  pyobj_key = pycall_convert_index(key);
1231
1325
  pyobj_value = pycall_pyobject_from_ruby(v);
@@ -1246,6 +1340,8 @@ pycall_libpython_helpers_m_delitem(VALUE mod, VALUE pyptr, VALUE key)
1246
1340
  PyObject *pyobj, *pyobj_key;
1247
1341
  int res;
1248
1342
 
1343
+ pycall_drain_pending_decrefs();
1344
+
1249
1345
  pyobj = check_get_pyobj_ptr(pyptr, NULL);
1250
1346
  pyobj_key = pycall_convert_index(key);
1251
1347
 
@@ -1263,6 +1359,8 @@ pycall_libpython_helpers_m_str(VALUE mod, VALUE pyptr)
1263
1359
  {
1264
1360
  PyObject *pyobj, *pyobj_str;
1265
1361
 
1362
+ pycall_drain_pending_decrefs();
1363
+
1266
1364
  pyobj = check_get_pyobj_ptr(pyptr, NULL);
1267
1365
 
1268
1366
  pyobj_str = Py_API(PyObject_Str)(pyobj);
@@ -1270,7 +1368,9 @@ pycall_libpython_helpers_m_str(VALUE mod, VALUE pyptr)
1270
1368
  pycall_pyerror_fetch_and_raise("PyObject_Str");
1271
1369
  }
1272
1370
 
1273
- return pycall_pyobject_to_ruby(pyobj_str);
1371
+ VALUE v = pycall_pyobject_to_ruby(pyobj_str);
1372
+ pycall_Py_DecRef(pyobj_str);
1373
+ return v;
1274
1374
  }
1275
1375
 
1276
1376
  static VALUE
@@ -1279,6 +1379,8 @@ pycall_libpython_helpers_m_dict_contains(VALUE mod, VALUE pyptr, VALUE key)
1279
1379
  PyObject *pyobj, *pyobj_key;
1280
1380
  int res;
1281
1381
 
1382
+ pycall_drain_pending_decrefs();
1383
+
1282
1384
  pyobj = check_get_pyobj_ptr(pyptr, Py_API(PyDict_Type));
1283
1385
  pyobj_key = pycall_pyobject_from_ruby(key);
1284
1386
  res = Py_API(PyDict_Contains)(pyobj, pyobj_key);
@@ -1296,6 +1398,8 @@ pycall_libpython_helpers_m_dict_each(VALUE mod, VALUE pyptr)
1296
1398
  PyObject *pyobj, *pyobj_key, *pyobj_value;
1297
1399
  Py_ssize_t pos;
1298
1400
 
1401
+ pycall_drain_pending_decrefs();
1402
+
1299
1403
  pyobj = check_get_pyobj_ptr(pyptr, Py_API(PyDict_Type));
1300
1404
 
1301
1405
  pos = 0;
@@ -1315,6 +1419,8 @@ pycall_libpython_helpers_m_sequence_contains(VALUE mod, VALUE pyptr, VALUE key)
1315
1419
  PyObject *pyobj, *pyobj_key;
1316
1420
  int res;
1317
1421
 
1422
+ pycall_drain_pending_decrefs();
1423
+
1318
1424
  pyobj = check_get_pyobj_ptr(pyptr, NULL);
1319
1425
  if (!Py_API(PySequence_Check)(pyobj))
1320
1426
  rb_raise(rb_eTypeError, "unexpected Python type %s (expected a Python sequence object)", Py_TYPE(pyobj)->tp_name);
@@ -1334,6 +1440,8 @@ pycall_libpython_helpers_m_sequence_each(VALUE mod, VALUE pyptr)
1334
1440
  {
1335
1441
  PyObject *pyobj, *pyobj_iter, *pyobj_item;
1336
1442
 
1443
+ pycall_drain_pending_decrefs();
1444
+
1337
1445
  pyobj = check_get_pyobj_ptr(pyptr, NULL);
1338
1446
  if (!Py_API(PySequence_Check)(pyobj))
1339
1447
  rb_raise(rb_eTypeError, "unexpected Python type %s (expected a Python sequence object)", Py_TYPE(pyobj)->tp_name);
@@ -1518,7 +1626,7 @@ pycall_pyobject_to_ruby(PyObject *pyobj)
1518
1626
  Py_API(Py_IncRef)((PyObject *)pyobj->ob_type);
1519
1627
  cls = pycall_python_type_mapping_get_mapped_class(pycall_pytypeptr_new((PyObject *)pyobj->ob_type));
1520
1628
  if (NIL_P(cls)) {
1521
- rb_warning("Currentry do not support to convert %s to Ruby object", Py_TYPE(pyobj)->tp_name);
1629
+ rb_warning("Currently do not support to convert %s to Ruby object", Py_TYPE(pyobj)->tp_name);
1522
1630
  return pycall_pyobject_wrapper_object_new(rb_cObject, pyobj);
1523
1631
  }
1524
1632
 
@@ -1653,7 +1761,7 @@ pycall_pylong_to_ruby(PyObject *pyobj)
1653
1761
  }
1654
1762
  #endif
1655
1763
 
1656
- rb_warning("Currentry do not support to convert multi-precision PyLong number to Ruby object");
1764
+ rb_warning("Currently do not support to convert multi-precision PyLong number to Ruby object");
1657
1765
 
1658
1766
  return Qnil;
1659
1767
  }
@@ -1690,19 +1798,21 @@ pycall_pyunicode_to_ruby(PyObject *pyobj)
1690
1798
  return Qnil;
1691
1799
  }
1692
1800
 
1693
- pyobj = Py_API(PyUnicode_AsUTF8String)(pyobj);
1694
- if (!pyobj) {
1801
+ PyObject *pyobj_uni = Py_API(PyUnicode_AsUTF8String)(pyobj);
1802
+ if (!pyobj_uni) {
1695
1803
  Py_API(PyErr_Clear)();
1696
1804
  return Qnil;
1697
1805
  }
1698
1806
 
1699
- res = Py_API(PyString_AsStringAndSize)(pyobj, &str, &len);
1807
+ res = Py_API(PyString_AsStringAndSize)(pyobj_uni, &str, &len);
1700
1808
  if (res < 0) {
1701
- pycall_Py_DecRef(pyobj);
1809
+ pycall_Py_DecRef(pyobj_uni);
1702
1810
  return Qnil;
1703
1811
  }
1704
1812
 
1705
- return rb_enc_str_new(str, len, rb_enc_from_index(rb_utf8_encindex()));
1813
+ VALUE v = rb_enc_str_new(str, len, rb_enc_from_index(rb_utf8_encindex()));
1814
+ pycall_Py_DecRef(pyobj_uni);
1815
+ return v;
1706
1816
  }
1707
1817
 
1708
1818
  static VALUE
@@ -1775,7 +1885,11 @@ pycall_conv_m_unregister_python_type_mapping(VALUE mod, VALUE pytypeptr)
1775
1885
  static VALUE
1776
1886
  pycall_conv_m_from_ruby(VALUE mod, VALUE obj)
1777
1887
  {
1778
- PyObject *pyobj = pycall_pyobject_from_ruby(obj);
1888
+ PyObject *pyobj;
1889
+
1890
+ pycall_drain_pending_decrefs();
1891
+
1892
+ pyobj = pycall_pyobject_from_ruby(obj);
1779
1893
  if (PyType_Check(pyobj) || PyClass_Check(pyobj))
1780
1894
  return pycall_pytypeptr_new(pyobj);
1781
1895
  if (PyRuby_Check(pyobj))
@@ -1787,7 +1901,11 @@ static VALUE
1787
1901
  pycall_conv_m_to_ruby(VALUE mod, VALUE pyptr)
1788
1902
  {
1789
1903
  VALUE obj, obj_pyptr;
1790
- PyObject *pyobj = check_get_pyobj_ptr(pyptr, NULL);
1904
+ PyObject *pyobj;
1905
+
1906
+ pycall_drain_pending_decrefs();
1907
+
1908
+ pyobj = check_get_pyobj_ptr(pyptr, NULL);
1791
1909
  obj = obj_pyptr = pycall_pyobject_to_ruby(pyobj);
1792
1910
  if (is_pyobject_wrapper(obj)) {
1793
1911
  obj_pyptr = pycall_pyobject_wrapper_get_pyptr(obj);
@@ -2309,6 +2427,8 @@ Init_pycall(void)
2309
2427
  pycall_tls_create((pycall_tls_key *)&without_gvl_key);
2310
2428
  rb_define_module_function(mPyCall, "without_gvl", pycall_m_without_gvl, 0);
2311
2429
 
2430
+ rb_nativethread_lock_initialize(&pending_decrefs.lock);
2431
+
2312
2432
  /* PyCall::PyPtr */
2313
2433
 
2314
2434
  cPyPtr = rb_define_class_under(mPyCall, "PyPtr", rb_cBasicObject);
@@ -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 Py_intptr_tr Py_ssize_t;
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
@@ -519,6 +520,11 @@ PyObject * PyRuby_New(VALUE ruby_object);
519
520
 
520
521
  /* ==== thread support ==== */
521
522
 
523
+ typedef enum {
524
+ PyGILState_LOCKED,
525
+ PyGILState_UNLOCKED
526
+ } PyGILState_STATE;
527
+
522
528
  #if defined(PYCALL_THREAD_WIN32)
523
529
  typedef DWORD pycall_tls_key;
524
530
  #elif defined(PYCALL_THREAD_PTHREAD)
@@ -669,6 +675,10 @@ typedef struct {
669
675
  PyObject * (* PyUnicode_AsUTF8String)(PyObject *);
670
676
  PyObject * (* PyUnicode_DecodeUTF8)(char const*, Py_ssize_t, char const *);
671
677
  PyObject * (* PyUnicode_FromFormatV)(char const*, ...);
678
+
679
+ int (* PyGILState_Check)(void);
680
+ PyGILState_STATE (* PyGILState_Ensure)(void);
681
+ void (* PyGILState_Release)(PyGILState_STATE);
672
682
  } pycall_libpython_api_table_t;
673
683
 
674
684
  pycall_libpython_api_table_t *pycall_libpython_api_table(void);
data/ext/pycall/range.c CHANGED
@@ -6,6 +6,12 @@ struct enumerator_head {
6
6
  VALUE args;
7
7
  };
8
8
 
9
+ #ifdef HAVE_RTYPEDDATA_GET_DATA
10
+ # define GET_ENUMERATOR_DATA(obj) ((struct enumerator_head *)RTYPEDDATA_GET_DATA(obj))
11
+ #else
12
+ # define GET_ENUMERATOR_DATA(obj) ((struct enumerator_head *)DATA_PTR(obj))
13
+ #endif
14
+
9
15
  int
10
16
  pycall_obj_is_step_range(VALUE obj)
11
17
  {
@@ -19,7 +25,7 @@ pycall_obj_is_step_range(VALUE obj)
19
25
  return 0;
20
26
  }
21
27
 
22
- eh = (struct enumerator_head *)DATA_PTR(obj);
28
+ eh = GET_ENUMERATOR_DATA(obj);
23
29
 
24
30
  if (!rb_obj_is_kind_of(eh->obj, rb_cRange)) {
25
31
  return 0;
@@ -50,7 +56,7 @@ pycall_extract_range(VALUE obj, VALUE *pbegin, VALUE *pend, int *pexclude_end, V
50
56
  exclude_end = rb_funcallv(obj, id_exclude_end, 0, 0);
51
57
  }
52
58
  else if (pycall_obj_is_step_range(obj)) {
53
- struct enumerator_head *eh = (struct enumerator_head *)DATA_PTR(obj);
59
+ struct enumerator_head *eh = GET_ENUMERATOR_DATA(obj);
54
60
  begin = rb_funcallv(eh->obj, id_begin, 0, 0);
55
61
  end = rb_funcallv(eh->obj, id_end, 0, 0);
56
62
  exclude_end = rb_funcallv(eh->obj, id_exclude_end, 0, 0);
@@ -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 *);
@@ -59,10 +58,11 @@ PyObject *
59
58
  PyRuby_New(VALUE ruby_object)
60
59
  {
61
60
  if (!ruby_thread_has_gvl_p()) {
62
- CALL_WITH_GVL(PyRuby_New_impl, ruby_object);
61
+ return CALL_WITH_GVL(PyRuby_New_impl, ruby_object);
62
+ }
63
+ else {
64
+ return PyRuby_New_impl(ruby_object);
63
65
  }
64
-
65
- return PyRuby_New_impl(ruby_object);
66
66
  }
67
67
 
68
68
  static void *
@@ -90,7 +90,9 @@ PyRuby_dealloc_with_gvl(PyRubyObject *pyro)
90
90
  if (!ruby_thread_has_gvl_p()) {
91
91
  CALL_WITH_GVL(PyRuby_dealloc, pyro);
92
92
  }
93
- PyRuby_dealloc(pyro);
93
+ else {
94
+ PyRuby_dealloc(pyro);
95
+ }
94
96
  }
95
97
 
96
98
  static PyObject *
@@ -99,9 +101,7 @@ PyRuby_repr(PyRubyObject *pyro)
99
101
  VALUE obj, str;
100
102
  PyObject *res;
101
103
 
102
- obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)pyro);
103
- if (obj == Qundef)
104
- return NULL;
104
+ obj = PyRuby_get_ruby_object((PyObject *)pyro);
105
105
 
106
106
  str = rb_inspect(obj);
107
107
  res = pycall_pystring_from_format("<PyCall.ruby_object %s>", StringValueCStr(str));
@@ -114,7 +114,9 @@ PyRuby_repr_with_gvl(PyRubyObject *pyro)
114
114
  if (!ruby_thread_has_gvl_p()) {
115
115
  return CALL_WITH_GVL(PyRuby_repr, pyro);
116
116
  }
117
- return PyRuby_repr(pyro);
117
+ else {
118
+ return PyRuby_repr(pyro);
119
+ }
118
120
  }
119
121
 
120
122
  #if SIZEOF_SSIZE_T < 8
@@ -138,9 +140,7 @@ PyRuby_hash_long(PyRubyObject *pyro)
138
140
  VALUE obj, rbhash;
139
141
  intptr_t h;
140
142
 
141
- obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)pyro);
142
- if (obj == Qundef)
143
- return (void *)-1;
143
+ obj = PyRuby_get_ruby_object((PyObject *)pyro);
144
144
 
145
145
  rbhash = rb_hash(obj);
146
146
  h = FIX2LONG(rbhash); /* Ruby's hash value is a Fixnum */
@@ -154,7 +154,9 @@ PyRuby_hash_long_with_gvl(PyRubyObject *pyro)
154
154
  if (!ruby_thread_has_gvl_p()) {
155
155
  return (long)(intptr_t)CALL_WITH_GVL(PyRuby_hash_long, pyro);
156
156
  }
157
- return (long)(intptr_t)PyRuby_hash_long(pyro);
157
+ else {
158
+ return (long)(intptr_t)PyRuby_hash_long(pyro);
159
+ }
158
160
  }
159
161
 
160
162
  static void *
@@ -163,9 +165,7 @@ PyRuby_hash_hash_t(PyRubyObject *pyro)
163
165
  VALUE obj, rbhash;
164
166
  Py_hash_t h;
165
167
 
166
- obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)pyro);
167
- if (obj == Qundef)
168
- return (void *)-1;
168
+ obj = PyRuby_get_ruby_object((PyObject *)pyro);
169
169
 
170
170
  rbhash = rb_hash(obj);
171
171
  #if SIZEOF_PY_HASH_T == SIZEOF_LONG
@@ -185,7 +185,9 @@ PyRuby_hash_hash_t_with_gvl(PyRubyObject *pyro)
185
185
  if (!ruby_thread_has_gvl_p()) {
186
186
  return (Py_hash_t)CALL_WITH_GVL(PyRuby_hash_hash_t, pyro);
187
187
  }
188
- return (Py_hash_t)PyRuby_hash_hash_t(pyro);
188
+ else {
189
+ return (Py_hash_t)PyRuby_hash_hash_t(pyro);
190
+ }
189
191
  }
190
192
 
191
193
  struct call_rb_funcallv_params {
@@ -233,9 +235,7 @@ PyRuby_call(struct PyRuby_call_params *params)
233
235
  PyObject *pyobj_res;
234
236
  int state;
235
237
 
236
- obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)params->pyro);
237
- if (obj == Qundef)
238
- return NULL;
238
+ obj = PyRuby_get_ruby_object((PyObject *)params->pyro);
239
239
 
240
240
  id_call = rb_intern("call");
241
241
  if (!rb_respond_to(obj, id_call)) {
@@ -269,8 +269,9 @@ PyRuby_call_with_gvl(PyRubyObject *pyro, PyObject *pyobj_args, PyObject *pyobj_k
269
269
  if (!ruby_thread_has_gvl_p()) {
270
270
  return CALL_WITH_GVL(PyRuby_call, &params);
271
271
  }
272
-
273
- return PyRuby_call(&params);
272
+ else {
273
+ return PyRuby_call(&params);
274
+ }
274
275
  }
275
276
 
276
277
  struct PyRuby_getattro_params {
@@ -286,9 +287,7 @@ PyRuby_getattro(struct PyRuby_getattro_params *params)
286
287
  ID name_id;
287
288
  PyObject *pyobj_res;
288
289
 
289
- obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)params->pyro);
290
- if (obj == Qundef)
291
- return NULL;
290
+ obj = PyRuby_get_ruby_object((PyObject *)params->pyro);
292
291
 
293
292
  name = pycall_pyobject_to_ruby(params->pyobj_name);
294
293
  name_cstr = StringValueCStr(name);
@@ -348,8 +347,9 @@ PyRuby_getattro_with_gvl(PyRubyObject *pyro, PyObject *pyobj_name)
348
347
  if (!ruby_thread_has_gvl_p()) {
349
348
  return CALL_WITH_GVL(PyRuby_getattro, &params);
350
349
  }
351
-
352
- return PyRuby_getattro(&params);
350
+ else {
351
+ return PyRuby_getattro(&params);
352
+ }
353
353
  }
354
354
 
355
355
  /* ==== PyCall::PyRubyPtr ==== */
@@ -478,56 +478,3 @@ pycall_init_ruby_wrapper(void)
478
478
  rb_define_module_function(mPyCall, "wrap_ruby_object", pycall_m_wrap_ruby_object, 1);
479
479
  }
480
480
 
481
- /* --- File internal utilities --- */
482
-
483
- static VALUE
484
- funcall_id2ref(VALUE object_id)
485
- {
486
- VALUE rb_mObjSpace;
487
- object_id = rb_check_to_integer(object_id, "to_int");
488
- rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
489
- return rb_funcall(rb_mObjSpace, rb_intern("_id2ref"), 1, object_id);
490
- }
491
-
492
- static VALUE
493
- protect_id2ref(VALUE object_id)
494
- {
495
- VALUE obj;
496
- int state;
497
-
498
- obj = rb_protect((VALUE (*)(VALUE))funcall_id2ref, object_id, &state);
499
- if (state)
500
- return Qundef;
501
-
502
- return obj;
503
- }
504
-
505
- static VALUE
506
- protect_id2ref_and_set_pyerr(VALUE object_id)
507
- {
508
- VALUE obj = protect_id2ref(object_id);
509
- if (obj != Qundef)
510
- return obj;
511
-
512
- obj = rb_errinfo();
513
- if (RTEST(rb_obj_is_kind_of(obj, rb_eRangeError))) {
514
- Py_API(PyErr_SetString)(Py_API(PyExc_RuntimeError), "[BUG] referenced object was garbage-collected");
515
- }
516
- else {
517
- VALUE emesg = rb_check_funcall(obj, rb_intern("message"), 0, 0);
518
- Py_API(PyErr_Format)(Py_API(PyExc_RuntimeError),
519
- "[BUG] Unable to obtain ruby object from ID: %s (%s)",
520
- StringValueCStr(emesg), rb_class2name(CLASS_OF(obj)));
521
- }
522
- return Qundef;
523
- }
524
-
525
- static VALUE
526
- PyRuby_get_ruby_object_and_set_pyerr(PyObject *pyobj)
527
- {
528
- VALUE obj_id;
529
- if (!PyRuby_Check(pyobj))
530
- return Qundef;
531
- obj_id = rb_obj_id(PyRuby_get_ruby_object(pyobj));
532
- return protect_id2ref_and_set_pyerr(obj_id);
533
- }
@@ -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 occurrance in Python's GC collect function
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
 
@@ -33,8 +33,6 @@ module PyCall
33
33
  }.freeze
34
34
 
35
35
  def method_missing(name, *args)
36
- name_str = name.to_s if name.kind_of?(Symbol)
37
- name_str.chop! if name_str.end_with?('=')
38
36
  case name
39
37
  when *OPERATOR_METHOD_NAMES.keys
40
38
  op_name = OPERATOR_METHOD_NAMES[name]
@@ -44,7 +42,8 @@ module PyCall
44
42
  return self.__send__(name, *args)
45
43
  end
46
44
  else
47
- if LibPython::Helpers.hasattr?(__pyptr__, name_str)
45
+ name_without_last_equal = name.to_s.chomp('=')
46
+ if LibPython::Helpers.hasattr?(__pyptr__, name_without_last_equal)
48
47
  LibPython::Helpers.define_wrapper_method(self, name)
49
48
  return self.__send__(name, *args)
50
49
  end
@@ -1,5 +1,5 @@
1
1
  module PyCall
2
- VERSION = "1.5.1"
2
+ VERSION = "1.5.3"
3
3
 
4
4
  module Version
5
5
  numbers, TAG = VERSION.split("-")
data/lib/pycall.rb CHANGED
@@ -116,7 +116,7 @@ module PyCall
116
116
  rescue PyError => err
117
117
  raise err unless ctx.__exit__(err.type, err.value, err.traceback)
118
118
  rescue Exception => err
119
- # TODO: support telling what exception has been catched
119
+ # TODO: support telling what exception has been caught
120
120
  raise err unless ctx.__exit__(err.class, err, err.backtrace_locations)
121
121
  else
122
122
  ctx.__exit__(nil, nil, nil)