pycall 1.4.0 → 1.4.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: 79fa29a4fd735c0741f03e74aadce297273cd2d64c0813b9ee2e20ad5fa321b9
4
- data.tar.gz: 108942ac4b4d45324644fe90af4e56e239f7ce3b2f27fa0d98d5defa439da8db
3
+ metadata.gz: 9b2526ea3050985dc6d864e979804fb4ebaa9c36d8239b48809a9cd31dd01de5
4
+ data.tar.gz: 68df5fcac7fd5c574009ebbc33f0d9c1724ff8d5057d4dfaa69832b8509e4a92
5
5
  SHA512:
6
- metadata.gz: eb899c3e9c353622945df3b816df4588cd3b4606f723c53973a2f8d77d8eb9edf94b7dbcf15ff4d33f65430fd6d38a8bc2ccc2fda2a1f8f274dc769b0280e42a
7
- data.tar.gz: ff84eb82b4e10d1a2f699abd32cfcdcc6159cba6b83f2258bc4100c7229bb49ca1c7593b5a6629ef2081007728bc3be5e266b65c2967c49c043fb3dfe0bf3835
6
+ metadata.gz: c52cd3ac7b709238a1b3ec95ed7eb45bcfaa5ef8a40b74f8de15cec928350152769c915250f27290e1b7f2bfb84032faa3a39837d0598c2927a114f6989f11dc
7
+ data.tar.gz: 6c45f609e09251815588b0a02095af9d221e2c715d4e614d16888326fc46c6158a631b6cc514d9b3e673468abf2834e003074a5e77f27b46098c5ab698328459
@@ -21,35 +21,58 @@ jobs:
21
21
  fail-fast: false
22
22
  matrix:
23
23
  os:
24
+ - ubuntu-latest
24
25
  - ubuntu-20.04
25
26
  - macos-latest
26
27
  ruby:
28
+ - "3.2"
29
+ - "3.1"
27
30
  - "3.0"
28
- - 2.7
29
- - 2.6
31
+ - "2.7"
30
32
  python:
31
- - 3.x
32
- - 2.x
33
+ - "3.x"
33
34
  python_architecture:
34
35
  - x64
35
36
  venv:
36
37
  - ""
37
38
  include:
