pycall 1.4.0 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
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