pycall 1.4.2 → 1.5.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b2526ea3050985dc6d864e979804fb4ebaa9c36d8239b48809a9cd31dd01de5
4
- data.tar.gz: 68df5fcac7fd5c574009ebbc33f0d9c1724ff8d5057d4dfaa69832b8509e4a92
3
+ metadata.gz: c0793d5cd5f93c4eb9cd5938b7999799649db72f2abd35b4ae3247c450aec7ce
4
+ data.tar.gz: 404e3c06167a752f94cfc9051734a259725366f7c981c654e4f8744a3613c907
5
5
  SHA512:
6
- metadata.gz: c52cd3ac7b709238a1b3ec95ed7eb45bcfaa5ef8a40b74f8de15cec928350152769c915250f27290e1b7f2bfb84032faa3a39837d0598c2927a114f6989f11dc
7
- data.tar.gz: 6c45f609e09251815588b0a02095af9d221e2c715d4e614d16888326fc46c6158a631b6cc514d9b3e673468abf2834e003074a5e77f27b46098c5ab698328459
6
+ metadata.gz: 2c8f666bb616b01f69bcd33130991cd22f9f2bfea3b67946e87550c846327032bd14d69d2522d8b83ee18db5551cea3bf0fa51f7043d7cfcfd8a8490c6bf04df
7
+ data.tar.gz: 041600f566b4d8158dc4772830ab1a8eb00479a82b118f0f135e20130d05d9047dba53b8ab32701c2bee20ec770a48cd540cd259d369163e64f4da775e7e26ae
@@ -0,0 +1,11 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "bundler" # See documentation for possible values
9
+ directory: "/" # Location of package manifests
10
+ schedule:
11
+ interval: "daily"
@@ -25,6 +25,7 @@ jobs:
25
25
  - ubuntu-20.04
26
26
  - macos-latest
27
27
  ruby:
28
+ - "3.3"
28
29
  - "3.2"
29
30
  - "3.1"
30
31
  - "3.0"
@@ -41,41 +42,28 @@ jobs:
41
42
  - { os: ubuntu-20.04 , ruby: 2.5 , python: "3.x" , python_architecture: x64 , venv: "" }
42
43
  - { os: ubuntu-20.04 , ruby: 2.4 , python: "3.x" , python_architecture: x64 , venv: "" }
43
44
 
44
- # The latest Python 2
45
- - { os: ubuntu-20.04 , ruby: 3.1 , python: "2.x" , python_architecture: x64 , venv: "" }
46
- - { os: ubuntu-20.04 , ruby: 3.0 , python: "2.x" , python_architecture: x64 , venv: "" }
47
- - { os: ubuntu-20.04 , ruby: 2.7 , python: "2.x" , python_architecture: x64 , venv: "" }
48
- - { os: ubuntu-20.04 , ruby: 2.6 , python: "2.x" , python_architecture: x64 , venv: "" }
49
- - { os: ubuntu-20.04 , ruby: 2.5 , python: "2.x" , python_architecture: x64 , venv: "" }
50
- - { os: ubuntu-20.04 , ruby: 2.4 , python: "2.x" , python_architecture: x64 , venv: "" }
51
-
52
45
  # Ruby 2.7 with Each Python 3.x
46
+ - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.12" , python_architecture: x64 , venv: "" }
53
47
  - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.11" , python_architecture: x64 , venv: "" }
54
48
  - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.10" , python_architecture: x64 , venv: "" }
55
49
  - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.9" , python_architecture: x64 , venv: "" }
56
50
  - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.8" , python_architecture: x64 , venv: "" }
57
51
  - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.7" , python_architecture: x64 , venv: "" }
58
52
  - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.6" , python_architecture: x64 , venv: "" }
59
- - { os: ubuntu-18.04 , ruby: 2.7 , python: "3.8" , python_architecture: x64 , venv: "" }
60
53
 
61
54
  # Ruby-debug with the latest Python 3
62
55
  - { os: ubuntu-20.04 , ruby: debug , python: "3.x" , python_architecture: x64 , venv: "" }
63
56
 