38
- - { os: ubuntu-20.04 , ruby: 2.5 , python: 3.x , python_architecture: x64 , venv: "" }
39
- - { os: ubuntu-20.04 , ruby: 2.4 , python: 3.x , python_architecture: x64 , venv: "" }
40
- - { os: ubuntu-20.04 , ruby: 2.5 , python: 2.x , python_architecture: x64 , venv: "" }
41
- - { os: ubuntu-20.04 , ruby: 2.4 , python: 2.x , python_architecture: x64 , venv: "" }
42
- - { os: ubuntu-20.04 , ruby: 2.7 , python: 3.8 , python_architecture: x64 , venv: "" }
43
- - { os: ubuntu-20.04 , ruby: 2.7 , python: 3.7 , python_architecture: x64 , venv: "" }
44
- - { os: ubuntu-20.04 , ruby: 2.7 , python: 3.6 , python_architecture: x64 , venv: "" }
45
- - { os: ubuntu-18.04 , ruby: 2.7 , python: 3.8 , python_architecture: x64 , venv: "" }
46
- - { os: ubuntu-20.04 , ruby: debug , python: 3.x , python_architecture: x64 , venv: "" }
47
- - { os: ubuntu-20.04 , ruby: "3.0" , python: 3.x , python_architecture: x64 , venv: "venv:" }
48
- - { os: ubuntu-18.04 , ruby: "3.0" , python: 3.x , python_architecture: x64 , venv: "venv:" }
49
- - { os: ubuntu-18.04 , ruby: "3.0" , python: 3.8 , python_architecture: x64 , venv: "venv:" }
50
- - { os: macos-latest , ruby: "3.0" , python: 3.x , python_architecture: x64 , venv: "venv:" }
51
- - { os: macos-latest , ruby: "3.0" , python: 3.8 , python_architecture: x64 , venv: "venv:" }
52
- #- { os: macos-latest , ruby: debug , python: 3.x , python_architecture: x64 , venv: "" }
39
+ # Old ruby and the latest Python 3
40
+ - { os: ubuntu-20.04 , ruby: 2.6 , python: "3.x" , python_architecture: x64 , venv: "" }
41
+ - { os: ubuntu-20.04 , ruby: 2.5 , python: "3.x" , python_architecture: x64 , venv: "" }
42
+ - { os: ubuntu-20.04 , ruby: 2.4 , python: "3.x" , python_architecture: x64 , venv: "" }
43
+
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
+ # Ruby 2.7 with Each Python 3.x
53
+ - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.11" , python_architecture: x64 , venv: "" }
54
+ - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.10" , python_architecture: x64 , venv: "" }
55
+ - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.9" , python_architecture: x64 , venv: "" }
56
+ - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.8" , python_architecture: x64 , venv: "" }
57
+ - { os: ubuntu-20.04 , ruby: 2.7 , python: "3.7" , python_architecture: x64 , venv: "" }
58
+ - { 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
+
61
+ # Ruby-debug with the latest Python 3
62
+ - { os: ubuntu-20.04 , ruby: debug , python: "3.x" , python_architecture: x64 , venv: "" }
63
+
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:" }
70
+
71
+ # 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:" }
74
+
75
+ #- { os: macos-latest , ruby: debug , python: "3.x" , python_architecture: x64 , venv: "" }
53
76
 
54
77
  steps:
55
78
  - uses: actions/checkout@v2
@@ -98,9 +121,9 @@ jobs:
98
121
  - ubuntu-20.04
99
122
  - macos-latest
100
123
  ruby:
101
- - "3.0"
124
+ - "3.1"
102
125
  python:
103
- - 3.8
126
+ - "3.10"
104
127
 
105
128
  steps:
106
129
  - uses: actions/checkout@v2
data/CHANGES.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # The change history of PyCall
2
2
 
3
+ ## 1.4.2
4
+
5
+ * Add supports of unary operators: `+@`, `-@`, `~`
6
+ * Fix `without_gvl` for exceptions occurred in the given block
7
+ * Add PyCall.setattr and PyCall.delattr
8
+
9
+ ## 1.4.1
10
+
11
+ * Fix SEGV occurred on Windows
12
+ * Add PyCall.iterable
13
+
3
14
  ## 1.4.0
4
15
 
5
16
  * Explicitly states that Windows is not supported yet in README
data/README.md CHANGED
@@ -32,12 +32,6 @@ pyenv does not build the shared library in default, so you need to specify `--en
32
32
  $ env PYTHON_CONFIGURE_OPTS='--enable-shared' pyenv install 3.7.2
33
33
  ```
34
34
 
35
- ## Note for Windows users
36
-
37
- Currently, pycall.rb does not support Windows. Please try to use pycall.rb on WSL2 environment.
38
-
39
- On Windows, the error "[BUG] object allocation during garbage collection phase" is occurred at unpredictable timings.
40
-
41
35
  ## Installation
42
36
 
43
37
  Add this line to your application's Gemfile:
@@ -59,9 +53,8 @@ Or install it yourself as:
59
53
  Here is a simple example to call Python's `math.sin` function and compare it to
60
54
  the `Math.sin` in Ruby:
61
55
 
62
- require 'pycall/import'
63
- include PyCall::Import
64
- pyimport :math
56
+ require 'pycall'
57
+ math = PyCall.import_module("math")
65
58
  math.sin(math.pi / 4) - Math.sin(Math::PI / 4) # => 0.0
66
59
 
67
60
  Type conversions from Ruby to Python are automatically performed for numeric,
data/ext/pycall/gc.c CHANGED
@@ -1,5 +1,74 @@
1
1
  #include "pycall_internal.h"
2
2
 
3
+ struct gcguard {
4
+ st_table *guarded_objects;
5
+ };
6
+
7
+ static int
8
+ gcguard_mark_i(st_data_t key, st_data_t val, st_data_t arg)
9
+ {
10
+ VALUE obj = (VALUE)val;
11
+ rb_gc_mark(obj);
12
+ return ST_CONTINUE;
13
+ }
14
+
15
+ static void
16
+ gcguard_mark(void* ptr)
17
+ {
18
+ struct gcguard *gg = (struct gcguard *)ptr;
19
+ st_foreach(gg->guarded_objects, gcguard_mark_i, 0);
20
+ }
21
+
22
+ static void
23
+ gcguard_free(void* ptr)
24
+ {
25
+ struct gcguard *gg = (struct gcguard *)ptr;
26
+ st_free_table(gg->guarded_objects);
27
+ }
28
+
29
+ static size_t
30
+ gcguard_memsize(const void* ptr)
31
+ {
32
+ const struct gcguard *gg = (const struct gcguard *)ptr;
33
+ return st_memsize(gg->guarded_objects);
34
+ }
35
+
36
+ static rb_data_type_t gcguard_data_type = {
37
+ "PyCall::gcguard",
38
+ {
39
+ gcguard_mark,
40
+ gcguard_free,
41
+ gcguard_memsize,
42
+ },
43
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
44
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
45
+ #endif
46
+ };
47
+
48
+ static void
49
+ gcguard_aset(VALUE gcguard, PyObject *pyptr, VALUE rbobj)
50
+ {
51
+ struct gcguard *gg;
52
+ TypedData_Get_Struct(gcguard, struct gcguard, &gcguard_data_type, gg);
53
+
54
+ st_insert(gg->guarded_objects, (st_data_t)pyptr, (st_data_t)rbobj);
55
+ }
56
+
57
+ static void
58
+ gcguard_delete(VALUE gcguard, PyObject *pyptr)
59
+ {
60
+ if (rb_typeddata_is_kind_of(gcguard, &gcguard_data_type)) {
61
+ /* This check is necessary to avoid error on the process finalization phase */
62
+ struct gcguard *gg;
63
+ st_data_t key, val;
64
+
65
+ TypedData_Get_Struct(gcguard, struct gcguard, &gcguard_data_type, gg);
66
+
67
+ key = (st_data_t)pyptr;
68
+ st_delete(gg->guarded_objects, &key, &val);
69
+ }
70
+ }
71
+
3
72
  static ID id_gcguard_table;
4
73
  static PyObject *weakref_callback_pyobj;
5
74
  static PyObject *gcguard_weakref_destroyed(PyObject *self, PyObject *weakref);
@@ -21,15 +90,15 @@ gcguard_weakref_destroyed(PyObject *self, PyObject *weakref)
21
90
  void
22
91
  pycall_gcguard_aset(PyObject *pyobj, VALUE rbobj)
23
92
  {
24
- VALUE table = rb_ivar_get(mPyCall, id_gcguard_table);
25
- rb_hash_aset(table, PTR2NUM(pyobj), rbobj);
93
+ VALUE gcguard = rb_ivar_get(mPyCall, id_gcguard_table);
94
+ gcguard_aset(gcguard, pyobj, rbobj);
26
95
  }
27
96
 
28
97
  void
29
98
  pycall_gcguard_delete(PyObject *pyobj)
30
99
  {
31
- VALUE table = rb_ivar_get(mPyCall, id_gcguard_table);
32
- rb_hash_delete(table, PTR2NUM(pyobj));
100
+ VALUE gcguard = rb_ivar_get(mPyCall, id_gcguard_table);
101
+ gcguard_delete(gcguard, pyobj);
33
102
  }
34
103
 
35
104
  void
@@ -64,11 +133,21 @@ pycall_gcguard_register(PyObject *pyobj, VALUE obj)
64
133
  pycall_gcguard_aset(wref, obj);
65
134
  }
