pycall 1.4.1 → 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: b016b6c9b12867d113713238ecc171cc4fde8965197c79c59abf66d8bb3b252e
4
- data.tar.gz: abb36597376d37744972f7bb537ab61032387c73947d7846b9947bb622bf04ac
3
+ metadata.gz: 9b2526ea3050985dc6d864e979804fb4ebaa9c36d8239b48809a9cd31dd01de5
4
+ data.tar.gz: 68df5fcac7fd5c574009ebbc33f0d9c1724ff8d5057d4dfaa69832b8509e4a92
5
5
  SHA512:
6
- metadata.gz: 18bc020ef0c1f1d82e3796ae023170ee287bbf966c3efd12dd48f730eec585b7b70e00352d316e8e524e608c70bff0348937c1afc434ba7d6ae634223f0e1fa6
7
- data.tar.gz: 9ea69bb090386a7a280be6a7c779b406f49a3de2da5b406c64529be6a462535cbe9eefaad404e3dd1dab6bc98a5840e2825708f8d1602e1404ab4dbd83ce43b2
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,11 @@
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
+
3
9
  ## 1.4.1
4
10
 
5
11
  * Fix SEGV occurred on Windows
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,
@@ -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
  }
@@ -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.1"
2
+ VERSION = "1.4.2"
3
3
 
4
4
  module Version
5
5
  numbers, TAG = VERSION.split("-")
data/lib/pycall.rb CHANGED
@@ -59,6 +59,14 @@ module PyCall
59
59
  LibPython::Helpers.hasattr?(obj.__pyptr__, name)
60
60
  end
61
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
+
62
70
  def same?(left, right)
63
71
  case left
64
72
  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.1
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-07-12 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
@@ -236,7 +236,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
236
236
  - !ruby/object:Gem::Version
237
237
  version: '0'
238
238
  requirements: []
239
- rubygems_version: 3.2.21
239
+ rubygems_version: 3.3.13
240
240
  signing_key:
241
241
  specification_version: 4
242
242
  summary: pycall