64
- # Ruby 3.1 with the latest Python 3 with venv
65
- - { os: ubuntu-20.04 , ruby: "3.1" , python: "3.x" , python_architecture: x64 , venv: "venv:" }
66
- - { os: ubuntu-18.04 , ruby: "3.1" , python: "3.x" , python_architecture: x64 , venv: "venv:" }
67
-
68
- # Ubuntu 18.04 with venv
69
- - { os: ubuntu-18.04 , ruby: "3.1" , python: "3.8" , python_architecture: x64 , venv: "venv:" }
57
+ # The latest stable Ruby with the latest Python 3 with venv
58
+ - { os: ubuntu-20.04 , ruby: "3.3" , python: "3.x" , python_architecture: x64 , venv: "venv:" }
70
59
 
71
60
  # macOS with venv
72
- - { os: macos-latest , ruby: "3.1" , python: "3.x" , python_architecture: x64 , venv: "venv:" }
73
- - { os: macos-latest , ruby: "3.1" , python: "3.8" , python_architecture: x64 , venv: "venv:" }
61
+ - { os: macos-latest , ruby: "3.3" , python: "3.x" , python_architecture: x64 , venv: "venv:" }
74
62
 
75
63
  #- { os: macos-latest , ruby: debug , python: "3.x" , python_architecture: x64 , venv: "" }
76
64
 
77
65
  steps:
78
- - uses: actions/checkout@v2
66
+ - uses: actions/checkout@v3
79
67
  with:
80
68
  fetch-depth: 1
81
69
 
@@ -84,7 +72,7 @@ jobs:
84
72
  with:
85
73
  ruby-version: ${{ matrix.ruby }}
86
74
 
87
- - uses: actions/setup-python@v2
75
+ - uses: actions/setup-python@v4
88
76
  with:
89
77
  python-version: ${{ matrix.python }}
90
78
  architecture: ${{ matrix.python_architecture }}
@@ -119,7 +107,7 @@ jobs:
119
107
  matrix:
120
108
  os:
121
109
  - ubuntu-20.04
122
- - macos-latest
110
+ #- macos-latest
123
111
  ruby:
124
112
  - "3.1"
125
113
  python:
@@ -26,7 +26,6 @@ jobs:
26
26
  - 2.6
27
27
  python:
28
28
  - 3.x
29
- - 2.x
30
29
  python_architecture:
31
30
  - x64
32
31
  include:
@@ -34,7 +33,7 @@ jobs:
34
33
  #- { os: windows-latest , ruby: mswin , python: 3.x , python_architecture: x64 }
35
34
 
36
35
  steps:
37
- - uses: actions/checkout@v2
36
+ - uses: actions/checkout@v3
38
37
  with:
39
38
  fetch-depth: 1
40
39
 
@@ -43,7 +42,7 @@ jobs:
43
42
  with:
44
43
  ruby-version: ${{ matrix.ruby }}
45
44
 
46
- - uses: actions/setup-python@v2
45
+ - uses: actions/setup-python@v4
47
46
  with:
48
47
  python-version: ${{ matrix.python }}
49
48
  architecture: ${{ matrix.python_architecture }}
data/CHANGES.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # The change history of PyCall
2
2
 