66
135
 
136
+ static VALUE
137
+ gcguard_new(void)
138
+ {
139
+ struct gcguard *gg;
140
+ VALUE obj = TypedData_Make_Struct(0, struct gcguard, &gcguard_data_type, gg);
141
+ gg->guarded_objects = st_init_numtable();
142
+
143
+ return obj;
144
+ }
145
+
67
146
  void
68
147
  pycall_init_gcguard(void)
69
148
  {
70
149
  id_gcguard_table = rb_intern("gcguard_table");
71
- rb_ivar_set(mPyCall, id_gcguard_table, rb_hash_new());
150
+ rb_ivar_set(mPyCall, id_gcguard_table, gcguard_new());
72
151
 
73
152
  weakref_callback_pyobj = Py_API(PyCFunction_NewEx)(&gcguard_weakref_callback_def, NULL, NULL);
74
153
  }
@@ -110,6 +110,7 @@ pycall_init_libpython_api_table(VALUE libpython_handle)
110
110
  INIT_API_TABLE_ENTRY(PyObject_GetAttrString, required);
111
111
  INIT_API_TABLE_ENTRY(PyObject_SetAttrString, required);
112
112
  INIT_API_TABLE_ENTRY(PyObject_HasAttrString, required);
113
+ INIT_API_TABLE_ENTRY(PyObject_DelAttrString, optional);
113
114
  INIT_API_TABLE_ENTRY(PyObject_GetItem, required);
114
115
  INIT_API_TABLE_ENTRY(PyObject_SetItem, required);
115
116
  INIT_API_TABLE_ENTRY(PyObject_DelItem, required);
data/ext/pycall/pycall.c CHANGED
@@ -52,7 +52,7 @@ pycall_python_hexversion(void)
52
52
 
53
53
  #define python_is_unicode_literals (python_major_version >= 3)
54
54
 
55
- long pycall_hash_salt;
55
+ intptr_t pycall_hash_salt;
56
56
 
57
57
  static VALUE pycall_call_python_callable(PyObject *pycallable, int argc, VALUE *argv);
58
58
 
@@ -80,7 +80,7 @@ pycall_without_gvl_p(void)
80
80
  *
81
81
  * In Win32 thread, the default value is 0 (initialized by TlsAlloc).
82
82
  */
83
- return (int)pycall_tls_get(without_gvl_key);
83
+ return pycall_tls_get(without_gvl_key) != (void*)0;
84
84
  }
85
85
 
86
86
  static inline int
@@ -107,6 +107,10 @@ pycall_without_gvl(VALUE (* func)(VALUE), VALUE arg)
107
107
 
108
108
  pycall_set_with_gvl();
109
109
 
110
+ if (state) {
111
+ rb_jump_tag(state);
112
+ }
113
+
110
114
  return result;
111
115
  }
112
116
 
@@ -410,7 +414,6 @@ pycall_pyptr_inspect(VALUE obj)
410
414
 
411
415
  cname = rb_class_name(CLASS_OF(obj));
412
416
  str = rb_sprintf("#<%"PRIsVALUE":%p type=%s addr=%p>", cname, (void*)obj, Py_TYPE(pyobj)->tp_name, pyobj);
413
- OBJ_INFECT(str, obj);
414
417
 
415
418
  return str;
416
419
  }
@@ -861,6 +864,51 @@ pycall_libpython_helpers_m_hasattr_p(VALUE mod, VALUE pyptr, VALUE name)
861
864
  return res ? Qtrue : Qfalse;
862
865
  }
863
866
 