3
+ ## 1.5.2
4
+
5
+ * Fix memory leak with str(list) (#169).
6
+
7
+ *mknkmyza*
8
+
9
+ * Fix SEGV occured on Ruby process finalization.
10
+
11
+ * Fix for supporting Ruby >= 3.3.
12
+
13
+ * Fix for supporting Python >= 3.2.
14
+
15
+ ## 1.5.1
16
+
17
+ * Fix memory leak in rich compare methods (#167, #168).
18
+
19
+ *mknkmyza*
20
+
21
+ ## 1.5.0
22
+
23
+ * Fix to prevent distutils deprecation warning (#159)
24
+
25
+ *Christopher Dilks*
26
+
27
+ * Drop Python 2.7 support
28
+
29
+ * Fix memory leak of Python objects. (#129)
30
+ This should fixes #128 and maybe also fixes #164.
31
+
32
+ *mknkmyza*
33
+
3
34
  ## 1.4.2
4
35
 
5
36
  * Add supports of unary operators: `+@`, `-@`, `~`
data/README.md CHANGED
@@ -19,9 +19,7 @@ pycall.rb supports Ruby version 2.4 or higher.
19
19
 
20
20
  ## Supported Python versions
21
21
 
22
- pycall.rb supports Python version 2.7 or higher.
23
-
24
- Note that in Python 2.7 old-style class, that is defined without a super class, is not fully supported in pycall.rb.
22
+ pycall.rb supports Python version 3.7 or higher.
25
23
 
26
24
  ## Note for pyenv users
27
25
 
@@ -144,9 +142,9 @@ Use [mrkn/pandas.rb](https://github.com/mrkn/pandas.rb) instead of just importin
144
142
 
145
143
  PyCall wraps pointers of Python objects in `PyCall::PyPtr` objects.
146
144
  `PyCall::PyPtr` class has two subclasses, `PyCall::PyTypePtr` and
147
- `PyCall::PyRubyPtr`. `PyCall::PyTypePtr` is specialized for type (and classobj
148
- in 2.7) objects, and `PyCall::PyRubyPtr` is for the objects that wraps pointers
149
- of Ruby objects.
145
+ `PyCall::PyRubyPtr`. `PyCall::PyTypePtr` is specialized for type objects,
146
+ and `PyCall::PyRubyPtr` is for the objects that wraps pointers of
147
+ Ruby objects.
150
148
 
151
149
  These `PyCall::PyPtr` objects are used mainly in PyCall infrastructure.
152
150
  Instead, we usually treats the instances of `Object`, `Class`, `Module`, or
@@ -162,18 +160,33 @@ translates Ruby's coerce system into Python's swapped operation protocol.
162
160
  ## Deploying on Heroku
163
161
 
164
162
  Heroku's default version of Python is not compiled with the `--enabled-shared`
165
- option and can't be accessed by PyCall. Alternative [buildpacks](https://devcenter.heroku.com/articles/buildpacks) are available,
166
- including these that have been reported to work with PyCall:
167
-
168
- https://github.com/richgong/heroku-buildpack-python
169
- https://github.com/dsounded/heroku-buildpack-python
170
- https://github.com/ReforgeHQ/heroku-buildpack-python
171
-
172
- These community-developed buildpacks are not supported by Heroku, so it's
173
- worth examining the source to make sure the buildpack you use suits your
174
- needs. For instance, 'ReforgeHQ' works well with Python 3.8.1, but has not
175
- been configured to work with other versions and may not be as generally
176
- useful as the 'dsounded' or 'richgong' buildpacks.
163
+ option and can't be accessed by PyCall.
164
+
165
+ There are many ways to make our heroku use Python that is compiled with the `--enabled-shared` option:
166
+
167
+ - use Heroku's official Python buildpacks `post_compile` hooks to recompile the python if the `--enabled-shared` option is not enabled.
168
+ example script of `post_compile` in ruby on rails app `bin/post_compile`.
169
+
170
+ set -e
171
+ buildpack_url=https://github.com/heroku/heroku-buildpack-python
172
+ buildpack_vsn=v197 # adjust version accordingly https://github.com/heroku/heroku-buildpack-python/tags
173
+
174
+ # rebuild python if it's missing enable-shared
175
+ if ! python3 -msysconfig | grep enable-shared \
176
+ > /dev/null; then
177
+ PYTHON_VERSION="$(< runtime.txt)"
178
+ git clone -b "$buildpack_vsn" "$buildpack_url" _buildpack
179
+ export WORKSPACE_DIR="$PWD/_buildpack/builds"
180
+ rm -f .heroku/python/bin/python # prevent failing ln after build
181
+ sed -i 's!figure --pre!figure --enable-shared --pre!' \
182
+ "$WORKSPACE_DIR"/runtimes/python3
183
+ "$WORKSPACE_DIR/runtimes/$PYTHON_VERSION" /app/.heroku/python/
184
+ rm -fr _buildpack
185
+ fi
186
+
187
+ - use your own precompiled python with `--enabled-shared` options then fork the official heroku [python buildspacks](https://github.com/heroku/heroku-buildpack-python) and change the `BUILDPACK_S3_BASE_URL` with your own uploaded precompiled python in Amazon's S3.
188
+ - use 3rd party buildpacks from the [markets](https://elements.heroku.com/buildpacks) that have python with `--enabled-shared` option.
189
+
177
190
 
178
191
  The buildpack will expect to find both a `runtime.txt` and a `requirements.txt`
179
192
  file in the root of your project. You will need to add these to specify the
@@ -1,3 +1,5 @@
1
1
  require 'mkmf'
2
2
 
3
+ have_func("RTYPEDDATA_GET_DATA")
4
+
3
5
  create_makefile('pycall')
data/ext/pycall/gc.c CHANGED
@@ -1,5 +1,7 @@
1
1
  #include "pycall_internal.h"
2
2
 
3
+ static ID id_gcguard_table;
4
+
3
5
  struct gcguard {
4
6
  st_table *guarded_objects;
5
7
  };
@@ -24,6 +26,7 @@ gcguard_free(void* ptr)
24
26
  {
25
27
  struct gcguard *gg = (struct gcguard *)ptr;
26
28
  st_free_table(gg->guarded_objects);
29
+ rb_ivar_set(mPyCall, id_gcguard_table, Qnil);
27
30
  }
28
31
 
29
32
  static size_t
@@ -69,7 +72,6 @@ gcguard_delete(VALUE gcguard, PyObject *pyptr)
69
72
  }
70
73
  }
71
74
 
72
- static ID id_gcguard_table;
73
75
  static PyObject *weakref_callback_pyobj;
74
76
  static PyObject *gcguard_weakref_destroyed(PyObject *self, PyObject *weakref);
75
77
 
@@ -98,7 +100,9 @@ void
98
100
  pycall_gcguard_delete(PyObject *pyobj)
99
101
  {
100
102
  VALUE gcguard = rb_ivar_get(mPyCall, id_gcguard_table);
101
- gcguard_delete(gcguard, pyobj);
103
+ if (!NIL_P(gcguard)) {
104
+ gcguard_delete(gcguard, pyobj);
105
+ }
102
106
  }
103
107
 
104
108
  void
@@ -217,6 +217,10 @@ pycall_init_libpython_api_table(VALUE libpython_handle)
217
217
  INIT_API_TABLE_ENTRY2(PyUnicode_DecodeUTF8, PyUnicodeUCS2_DecodeUTF8, required);
218
218
  INIT_API_TABLE_ENTRY2(PyUnicode_FromFormatV, PyUnicodeUCS2_FromFormatV, required);
219
219
  }
220
+
221
+ INIT_API_TABLE_ENTRY(PyGILState_Check, required);
222
+ INIT_API_TABLE_ENTRY(PyGILState_Ensure, required);
223
+ INIT_API_TABLE_ENTRY(PyGILState_Release, required);
220
224
  }
221
225
 
222
226
  void
data/ext/pycall/pycall.c CHANGED
@@ -139,7 +139,15 @@ pycall_pyptr_free(void *ptr)
139
139
  fprintf(stderr, "zero refcnt object %p of type %s\n", pyobj, Py_TYPE(pyobj)->tp_name);
140
140
  }
141
141
  #endif /* PYCALL_DEBUG_DUMP_REFCNT */
142
- pycall_Py_DecRef(pyobj);
142
+
143
+ if (Py_API(PyGILState_Check())) {
144
+ pycall_Py_DecRef(pyobj);
145
+ }
146
+ else {
147
+ PyGILState_STATE gstate = Py_API(PyGILState_Ensure)();
148
+ pycall_Py_DecRef(pyobj);
149
+ Py_API(PyGILState_Release)(gstate);
150
+ }
143
151
  }
144
152
 
145
153
  static size_t _PySys_GetSizeOf(PyObject *);
@@ -792,8 +800,9 @@ pycall_libpython_helpers_m_compare(VALUE mod, VALUE op, VALUE pyptr_a, VALUE pyp
792
800
  if (!res) {
793
801
  pycall_pyerror_fetch_and_raise("PyObject_RichCompare in pycall_libpython_helpers_m_compare");
794
802
  }
795
-
796
- return pycall_pyobject_to_ruby(res);
803
+ VALUE obj = pycall_pyobject_to_ruby(res);
804
+ pycall_Py_DecRef(res);
805
+ return obj;
797
806
  }
798
807
 
799
808
  static int is_pyobject_wrapper(VALUE obj);
@@ -966,10 +975,10 @@ pycall_extract_kwargs_from_ruby_hash(VALUE key, VALUE value, VALUE arg)
966
975
  key_cstr = StringValueCStr(key);
967
976
  pyvalue = pycall_pyobject_from_ruby(value);
968
977
 
969
- if (Py_API(PyDict_SetItemString)(kwargs, key_cstr, pyvalue) < 0) {
970
- return ST_STOP;
971
- }
972
- return ST_CONTINUE;
978
+ int res = Py_API(PyDict_SetItemString)(kwargs, key_cstr, pyvalue);
979
+ pycall_Py_DecRef(pyvalue);
980
+
981
+ return (res < 0) ? ST_STOP : ST_CONTINUE;
973
982
  }
974
983
 
975
984
  static void
@@ -1061,6 +1070,10 @@ pycall_call_python_callable(PyObject *pycallable, int argc, VALUE *argv)
1061
1070
  }
1062
1071
 
1063
1072
  res = pyobject_call(pycallable, args, kwargs); /* New reference */
1073
+ pycall_Py_DecRef(args);
1074
+ if (kwargs) {
1075
+ pycall_Py_DecRef(kwargs);
1076
+ }
1064
1077
  if (!res) {
1065
1078
  pycall_pyerror_fetch_and_raise("PyObject_Call in pycall_call_python_callable");
1066
1079
  }
@@ -1099,9 +1112,9 @@ pycall_pyobject_wrapper_wrapper_method(int argc, VALUE *argv, VALUE wrapper)
1099
1112
 
1100
1113
  name_cstr[RSTRING_LEN(name) - 1] = '\0';
1101
1114
  res = Py_API(PyObject_SetAttrString)(pyobj, name_cstr, attr);
1115
+ pycall_Py_DecRef(attr);
1102
1116
  name_cstr[RSTRING_LEN(name) - 1] = '=';
1103
1117
  if (res == -1) {
1104
- pycall_Py_DecRef(attr);
1105
1118
  pycall_pyerror_fetch_and_raise("PyObject_SetAttrString in pycall_pyobject_wrapper_wrapper_method");
1106
1119
  }