867
+ static VALUE
868
+ pycall_libpython_helpers_m_setattr(VALUE mod, VALUE pyptr, VALUE name, VALUE val)
869
+ {
870
+ PyObject *pyobj, *pyval;
871
+
872
+ if (!is_pycall_pyptr(pyptr)) {
873
+ rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
874
+ }
875
+
876
+ pyobj = get_pyobj_ptr(pyptr);
877
+
878
+ if (RB_TYPE_P(name, T_SYMBOL)) {
879
+ name = rb_sym_to_s(name);
880
+ }
881
+
882
+ pyval = pycall_pyobject_from_ruby(val);
883
+ if (Py_API(PyObject_SetAttrString)(pyobj, StringValueCStr(name), pyval) == -1) {
884
+ pycall_pyerror_fetch_and_raise("PyObject_SetAttrString");
885
+ }
886
+
887
+ return Qnil;
888
+ }
889
+
890
+ static VALUE
891
+ pycall_libpython_helpers_m_delattr(VALUE mod, VALUE pyptr, VALUE name)
892
+ {
893
+ PyObject *pyobj;
894
+
895
+ if (!is_pycall_pyptr(pyptr)) {
896
+ rb_raise(rb_eTypeError, "PyCall::PyPtr is required");
897
+ }
898
+
899
+ pyobj = get_pyobj_ptr(pyptr);
900
+
901
+ if (RB_TYPE_P(name, T_SYMBOL)) {
902
+ name = rb_sym_to_s(name);
903
+ }
904
+
905
+ if (Py_API(PyObject_DelAttrString)(pyobj, StringValueCStr(name)) == -1) {
906
+ pycall_pyerror_fetch_and_raise("PyObject_DelAttrString");
907
+ }
908
+
909
+ return Qnil;
910
+ }
911
+
864
912
  static VALUE
865
913
  pycall_libpython_helpers_m_callable_p(VALUE mod, VALUE pyptr)