1107
1120
 
@@ -1119,7 +1132,9 @@ pycall_pyobject_wrapper_wrapper_method(int argc, VALUE *argv, VALUE wrapper)
1119
1132
  if (PyType_Check(attr) || PyClass_Check(attr))
1120
1133
  return pycall_pyobject_to_ruby(attr);
1121
1134
 
1122
- return pycall_call_python_callable(attr, argc, argv);
1135
+ VALUE obj = pycall_call_python_callable(attr, argc, argv);
1136
+ pycall_Py_DecRef(attr);
1137
+ return obj;
1123
1138
  }
1124
1139
 
1125
1140
  static VALUE
@@ -1203,6 +1218,7 @@ pycall_libpython_helpers_m_getitem(VALUE mod, VALUE pyptr, VALUE key)
1203
1218
  pyobj_key = pycall_convert_index(key);
1204
1219
 
1205
1220
  pyobj_v = Py_API(PyObject_GetItem)(pyobj, pyobj_key);
1221
+ pycall_Py_DecRef(pyobj_key);
1206
1222
  if (!pyobj_v) {
1207
1223
  pycall_pyerror_fetch_and_raise("PyObject_GetItem in pycall_libpython_helpers_m_getitem");
1208
1224
  }
@@ -1223,11 +1239,11 @@ pycall_libpython_helpers_m_setitem(VALUE mod, VALUE pyptr, VALUE key, VALUE v)
1223
1239
  pyobj_value = pycall_pyobject_from_ruby(v);
1224
1240
 
1225
1241
  res = Py_API(PyObject_SetItem)(pyobj, pyobj_key, pyobj_value);
1242
+ pycall_Py_DecRef(pyobj_key);
1243
+ pycall_Py_DecRef(pyobj_value);
1226
1244
  if (res == -1) {
1227
1245
  pycall_pyerror_fetch_and_raise("PyObject_SetItem in pycall_libpython_helpers_m_setitem");
1228
1246
  }
1229
- Py_API(Py_DecRef(pyobj_key));
1230
- Py_API(Py_DecRef(pyobj_value));
1231
1247
 
1232
1248
  return v;
1233
1249
  }
@@ -1242,6 +1258,7 @@ pycall_libpython_helpers_m_delitem(VALUE mod, VALUE pyptr, VALUE key)
1242
1258
  pyobj_key = pycall_convert_index(key);
1243
1259
 
1244
1260
  res = Py_API(PyObject_DelItem)(pyobj, pyobj_key);
1261
+ pycall_Py_DecRef(pyobj_key);
1245
1262
  if (res == -1) {
1246
1263
  pycall_pyerror_fetch_and_raise("PyObject_DelItem");
1247
1264
  }
@@ -1261,7 +1278,9 @@ pycall_libpython_helpers_m_str(VALUE mod, VALUE pyptr)
1261
1278
  pycall_pyerror_fetch_and_raise("PyObject_Str");
1262
1279
  }
1263
1280
 
1264
- return pycall_pyobject_to_ruby(pyobj_str);
1281
+ VALUE v = pycall_pyobject_to_ruby(pyobj_str);
1282
+ pycall_Py_DecRef(pyobj_str);
1283
+ return v;
1265
1284
  }
1266
1285
 
1267
1286
  static VALUE
@@ -1273,6 +1292,7 @@ pycall_libpython_helpers_m_dict_contains(VALUE mod, VALUE pyptr, VALUE key)
1273
1292
  pyobj = check_get_pyobj_ptr(pyptr, Py_API(PyDict_Type));
1274
1293
  pyobj_key = pycall_pyobject_from_ruby(key);
1275
1294
  res = Py_API(PyDict_Contains)(pyobj, pyobj_key);
1295
+ pycall_Py_DecRef(pyobj_key);
1276
1296
  if (res == -1) {
1277
1297
  pycall_pyerror_fetch_and_raise("PyDict_Contains");
1278
1298
  }
@@ -1311,6 +1331,7 @@ pycall_libpython_helpers_m_sequence_contains(VALUE mod, VALUE pyptr, VALUE key)
1311
1331
 
1312
1332
  pyobj_key = pycall_pyobject_from_ruby(key);
1313
1333
  res = Py_API(PySequence_Contains)(pyobj, pyobj_key);
1334
+ pycall_Py_DecRef(pyobj_key);
1314
1335
  if (res == -1) {
1315
1336
  pycall_pyerror_fetch_and_raise("PySequence_Contains");
1316
1337
  }
@@ -1679,19 +1700,21 @@ pycall_pyunicode_to_ruby(PyObject *pyobj)
1679
1700
  return Qnil;
1680
1701
  }
1681
1702
 
1682
- pyobj = Py_API(PyUnicode_AsUTF8String)(pyobj);
1683
- if (!pyobj) {
1703
+ PyObject *pyobj_uni = Py_API(PyUnicode_AsUTF8String)(pyobj);
1704
+ if (!pyobj_uni) {
1684
1705
  Py_API(PyErr_Clear)();
1685
1706
  return Qnil;
1686
1707
  }
1687
1708
 
1688
- res = Py_API(PyString_AsStringAndSize)(pyobj, &str, &len);
1709
+ res = Py_API(PyString_AsStringAndSize)(pyobj_uni, &str, &len);
1689
1710
  if (res < 0) {
1690
- pycall_Py_DecRef(pyobj);
1711
+ pycall_Py_DecRef(pyobj_uni);
1691
1712
  return Qnil;
1692
1713
  }
1693
1714
 
1694
- return rb_enc_str_new(str, len, rb_enc_from_index(rb_utf8_encindex()));
1715
+ VALUE v = rb_enc_str_new(str, len, rb_enc_from_index(rb_utf8_encindex()));
1716
+ pycall_Py_DecRef(pyobj_uni);
1717
+ return v;
1695
1718
  }
1696
1719
 
1697
1720
  static VALUE
@@ -1708,6 +1731,7 @@ pycall_pytuple_to_a(PyObject *pyobj)
1708
1731
  PyObject *pytem = Py_API(PyTuple_GetItem)(pyobj, i);