866
914
  {
@@ -1077,7 +1125,7 @@ pycall_pyobject_wrapper_wrapper_method(int argc, VALUE *argv, VALUE wrapper)
1077
1125
  static VALUE
1078
1126
  pycall_libpython_helpers_m_define_wrapper_method(VALUE mod, VALUE wrapper, VALUE name)
1079
1127
  {
1080
- VALUE pyptr, name_sym;
1128
+ VALUE pyptr;
1081
1129
  PyObject *pyobj, *attr;
1082
1130
  char *name_cstr;
1083
1131
 
@@ -1089,12 +1137,8 @@ pycall_libpython_helpers_m_define_wrapper_method(VALUE mod, VALUE wrapper, VALUE
1089
1137
  pyobj = get_pyobj_ptr(pyptr);
1090
1138
 
1091
1139
  if (RB_TYPE_P(name, T_SYMBOL)) {
1092
- name_sym = name;
1093
1140
  name = rb_sym_to_s(name);
1094
1141
  }
1095
- else if (RB_TYPE_P(name, T_STRING)) {
1096
- name_sym = rb_str_intern(name);
1097
- }
1098
1142
 
1099
1143
  name_cstr = StringValueCStr(name);
1100
1144
  if (name_cstr[RSTRING_LEN(name) - 1] == '=') {
@@ -1189,7 +1233,7 @@ pycall_libpython_helpers_m_setitem(VALUE mod, VALUE pyptr, VALUE key, VALUE v)
1189
1233
  }
1190
1234
 
1191
1235
  static VALUE
1192
- pycall_libpython_helpers_m_delitem(VALUE mod, VALUE pyptr, VALUE key, VALUE v)
1236
+ pycall_libpython_helpers_m_delitem(VALUE mod, VALUE pyptr, VALUE key)
1193
1237
  {
1194
1238
  PyObject *pyobj, *pyobj_key;
1195
1239
  int res;
@@ -1202,7 +1246,7 @@ pycall_libpython_helpers_m_delitem(VALUE mod, VALUE pyptr, VALUE key, VALUE v)
1202
1246
  pycall_pyerror_fetch_and_raise("PyObject_DelItem");
1203
1247
  }
1204
1248
 
1205
- return v;
1249
+ return Qnil;
1206
1250
  }
1207
1251
 
1208
1252
  static VALUE
@@ -2017,6 +2061,8 @@ pycall_pyerror_fetch_and_raise(char const *format, ...)
2017
2061
  va_list args;
2018
2062
  VALUE pyerror, msg;
2019
2063
 
2064
+ RBIMPL_NONNULL_ARG(format);
2065
+
2020
2066
  pyerror = pycall_pyerror_fetch();
2021
2067
  if (!NIL_P(pyerror))
2022
2068
  rb_exc_raise(pyerror);
@@ -2074,11 +2120,24 @@ pycall_pystring_from_formatv(char const *format, va_list vargs)
2074
2120
 
2075
2121
  /* ==== Python ==== */
2076
2122
 
2123
+ int
2124
+ pycall_PyObject_DelAttrString(PyObject *pyobj, const char *attr_name)
2125
+ {
2126
+ /* PyObject_DelAttrString is defined by using PyObject_SetAttrString in CPython's abstract.h */
2127
+ return Py_API(PyObject_SetAttrString)(pyobj, attr_name, NULL);
2128
+ }
2129
+
2077
2130
  static void
2078
2131
  init_python(void)
2079
2132
  {
2080
2133
  static char const *argv[1] = { "" };
2081
2134
 
2135
+ /* optional functions */
2136
+ if (! Py_API(PyObject_DelAttrString)) {
2137
+ /* The case of PyObject_DelAttrString as a macro */
2138
+ Py_API(PyObject_DelAttrString) = pycall_PyObject_DelAttrString;
2139
+ }
2140
+
2082
2141
  Py_API(Py_InitializeEx)(0);
2083
2142
  Py_API(PySys_SetArgvEx)(0, (char **)argv, 0);
2084
2143
 
@@ -2236,7 +2295,7 @@ Init_pycall(void)
2236
2295
 
2237
2296
  rb_define_module_function(mPyCall, "after_fork", pycall_after_fork, 0);
2238
2297
 
2239
- pycall_tls_create(&without_gvl_key);
2298
+ pycall_tls_create((pycall_tls_key *)&without_gvl_key);
2240
2299
  rb_define_module_function(mPyCall, "without_gvl", pycall_m_without_gvl, 0);
2241
2300
 
2242
2301
  /* PyCall::PyPtr */
@@ -2301,6 +2360,8 @@ Init_pycall(void)
2301
2360
  rb_define_module_function(mHelpers, "compare", pycall_libpython_helpers_m_compare, 3);
2302
2361
  rb_define_module_function(mHelpers, "getattr", pycall_libpython_helpers_m_getattr, -1);
2303
2362
  rb_define_module_function(mHelpers, "hasattr?", pycall_libpython_helpers_m_hasattr_p, 2);
2363
+ rb_define_module_function(mHelpers, "setattr", pycall_libpython_helpers_m_setattr, 3);
2364
+ rb_define_module_function(mHelpers, "delattr", pycall_libpython_helpers_m_delattr, 2);
2304
2365
  rb_define_module_function(mHelpers, "callable?", pycall_libpython_helpers_m_callable_p, 1);
2305
2366
  rb_define_module_function(mHelpers, "call_object", pycall_libpython_helpers_m_call_object, -1);
2306
2367
  rb_define_module_function(mHelpers, "getitem", pycall_libpython_helpers_m_getitem, 2);
@@ -34,6 +34,22 @@ extern "C" {
34
34
  # error ---->> ruby requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<----
35
35
  #endif
36
36
 
37
+ #ifndef RUBY_ASSERT
38
+ # define RUBY_ASSERT(expr) assert(expr)
39
+ #endif
40
+
41
+ #ifndef RBIMPL_ATTR_NONNULL
42
+ # define RBIMPL_ATTR_NONNULL(list) /* void */
43
+ #endif
44
+
45
+ #ifndef RBIMPL_NONNULL_ARG
46
+ # define RBIMPL_NONNULL_ARG(arg) RUBY_ASSERT(arg)
47
+ #endif
48
+
49
+ #ifndef RBIMPL_ATTR_FORMAT
50
+ # define RBIMPL_ATTR_FORMAT(x, y, z) /* void */
51
+ #endif
52
+
37
53
  #ifndef RB_INTEGER_TYPE_P
38
54
  # define RB_INTEGER_TYPE_P(obj) pycall_integer_type_p(obj)
39
55
  static inline int
@@ -568,6 +584,7 @@ typedef struct {
568
584
  PyObject * (* PyObject_GetAttrString)(PyObject *, char const *);
569
585
  int (* PyObject_SetAttrString)(PyObject *, char const *, PyObject *);
570
586
  int (* PyObject_HasAttrString)(PyObject *, char const *);
587
+ int (* PyObject_DelAttrString)(PyObject *, char const *);
571
588
  PyObject * (* PyObject_GetItem)(PyObject *, PyObject *);
572
589
  int (* PyObject_SetItem)(PyObject *obj, PyObject *key, PyObject *value);
573
590
  int (* PyObject_DelItem)(PyObject *, PyObject *);
@@ -692,6 +709,8 @@ PyObject *pycall_pylist_from_ruby(VALUE);
692
709
  PyObject *pycall_pydict_from_ruby(VALUE);
693
710
  PyObject *pycall_pyslice_from_ruby(VALUE);
694
711
 
712
+ RBIMPL_ATTR_NONNULL((1))
713
+ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 0)
695
714
  NORETURN(void pycall_pyerror_fetch_and_raise(char const *format, ...));
696
715
 
697
716
  unsigned long pycall_default_tp_flags(void);
@@ -714,7 +733,7 @@ void pycall_init_gcguard(void);
714
733
  void pycall_init_ruby_wrapper(void);
715
734
 
716
735
  #define pycall_hash_salt_32 0xb592cd9b
717
- extern long pycall_hash_salt;
736
+ extern intptr_t pycall_hash_salt;
718
737
  extern VALUE pycall_mPyCall;
719
738
  extern VALUE pycall_cPyPtr;
720
739
  extern VALUE pycall_eError;
@@ -136,7 +136,7 @@ static void *
136
136
  PyRuby_hash_long(PyRubyObject *pyro)
137
137
  {
138
138
  VALUE obj, rbhash;
139
- long h;
139
+ intptr_t h;
140
140
 
141
141
  obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)pyro);
142
142
  if (obj == Qundef)
@@ -152,9 +152,9 @@ static long
152
152
  PyRuby_hash_long_with_gvl(PyRubyObject *pyro)
153
153
  {
154
154
  if (!ruby_thread_has_gvl_p()) {
155
- return (long)CALL_WITH_GVL(PyRuby_hash_long, pyro);
155
+ return (long)(intptr_t)CALL_WITH_GVL(PyRuby_hash_long, pyro);
156
156
  }
157
- return (long)PyRuby_hash_long(pyro);
157
+ return (long)(intptr_t)PyRuby_hash_long(pyro);
158
158
  }
159
159
 
160
160
  static void *
@@ -171,10 +171,10 @@ PyRuby_hash_hash_t(PyRubyObject *pyro)
171
171
  #if SIZEOF_PY_HASH_T == SIZEOF_LONG
172
172
  /* In this case, we can assume sizeof(Py_hash_t) == sizeof(long) */
173
173
  h = NUM2SSIZET(rbhash);
174
- return (void *)(h == -1 ? (Py_hash_t)pycall_hash_salt : h);
174
+ return (void *)(h == -1 ? pycall_hash_salt : h);
175
175
  #else
176
176
  /* In this case, we can assume sizeof(long) == 4 and sizeof(Py_hash_t) == 8 */
177
- h = (pycall_hash_salt_32 << 32) | FIX2LONG(rbhash);
177
+ h = ((Py_hash_t)pycall_hash_salt_32 << 32) | FIX2LONG(rbhash);
178
178
  return (void *)(h == -1 ? ((pycall_hash_salt << 32) | pycall_hash_salt) : h);
179
179
  #endif
180
180
  }
@@ -0,0 +1,32 @@
1
+ module PyCall
2
+ class IterableWrapper
3
+ include Enumerable
4
+
5
+ def initialize(obj)
6
+ @obj = check_iterable(obj)
7
+ end
8
+
9
+ private def check_iterable(obj)
10
+ unless PyCall.hasattr?(obj, :__iter__)
11
+ raise ArgumentError, "%p object is not iterable" % obj
12
+ end
13
+ obj
14
+ end
15
+
16
+ def each
17
+ return enum_for(__method__) unless block_given?
18
+ iter = @obj.__iter__()
19
+ while true
20
+ begin
21
+ yield iter.__next__()
22
+ rescue PyCall::PyError => err
23
+ if err.type == PyCall.builtins.StopIteration
24
+ break
25
+ else
26
+ raise err
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -13,6 +13,12 @@ module PyCall
13
13
  end
14
14
 
15
15
  OPERATOR_METHOD_NAMES = {
16
+ # Unary operators
17
+ :+@ => :__pos__,
18
+ :-@ => :__neg__,
19
+ :~ => :__invert__,
20
+
21
+ # Binary operators
16
22
  :+ => :__add__,
17
23
  :- => :__sub__,
18
24
  :* => :__mul__,
@@ -1,5 +1,5 @@
1
1
  module PyCall
2
- VERSION = "1.4.0"
2
+ VERSION = "1.4.2"
3
3
 
4
4
  module Version
5
5
  numbers, TAG = VERSION.split("-")
@@ -6,7 +6,12 @@ module PyCall
6
6
  rescue
7
7
  WMAP_SUPPORT_INT_KEY = false
8
8
  else
9
- WMAP_SUPPORT_INT_KEY = true
9
+ case RUBY_PLATFORM
10
+ when /cygwin/, /mingw/, /mswin/
11
+ WMAP_SUPPORT_INT_KEY = false
12
+ else
13
+ WMAP_SUPPORT_INT_KEY = true
14
+ end
10
15
  end
11
16
 
12
17
  if WMAP_SUPPORT_INT_KEY
data/lib/pycall.rb CHANGED
@@ -5,6 +5,7 @@ module PyCall
5
5
  require 'pycall/pyobject_wrapper'
6
6
  require 'pycall/pytypeobject_wrapper'
7
7
  require 'pycall/pymodule_wrapper'
8
+ require 'pycall/iterable_wrapper'
8
9
  require 'pycall/init'
9
10
 
10
11
  module_function
@@ -58,6 +59,14 @@ module PyCall
58
59
  LibPython::Helpers.hasattr?(obj.__pyptr__, name)
59
60
  end
60
61
 
62
+ def setattr(obj, name, val)
63
+ LibPython::Helpers.setattr(obj.__pyptr__, name, val)
64
+ end
65
+
66
+ def delattr(obj, name)
67
+ LibPython::Helpers.delattr(obj.__pyptr__, name)
68
+ end
69
+
61
70
  def same?(left, right)
62
71
  case left
63
72
  when PyObjectWrapper
@@ -73,6 +82,10 @@ module PyCall
73
82
  LibPython::Helpers.import_module(name)
74
83
  end
75
84
 
85
+ def iterable(obj)
86
+ IterableWrapper.new(obj)
87
+ end
88
+
76
89
  def len(obj)
77
90
  case obj
78
91
  when PyObjectWrapper
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.0
4
+ version: 1.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenta Murata
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-28 00:00:00.000000000 Z
11
+ date: 2023-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -196,6 +196,7 @@ files:
196
196
  - lib/pycall/import.rb
197
197
  - lib/pycall/init.rb
198
198
  - lib/pycall/iruby_helper.rb
199
+ - lib/pycall/iterable_wrapper.rb
199
200
  - lib/pycall/libpython.rb
200
201
  - lib/pycall/libpython/finder.rb
201
202
  - lib/pycall/libpython/pyobject_struct.rb
@@ -235,7 +236,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
235
236
  - !ruby/object:Gem::Version
236
237
  version: '0'
237
238
  requirements: []
238
- rubygems_version: 3.2.3
239
+ rubygems_version: 3.3.13
239
240
  signing_key:
240
241
  specification_version: 4
241
242
  summary: pycall