1709
1732
  Py_API(Py_IncRef)(pytem);
1710
1733
  rb_ary_push(ary, pycall_pyobject_to_ruby(pytem));
1734
+ pycall_Py_DecRef(pytem);
1711
1735
  }
1712
1736
 
1713
1737
  return ary;
@@ -1726,6 +1750,7 @@ pycall_pysequence_to_a(PyObject *pyobj)
1726
1750
  for (i = 0; i < n; ++i) {
1727
1751
  PyObject *pytem = Py_API(PySequence_GetItem)(pyobj, i);
1728
1752
  rb_ary_push(ary, pycall_pyobject_to_ruby(pytem));
1753
+ pycall_Py_DecRef(pytem);
1729
1754
  }
1730
1755
 
1731
1756
  return ary;
@@ -1938,12 +1963,10 @@ pycall_pydict_from_ruby_iter(VALUE key, VALUE value, VALUE arg)
1938
1963
  pyobj_key = pycall_pyobject_from_ruby(key);
1939
1964
  pyobj_value = pycall_pyobject_from_ruby(value);
1940
1965
  res = Py_API(PyObject_SetItem)(pydictobj, pyobj_key, pyobj_value);
1941
- if (res == -1) {
1942
- return ST_STOP;
1943
- }
1944
- Py_API(Py_DecRef)(pyobj_key);
1945
- Py_API(Py_DecRef)(pyobj_value);
1946
- return ST_CONTINUE;
1966
+ pycall_Py_DecRef(pyobj_key);
1967
+ pycall_Py_DecRef(pyobj_value);
1968
+
1969
+ return (res == -1) ? ST_STOP : ST_CONTINUE;
1947
1970
  }
1948
1971
 
1949
1972
  PyObject *
@@ -519,6 +519,11 @@ PyObject * PyRuby_New(VALUE ruby_object);
519
519
 
520
520
  /* ==== thread support ==== */
521
521
 
522
+ typedef enum {
523
+ PyGILState_LOCKED,
524
+ PyGILState_UNLOCKED
525
+ } PyGILState_STATE;
526
+
522
527
  #if defined(PYCALL_THREAD_WIN32)
523
528
  typedef DWORD pycall_tls_key;
524
529
  #elif defined(PYCALL_THREAD_PTHREAD)
@@ -669,6 +674,10 @@ typedef struct {
669
674
  PyObject * (* PyUnicode_AsUTF8String)(PyObject *);
670
675
  PyObject * (* PyUnicode_DecodeUTF8)(char const*, Py_ssize_t, char const *);
671
676
  PyObject * (* PyUnicode_FromFormatV)(char const*, ...);
677
+
678
+ int (* PyGILState_Check)(void);
679
+ PyGILState_STATE (* PyGILState_Ensure)(void);
680
+ void (* PyGILState_Release)(PyGILState_STATE);
672
681
  } pycall_libpython_api_table_t;
673
682
 
674
683
  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);
@@ -59,10 +59,11 @@ PyObject *
59
59
  PyRuby_New(VALUE ruby_object)
60
60
  {
61
61
  if (!ruby_thread_has_gvl_p()) {
62
- CALL_WITH_GVL(PyRuby_New_impl, ruby_object);
62
+ return CALL_WITH_GVL(PyRuby_New_impl, ruby_object);
63
+ }
64
+ else {
65
+ return PyRuby_New_impl(ruby_object);
63
66
  }
64
-
65
- return PyRuby_New_impl(ruby_object);
66
67
  }
67
68
 
68
69
  static void *
@@ -90,7 +91,9 @@ PyRuby_dealloc_with_gvl(PyRubyObject *pyro)
90
91
  if (!ruby_thread_has_gvl_p()) {
91
92
  CALL_WITH_GVL(PyRuby_dealloc, pyro);
92
93
  }
93
- PyRuby_dealloc(pyro);
94
+ else {
95
+ PyRuby_dealloc(pyro);
96
+ }
94
97
  }
95
98
 
96
99
  static PyObject *
@@ -114,7 +117,9 @@ PyRuby_repr_with_gvl(PyRubyObject *pyro)
114
117
  if (!ruby_thread_has_gvl_p()) {
115
118
  return CALL_WITH_GVL(PyRuby_repr, pyro);
116
119
  }
117
- return PyRuby_repr(pyro);
120
+ else {
121
+ return PyRuby_repr(pyro);
122
+ }
118
123
  }
119
124
 
120
125
  #if SIZEOF_SSIZE_T < 8
@@ -154,7 +159,9 @@ PyRuby_hash_long_with_gvl(PyRubyObject *pyro)
154
159
  if (!ruby_thread_has_gvl_p()) {
155
160
  return (long)(intptr_t)CALL_WITH_GVL(PyRuby_hash_long, pyro);
156
161
  }
157
- return (long)(intptr_t)PyRuby_hash_long(pyro);
162
+ else {
163
+ return (long)(intptr_t)PyRuby_hash_long(pyro);
164
+ }
158
165
  }
159
166
 
160
167
  static void *
@@ -185,7 +192,9 @@ PyRuby_hash_hash_t_with_gvl(PyRubyObject *pyro)
185
192
  if (!ruby_thread_has_gvl_p()) {
186
193
  return (Py_hash_t)CALL_WITH_GVL(PyRuby_hash_hash_t, pyro);
187
194
  }
188
- return (Py_hash_t)PyRuby_hash_hash_t(pyro);
195
+ else {
196
+ return (Py_hash_t)PyRuby_hash_hash_t(pyro);
197
+ }
189
198
  }
190
199
 
191
200
  struct call_rb_funcallv_params {
@@ -269,8 +278,9 @@ PyRuby_call_with_gvl(PyRubyObject *pyro, PyObject *pyobj_args, PyObject *pyobj_k
269
278
  if (!ruby_thread_has_gvl_p()) {
270
279
  return CALL_WITH_GVL(PyRuby_call, &params);
271
280
  }
272
-
273
- return PyRuby_call(&params);
281
+ else {
282
+ return PyRuby_call(&params);
283
+ }
274
284
  }
275
285
 
276
286
  struct PyRuby_getattro_params {
@@ -348,8 +358,9 @@ PyRuby_getattro_with_gvl(PyRubyObject *pyro, PyObject *pyobj_name)
348
358
  if (!ruby_thread_has_gvl_p()) {
349
359
  return CALL_WITH_GVL(PyRuby_getattro, &params);
350
360
  }
351
-
352
- return PyRuby_getattro(&params);
361
+ else {
362
+ return PyRuby_getattro(&params);
363
+ }
353
364
  }
354
365
 
355
366
  /* ==== PyCall::PyRubyPtr ==== */
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python
2
2
 
3
3
  import ctypes.util
4
- from distutils.sysconfig import get_config_var, get_python_version
4
+ from sysconfig import get_config_var, get_python_version
5
5
  import os
6
6
  import sys
7
7
 
@@ -1,5 +1,5 @@
1
1
  module PyCall
2
- VERSION = "1.4.2"
2
+ VERSION = "1.5.2"
3
3
 
4
4
  module Version
5
5
  numbers, TAG = VERSION.split("-")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pycall
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 1.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenta Murata
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-08 00:00:00.000000000 Z
11
+ date: 2024-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -144,6 +144,7 @@ extensions:
144
144
  - ext/pycall/extconf.rb
145
145
  extra_rdoc_files: []
146
146
  files:
147
+ - ".github/dependabot.yml"
147
148
  - ".github/workflows/ci.yml"
148
149
  - ".github/workflows/windows.yml"
149
150
  - ".gitignore"
@@ -221,7 +222,7 @@ homepage: https://github.com/mrkn/pycall
221
222
  licenses:
222
223
  - MIT
223
224
  metadata: {}
224
- post_install_message:
225
+ post_install_message:
225
226
  rdoc_options: []
226
227
  require_paths:
227
228
  - lib
@@ -236,8 +237,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
236
237
  - !ruby/object:Gem::Version
237
238
  version: '0'
238
239
  requirements: []
239
- rubygems_version: 3.3.13
240
- signing_key:
240
+ rubygems_version: 3.5.10
241
+ signing_key:
241
242
  specification_version: 4
242
243
  summary: pycall
243
244
  test_files: []