pycall 1.0.3 → 1.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +6 -3
- data/CHANGES.md +22 -0
- data/README.md +2 -2
- data/Rakefile +2 -0
- data/appveyor.yml +10 -44
- data/ext/pycall/libpython.c +4 -0
- data/ext/pycall/pycall.c +50 -3
- data/ext/pycall/pycall.h +23 -0
- data/ext/pycall/pycall_internal.h +8 -1
- data/ext/pycall/ruby_wrapper.c +170 -79
- data/lib/pycall/conversion.rb +1 -1
- data/lib/pycall/version.rb +1 -1
- data/pycall.gemspec +1 -0
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 78588bb0a23c7fa9b5c522113598027e8c98aea9fb9b72e96b64a1db4e9cff41
|
4
|
+
data.tar.gz: '08d504ae9fdaa7ea8f532ca10848df3119264d956b259b40b3dfb356f5ea5834'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3d9c586c37ec66a8a6a7bd1093b5fd0848aad2602ab6784fe73a50c08a05402289601d1e87d7bfe13f51b54f2f8002790e7c95ac4899de339ad8af7dedccae3
|
7
|
+
data.tar.gz: b3c3d61680274ff6e612dabd28818522637f479225f43a9a8025d2a036127b3fddc62d2342456673cf96cdc280ce8e388fa503e904b5d5860b44c0b0fa8c3a29
|
data/.travis.yml
CHANGED
@@ -7,9 +7,10 @@ sudo: required
|
|
7
7
|
|
8
8
|
rvm:
|
9
9
|
- ruby-head
|
10
|
-
- 2.
|
10
|
+
- 2.5.0
|
11
|
+
- 2.4.3
|
11
12
|
- 2.3.5
|
12
|
-
- 2.2.
|
13
|
+
- 2.2.9
|
13
14
|
- 2.1.10
|
14
15
|
|
15
16
|
env:
|
@@ -39,8 +40,10 @@ matrix:
|
|
39
40
|
compiler: clang
|
40
41
|
rvm: 2.4.1
|
41
42
|
env: PYENV_VERSION=miniconda3-4.3.11
|
42
|
-
|
43
|
+
allow_failures:
|
43
44
|
- os: osx
|
45
|
+
- rvm: 2.2.9
|
46
|
+
- rvm: 2.1.10
|
44
47
|
|
45
48
|
before_install:
|
46
49
|
- gem update --system
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
# The change history of PyCall
|
2
2
|
|
3
|
+
## master
|
4
|
+
|
5
|
+
* Add `PyCall::Tuple#to_ary`
|
6
|
+
|
7
|
+
*Naoto Takai*
|
8
|
+
|
9
|
+
* Release GVL while the Python interpreter is running
|
10
|
+
|
11
|
+
* Drop support Ruby 2.2.x and 2.1.x
|
12
|
+
|
13
|
+
* Release GVL while the Python interpreter is running [Fix #45]
|
14
|
+
|
15
|
+
* Add public header file
|
16
|
+
|
17
|
+
* Use PyPtr.none? instead of removed PyCall.none?
|
18
|
+
|
19
|
+
*Kouhei Sutou*
|
20
|
+
|
21
|
+
* Export PyObject convert functions
|
22
|
+
|
23
|
+
*Kouhei Sutou*
|
24
|
+
|
3
25
|
## 1.0.3
|
4
26
|
|
5
27
|
* Fix anaconda support to define the environment variable `PYTHONHOME`.
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# PyCall: Calling Python functions from the Ruby language
|
2
2
|
|
3
|
-
[![Build Status](https://travis-ci.org/mrkn/pycall.rb.svg?branch=
|
4
|
-
[![Build status](https://ci.appveyor.com/api/projects/status/
|
3
|
+
[![Build Status](https://travis-ci.org/mrkn/pycall.rb.svg?branch=master)](https://travis-ci.org/mrkn/pycall.rb)
|
4
|
+
[![Build status](https://ci.appveyor.com/api/projects/status/071is0f4iu0vy8lp/branch/master?svg=true)](https://ci.appveyor.com/project/mrkn/pycall.rb/branch/master)
|
5
5
|
|
6
6
|
This library provides the features to directly call and partially interoperate
|
7
7
|
with Python from the Ruby language. You can import arbitrary Python modules
|
data/Rakefile
CHANGED
data/appveyor.yml
CHANGED
@@ -1,71 +1,37 @@
|
|
1
1
|
---
|
2
2
|
environment:
|
3
3
|
matrix:
|
4
|
-
# Ruby 2.
|
5
|
-
- ruby_version: "
|
4
|
+
# Ruby 2.4 (32bit)
|
5
|
+
- ruby_version: "24"
|
6
6
|
PYTHONDIR: "C:\\Python27"
|
7
7
|
PYTHON: "C:\\Python27\\python.exe"
|
8
8
|
|
9
|
-
- ruby_version: "
|
9
|
+
- ruby_version: "24"
|
10
10
|
PYTHONDIR: "C:\\Python34"
|
11
11
|
PYTHON: "C:\\Python34\\python.exe"
|
12
12
|
|
13
|
-
- ruby_version: "
|
13
|
+
- ruby_version: "24"
|
14
14
|
PYTHONDIR: "C:\\Python35"
|
15
15
|
PYTHON: "C:\\Python35\\python.exe"
|
16
16
|
|
17
|
-
- ruby_version: "
|
17
|
+
- ruby_version: "24"
|
18
18
|
PYTHONDIR: "C:\\Python36"
|
19
19
|
PYTHON: "C:\\Python36\\python.exe"
|
20
20
|
|
21
|
-
# Ruby 2.
|
22
|
-
- ruby_version: "
|
21
|
+
# Ruby 2.4 (64bit)
|
22
|
+
- ruby_version: "24-x64"
|
23
23
|
PYTHONDIR: "C:\\Python27-x64"
|
24
24
|
PYTHON: "C:\\Python27-x64\\python.exe"
|
25
25
|
|
26
|
-
- ruby_version: "
|
26
|
+
- ruby_version: "24-x64"
|
27
27
|
PYTHONDIR: "C:\\Python34-x64"
|
28
28
|
PYTHON: "C:\\Python34-x64\\python.exe"
|
29
29
|
|
30
|
-
- ruby_version: "
|
30
|
+
- ruby_version: "24-x64"
|
31
31
|
PYTHONDIR: "C:\\Python35-x64"
|
32
32
|
PYTHON: "C:\\Python35-x64\\python.exe"
|
33
33
|
|
34
|
-
- ruby_version: "
|
35
|
-
PYTHONDIR: "C:\\Python36-x64"
|
36
|
-
PYTHON: "C:\\Python36-x64\\python.exe"
|
37
|
-
|
38
|
-
# Ruby 2.2 (32bit)
|
39
|
-
- ruby_version: "22"
|
40
|
-
PYTHONDIR: "C:\\Python27"
|
41
|
-
PYTHON: "C:\\Python27\\python.exe"
|
42
|
-
|
43
|
-
- ruby_version: "22"
|
44
|
-
PYTHONDIR: "C:\\Python34"
|
45
|
-
PYTHON: "C:\\Python34\\python.exe"
|
46
|
-
|
47
|
-
- ruby_version: "22"
|
48
|
-
PYTHONDIR: "C:\\Python35"
|
49
|
-
PYTHON: "C:\\Python35\\python.exe"
|
50
|
-
|
51
|
-
- ruby_version: "22"
|
52
|
-
PYTHONDIR: "C:\\Python36"
|
53
|
-
PYTHON: "C:\\Python36\\python.exe"
|
54
|
-
|
55
|
-
# Ruby 2.2 (64bit)
|
56
|
-
- ruby_version: "22-x64"
|
57
|
-
PYTHONDIR: "C:\\Python27-x64"
|
58
|
-
PYTHON: "C:\\Python27-x64\\python.exe"
|
59
|
-
|
60
|
-
- ruby_version: "22-x64"
|
61
|
-
PYTHONDIR: "C:\\Python34-x64"
|
62
|
-
PYTHON: "C:\\Python34-x64\\python.exe"
|
63
|
-
|
64
|
-
- ruby_version: "22-x64"
|
65
|
-
PYTHONDIR: "C:\\Python35-x64"
|
66
|
-
PYTHON: "C:\\Python35-x64\\python.exe"
|
67
|
-
|
68
|
-
- ruby_version: "22-x64"
|
34
|
+
- ruby_version: "24-x64"
|
69
35
|
PYTHONDIR: "C:\\Python36-x64"
|
70
36
|
PYTHON: "C:\\Python36-x64\\python.exe"
|
71
37
|
|
data/ext/pycall/libpython.c
CHANGED
@@ -154,12 +154,16 @@ pycall_init_libpython_api_table(VALUE libpython_handle)
|
|
154
154
|
|
155
155
|
INIT_API_TABLE_ENTRY(PyIter_Next, required);
|
156
156
|
|
157
|
+
INIT_API_TABLE_ENTRY(PyEval_ThreadsInitialized, required);
|
158
|
+
INIT_API_TABLE_ENTRY(PyEval_InitThreads, required);
|
159
|
+
|
157
160
|
INIT_API_TABLE_ENTRY(PyErr_Occurred, required);
|
158
161
|
INIT_API_TABLE_ENTRY(PyErr_Fetch, required);
|
159
162
|
INIT_API_TABLE_ENTRY(PyErr_Restore, required);
|
160
163
|
INIT_API_TABLE_ENTRY(PyErr_Clear, required);
|
161
164
|
INIT_API_TABLE_ENTRY(PyErr_SetString, required);
|
162
165
|
INIT_API_TABLE_ENTRY(PyErr_Format, required);
|
166
|
+
INIT_API_TABLE_ENTRY(PyErr_SetInterrupt, required);
|
163
167
|
|
164
168
|
INIT_API_TABLE_ENTRY(PyImport_ImportModule, required);
|
165
169
|
INIT_API_TABLE_ENTRY(PyImport_ImportModuleLevel, required);
|
data/ext/pycall/pycall.c
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#include "pycall_internal.h"
|
2
|
+
#include "pycall.h"
|
2
3
|
#include <ruby/encoding.h>
|
3
4
|
|
4
5
|
#include <stdarg.h>
|
@@ -143,6 +144,12 @@ get_pyobj_ptr(VALUE obj)
|
|
143
144
|
return pyobj;
|
144
145
|
}
|
145
146
|
|
147
|
+
PyObject *
|
148
|
+
pycall_pyptr_get_pyobj_ptr(VALUE pyptr)
|
149
|
+
{
|
150
|
+
return get_pyobj_ptr(pyptr);
|
151
|
+
}
|
152
|
+
|
146
153
|
static inline PyObject*
|
147
154
|
try_get_pyobj_ptr(VALUE obj)
|
148
155
|
{
|
@@ -727,7 +734,6 @@ pycall_libpython_helpers_m_compare(VALUE mod, VALUE op, VALUE pyptr_a, VALUE pyp
|
|
727
734
|
}
|
728
735
|
|
729
736
|
static int is_pyobject_wrapper(VALUE obj);
|
730
|
-
static PyObject * pycall_pyobject_wrapper_get_pyobj_ptr(VALUE obj);
|
731
737
|
|
732
738
|
VALUE
|
733
739
|
pycall_getattr_default(VALUE obj, char const *name, VALUE default_value)
|
@@ -858,6 +864,42 @@ pycall_extract_kwargs_from_ruby_hash(VALUE key, VALUE value, VALUE arg)
|
|
858
864
|
return ST_CONTINUE;
|
859
865
|
}
|
860
866
|
|
867
|
+
static void
|
868
|
+
pycall_interrupt_python_thread(void *ptr)
|
869
|
+
{
|
870
|
+
Py_API(PyErr_SetInterrupt)();
|
871
|
+
}
|
872
|
+
|
873
|
+
struct call_pyobject_call_params {
|
874
|
+
PyObject *pycallable;
|
875
|
+
PyObject *args;
|
876
|
+
PyObject *kwargs;
|
877
|
+
};
|
878
|
+
|
879
|
+
PyObject *
|
880
|
+
call_pyobject_call(struct call_pyobject_call_params *params)
|
881
|
+
{
|
882
|
+
PyObject *res;
|
883
|
+
res = Py_API(PyObject_Call)(params->pycallable, params->args, params->kwargs); /* New reference */
|
884
|
+
return res;
|
885
|
+
}
|
886
|
+
|
887
|
+
PyObject *
|
888
|
+
pyobject_call_without_gvl(PyObject *pycallable, PyObject *args, PyObject *kwargs)
|
889
|
+
{
|
890
|
+
PyObject *res;
|
891
|
+
struct call_pyobject_call_params params;
|
892
|
+
params.pycallable = pycallable;
|
893
|
+
params.args = args;
|
894
|
+
params.kwargs = kwargs;
|
895
|
+
|
896
|
+
res = (PyObject *)rb_thread_call_without_gvl(
|
897
|
+
(void * (*)(void *))call_pyobject_call, (void *)¶ms,
|
898
|
+
(rb_unblock_function_t *)pycall_interrupt_python_thread, NULL);
|
899
|
+
|
900
|
+
return res;
|
901
|
+
}
|
902
|
+
|
861
903
|
static VALUE
|
862
904
|
pycall_call_python_callable(PyObject *pycallable, int argc, VALUE *argv)
|
863
905
|
{
|
@@ -905,7 +947,7 @@ pycall_call_python_callable(PyObject *pycallable, int argc, VALUE *argv)
|
|
905
947
|
}
|
906
948
|
}
|
907
949
|
|
908
|
-
res =
|
950
|
+
res = pyobject_call_without_gvl(pycallable, args, kwargs); /* New reference */
|
909
951
|
if (!res) {
|
910
952
|
pycall_pyerror_fetch_and_raise("PyObject_Call in pycall_call_python_callable");
|
911
953
|
}
|
@@ -1213,7 +1255,7 @@ pycall_pyobject_wrapper_get_pyptr(VALUE obj)
|
|
1213
1255
|
return rb_funcall(obj, rb_intern("__pyptr__"), 0);
|
1214
1256
|
}
|
1215
1257
|
|
1216
|
-
|
1258
|
+
PyObject *
|
1217
1259
|
pycall_pyobject_wrapper_get_pyobj_ptr(VALUE obj)
|
1218
1260
|
{
|
1219
1261
|
VALUE pyptr = pycall_pyobject_wrapper_get_pyptr(obj);
|
@@ -1947,6 +1989,10 @@ init_python(void)
|
|
1947
1989
|
Py_API(Py_InitializeEx)(0);
|
1948
1990
|
Py_API(PySys_SetArgvEx)(0, (char **)argv, 0);
|
1949
1991
|
|
1992
|
+
if (!Py_API(PyEval_ThreadsInitialized)()) {
|
1993
|
+
Py_API(PyEval_InitThreads)();
|
1994
|
+
}
|
1995
|
+
|
1950
1996
|
/* check the availability of stackless extension */
|
1951
1997
|
python_has_stackless_extension = (Py_API(PyImport_ImportModule)("stackless") != NULL);
|
1952
1998
|
if (!python_has_stackless_extension) {
|
@@ -2078,6 +2124,7 @@ init_tuple(void)
|
|
2078
2124
|
rb_define_singleton_method(cTuple, "new", pycall_tuple_s_new, -1);
|
2079
2125
|
rb_define_method(cTuple, "length", pycall_tuple_length, 0);
|
2080
2126
|
rb_define_method(cTuple, "to_a", pycall_tuple_to_a, 0);
|
2127
|
+
rb_define_alias(cTuple, "to_ary", "to_a");
|
2081
2128
|
}
|
2082
2129
|
|
2083
2130
|
void
|
data/ext/pycall/pycall.h
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#ifndef PYCALL_H
|
2
|
+
#define PYCALL_H 1
|
3
|
+
|
4
|
+
#if defined(__cplusplus)
|
5
|
+
extern "C" {
|
6
|
+
#if 0
|
7
|
+
} /* satisfy cc-mode */
|
8
|
+
#endif
|
9
|
+
#endif
|
10
|
+
|
11
|
+
VALUE pycall_pyptr_new(PyObject *pyobj);
|
12
|
+
PyObject *pycall_pyptr_get_pyobj_ptr(VALUE pyptr);
|
13
|
+
VALUE pycall_pyobject_to_ruby(PyObject *pyobj);
|
14
|
+
PyObject *pycall_pyobject_wrapper_get_pyobj_ptr(VALUE obj);
|
15
|
+
|
16
|
+
#if defined(__cplusplus)
|
17
|
+
#if 0
|
18
|
+
{ /* satisfy cc-mode */
|
19
|
+
#endif
|
20
|
+
} /* extern "C" { */
|
21
|
+
#endif
|
22
|
+
|
23
|
+
#endif /* PYCALL_H */
|
@@ -10,6 +10,7 @@ extern "C" {
|
|
10
10
|
|
11
11
|
#include <ruby.h>
|
12
12
|
#include <ruby/encoding.h>
|
13
|
+
#include <ruby/thread.h>
|
13
14
|
#include <assert.h>
|
14
15
|
#include <inttypes.h>
|
15
16
|
#include <limits.h>
|
@@ -34,6 +35,9 @@ pycall_integer_type_p(VALUE obj)
|
|
34
35
|
#endif
|
35
36
|
|
36
37
|
void ruby_debug_breakpoint();
|
38
|
+
int ruby_thread_has_gvl_p(void);
|
39
|
+
|
40
|
+
#define CALL_WITH_GVL(func, data) rb_thread_call_with_gvl((void * (*)(void *))(func), (void *)(data))
|
37
41
|
|
38
42
|
/* ==== python ==== */
|
39
43
|
|
@@ -581,12 +585,16 @@ typedef struct {
|
|
581
585
|
|
582
586
|
PyObject * (* PyIter_Next)(PyObject *);
|
583
587
|
|
588
|
+
int (* PyEval_ThreadsInitialized)(void);
|
589
|
+
void (* PyEval_InitThreads)(void);
|
590
|
+
|
584
591
|
PyObject * (* PyErr_Occurred)(void);
|
585
592
|
void (* PyErr_Fetch)(PyObject **, PyObject **, PyObject **);
|
586
593
|
void (* PyErr_Restore)(PyObject *, PyObject *, PyObject *);
|
587
594
|
void (* PyErr_Clear)(void);
|
588
595
|
void (* PyErr_SetString)(PyObject *, const char *); /* decoded from utf-8 */
|
589
596
|
void (* PyErr_Format)(PyObject *, const char *, ...); /* ASCII-encoded string */
|
597
|
+
void (* PyErr_SetInterrupt)(void);
|
590
598
|
|
591
599
|
PyObject * (* PyImport_ImportModule)(char const*);
|
592
600
|
PyObject * (* PyImport_ImportModuleLevel)(char const*, PyObject *, PyObject *, PyObject *, int);
|
@@ -637,7 +645,6 @@ VALUE pycall_import_module_level(char const *name, VALUE globals, VALUE locals,
|
|
637
645
|
VALUE pycall_getattr_default(VALUE pyobj, char const *name, VALUE default_value);
|
638
646
|
VALUE pycall_getattr(VALUE pyobj, char const *name);
|
639
647
|
|
640
|
-
VALUE pycall_pyobject_to_ruby(PyObject *);
|
641
648
|
VALUE pycall_pytype_to_ruby(PyObject *);
|
642
649
|
VALUE pycall_pymodule_to_ruby(PyObject *);
|
643
650
|
VALUE pycall_pybool_to_ruby(PyObject *);
|
data/ext/pycall/ruby_wrapper.c
CHANGED
@@ -5,29 +5,30 @@ static PyMemberDef PyRuby_members[] = {
|
|
5
5
|
{NULL} /* sentinel */
|
6
6
|
};
|
7
7
|
|
8
|
-
static
|
9
|
-
static
|
10
|
-
static PyObject *
|
11
|
-
static PyObject *
|
8
|
+
static VALUE PyRuby_get_ruby_object_and_set_pyerr(PyObject *pyobj);
|
9
|
+
static void PyRuby_dealloc_with_gvl(PyRubyObject *);
|
10
|
+
static PyObject * PyRuby_repr_with_gvl(PyRubyObject *);
|
11
|
+
static PyObject * PyRuby_call_with_gvl(PyRubyObject *, PyObject *, PyObject *);
|
12
|
+
static PyObject * PyRuby_getattro_with_gvl(PyRubyObject *, PyObject *);
|
12
13
|
|
13
14
|
PyTypeObject PyRuby_Type = {
|
14
15
|
PyVarObject_HEAD_INIT(NULL, 0)
|
15
16
|
"PyCall.ruby_object", /* tp_name */
|
16
17
|
sizeof(PyRubyObject), /* tp_basicsize */
|
17
18
|
0, /* tp_itemsize */
|
18
|
-
(destructor)
|
19
|
+
(destructor)PyRuby_dealloc_with_gvl, /* tp_dealloc */
|
19
20
|
0, /* tp_print */
|
20
21
|
0, /* tp_getattr */
|
21
22
|
0, /* tp_setattr */
|
22
23
|
0, /* tp_reserved */
|
23
|
-
(reprfunc)
|
24
|
+
(reprfunc)PyRuby_repr_with_gvl, /* tp_repr */
|
24
25
|
0, /* tp_as_number */
|
25
26
|
0, /* tp_as_sequence */
|
26
27
|
0, /* tp_as_mapping */
|
27
28
|
{0}, /* tp_hash */
|
28
|
-
(ternaryfunc)
|
29
|
+
(ternaryfunc)PyRuby_call_with_gvl, /* tp_call */
|
29
30
|
0, /* tp_str */
|
30
|
-
(getattrofunc)
|
31
|
+
(getattrofunc)PyRuby_getattro_with_gvl, /* tp_getattro */
|
31
32
|
0, /* tp_setattro */
|
32
33
|
0, /* tp_as_buffer */
|
33
34
|
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
@@ -42,8 +43,8 @@ PyTypeObject PyRuby_Type = {
|
|
42
43
|
PyRuby_members, /*tp_members*/
|
43
44
|
};
|
44
45
|
|
45
|
-
PyObject *
|
46
|
-
|
46
|
+
static PyObject *
|
47
|
+
PyRuby_New_impl(VALUE ruby_object)
|
47
48
|
{
|
48
49
|
PyRubyObject *op;
|
49
50
|
|
@@ -53,59 +54,17 @@ PyRuby_New(VALUE ruby_object)
|
|
53
54
|
return (PyObject *)op;
|
54
55
|
}
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
{
|
59
|
-
VALUE rb_mObjSpace;
|
60
|
-
object_id = rb_check_to_integer(object_id, "to_int");
|
61
|
-
rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
|
62
|
-
return rb_funcall(rb_mObjSpace, rb_intern("_id2ref"), 1, object_id);
|
63
|
-
}
|
64
|
-
|
65
|
-
static VALUE
|
66
|
-
protect_id2ref(VALUE object_id)
|
67
|
-
{
|
68
|
-
VALUE obj;
|
69
|
-
int state;
|
70
|
-
|
71
|
-
obj = rb_protect((VALUE (*)(VALUE))funcall_id2ref, object_id, &state);
|
72
|
-
if (state)
|
73
|
-
return Qundef;
|
74
|
-
|
75
|
-
return obj;
|
76
|
-
}
|
77
|
-
|
78
|
-
static VALUE
|
79
|
-
protect_id2ref_and_set_pyerr(VALUE object_id)
|
57
|
+
PyObject *
|
58
|
+
PyRuby_New(VALUE ruby_object)
|
80
59
|
{
|
81
|
-
|
82
|
-
|
83
|
-
return obj;
|
84
|
-
|
85
|
-
obj = rb_errinfo();
|
86
|
-
if (RTEST(rb_obj_is_kind_of(obj, rb_eRangeError))) {
|
87
|
-
Py_API(PyErr_SetString)(Py_API(PyExc_RuntimeError), "[BUG] referenced object was garbage-collected");
|
60
|
+
if (!ruby_thread_has_gvl_p()) {
|
61
|
+
CALL_WITH_GVL(PyRuby_New_impl, ruby_object);
|
88
62
|
}
|
89
|
-
else {
|
90
|
-
VALUE emesg = rb_check_funcall(obj, rb_intern("message"), 0, 0);
|
91
|
-
Py_API(PyErr_Format)(Py_API(PyExc_RuntimeError),
|
92
|
-
"[BUG] Unable to obtain ruby object from ID: %s (%s)",
|
93
|
-
StringValueCStr(emesg), rb_class2name(CLASS_OF(obj)));
|
94
|
-
}
|
95
|
-
return Qundef;
|
96
|
-
}
|
97
63
|
|
98
|
-
|
99
|
-
PyRuby_get_ruby_object_and_set_pyerr(PyObject *pyobj)
|
100
|
-
{
|
101
|
-
VALUE obj_id;
|
102
|
-
if (!PyRuby_Check(pyobj))
|
103
|
-
return Qundef;
|
104
|
-
obj_id = rb_obj_id(PyRuby_get_ruby_object(pyobj));
|
105
|
-
return protect_id2ref_and_set_pyerr(obj_id);
|
64
|
+
return PyRuby_New_impl(ruby_object);
|
106
65
|
}
|
107
66
|
|
108
|
-
static void
|
67
|
+
static void *
|
109
68
|
PyRuby_dealloc(PyRubyObject *pyro)
|
110
69
|
{
|
111
70
|
VALUE obj;
|
@@ -117,9 +76,20 @@ PyRuby_dealloc(PyRubyObject *pyro)
|
|
117
76
|
#endif /* PYCALL_DEBUG_DUMP_REFCNT */
|
118
77
|
|
119
78
|
if (obj == Qundef)
|
120
|
-
return;
|
79
|
+
return NULL;
|
121
80
|
|
122
81
|
pycall_gcguard_unregister_pyrubyobj((PyObject *)pyro);
|
82
|
+
|
83
|
+
return NULL;
|
84
|
+
}
|
85
|
+
|
86
|
+
static void
|
87
|
+
PyRuby_dealloc_with_gvl(PyRubyObject *pyro)
|
88
|
+
{
|
89
|
+
if (!ruby_thread_has_gvl_p()) {
|
90
|
+
CALL_WITH_GVL(PyRuby_dealloc, pyro);
|
91
|
+
}
|
92
|
+
PyRuby_dealloc(pyro);
|
123
93
|
}
|
124
94
|
|
125
95
|
static PyObject *
|
@@ -137,6 +107,15 @@ PyRuby_repr(PyRubyObject *pyro)
|
|
137
107
|
return res;
|
138
108
|
}
|
139
109
|
|
110
|
+
static PyObject *
|
111
|
+
PyRuby_repr_with_gvl(PyRubyObject *pyro)
|
112
|
+
{
|
113
|
+
if (!ruby_thread_has_gvl_p()) {
|
114
|
+
return CALL_WITH_GVL(PyRuby_repr, pyro);
|
115
|
+
}
|
116
|
+
return PyRuby_repr(pyro);
|
117
|
+
}
|
118
|
+
|
140
119
|
#if SIZEOF_SSIZE_T < 8
|
141
120
|
/* int64to32hash from src/support/hashing.c in Julia */
|
142
121
|
static inline uint32_t
|
@@ -152,7 +131,7 @@ int64to32hash(uint64_t key)
|
|
152
131
|
}
|
153
132
|
#endif
|
154
133
|
|
155
|
-
static
|
134
|
+
static void *
|
156
135
|
PyRuby_hash_long(PyRubyObject *pyro)
|
157
136
|
{
|
158
137
|
VALUE obj, rbhash;
|
@@ -160,15 +139,24 @@ PyRuby_hash_long(PyRubyObject *pyro)
|
|
160
139
|
|
161
140
|
obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)pyro);
|
162
141
|
if (obj == Qundef)
|
163
|
-
return -1;
|
142
|
+
return (void *)-1;
|
164
143
|
|
165
144
|
rbhash = rb_hash(obj);
|
166
145
|
h = FIX2LONG(rbhash); /* Ruby's hash value is a Fixnum */
|
167
146
|
|
168
|
-
return h == -1 ? pycall_hash_salt : h;
|
147
|
+
return (void *)(h == -1 ? pycall_hash_salt : h);
|
169
148
|
}
|
170
149
|
|
171
|
-
static
|
150
|
+
static long
|
151
|
+
PyRuby_hash_long_with_gvl(PyRubyObject *pyro)
|
152
|
+
{
|
153
|
+
if (!ruby_thread_has_gvl_p()) {
|
154
|
+
return (long)CALL_WITH_GVL(PyRuby_hash_long, pyro);
|
155
|
+
}
|
156
|
+
return (long)PyRuby_hash_long(pyro);
|
157
|
+
}
|
158
|
+
|
159
|
+
static void *
|
172
160
|
PyRuby_hash_hash_t(PyRubyObject *pyro)
|
173
161
|
{
|
174
162
|
VALUE obj, rbhash;
|
@@ -176,20 +164,29 @@ PyRuby_hash_hash_t(PyRubyObject *pyro)
|
|
176
164
|
|
177
165
|
obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)pyro);
|
178
166
|
if (obj == Qundef)
|
179
|
-
return -1;
|
167
|
+
return (void *)-1;
|
180
168
|
|
181
169
|
rbhash = rb_hash(obj);
|
182
170
|
#if SIZEOF_PY_HASH_T == SIZEOF_LONG
|
183
171
|
/* In this case, we can assume sizeof(Py_hash_t) == sizeof(long) */
|
184
172
|
h = NUM2SSIZET(rbhash);
|
185
|
-
return h == -1 ? (Py_hash_t)pycall_hash_salt : h;
|
173
|
+
return (void *)(h == -1 ? (Py_hash_t)pycall_hash_salt : h);
|
186
174
|
#else
|
187
175
|
/* In this case, we can assume sizeof(long) == 4 and sizeof(Py_hash_t) == 8 */
|
188
176
|
h = (pycall_hash_salt_32 << 32) | FIX2LONG(rbhash);
|
189
|
-
return h == -1 ? ((pycall_hash_salt << 32) | pycall_hash_salt) : h;
|
177
|
+
return (void *)(h == -1 ? ((pycall_hash_salt << 32) | pycall_hash_salt) : h);
|
190
178
|
#endif
|
191
179
|
}
|
192
180
|
|
181
|
+
static Py_hash_t
|
182
|
+
PyRuby_hash_hash_t_with_gvl(PyRubyObject *pyro)
|
183
|
+
{
|
184
|
+
if (!ruby_thread_has_gvl_p()) {
|
185
|
+
return (Py_hash_t)CALL_WITH_GVL(PyRuby_hash_hash_t, pyro);
|
186
|
+
}
|
187
|
+
return (Py_hash_t)PyRuby_hash_hash_t(pyro);
|
188
|
+
}
|
189
|
+
|
193
190
|
struct call_rb_funcallv_params {
|
194
191
|
VALUE recv;
|
195
192
|
ID meth;
|
@@ -221,15 +218,21 @@ rb_protect_funcallv(VALUE recv, ID meth, int argc, VALUE *argv, int *pstate)
|
|
221
218
|
return res;
|
222
219
|
}
|
223
220
|
|
221
|
+
struct PyRuby_call_params {
|
222
|
+
PyRubyObject *pyro;
|
223
|
+
PyObject *pyobj_args;
|
224
|
+
PyObject *pyobj_kwargs;
|
225
|
+
};
|
226
|
+
|
224
227
|
static PyObject *
|
225
|
-
PyRuby_call(
|
228
|
+
PyRuby_call(struct PyRuby_call_params *params)
|
226
229
|
{
|
227
230
|
ID id_call;
|
228
231
|
VALUE obj, args, kwargs, res;
|
229
232
|
PyObject *pyobj_res;
|
230
233
|
int state;
|
231
234
|
|
232
|
-
obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)pyro);
|
235
|
+
obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)params->pyro);
|
233
236
|
if (obj == Qundef)
|
234
237
|
return NULL;
|
235
238
|
|
@@ -239,9 +242,9 @@ PyRuby_call(PyRubyObject *pyro, PyObject *pyobj_args, PyObject *pyobj_kwargs)
|
|
239
242
|
return NULL;
|
240
243
|
}
|
241
244
|
|
242
|
-
args = pycall_pyobject_to_a(pyobj_args);
|
243
|
-
if (pyobj_kwargs) {
|
244
|
-
kwargs = pycall_pyobject_to_ruby(pyobj_kwargs);
|
245
|
+
args = pycall_pyobject_to_a(params->pyobj_args);
|
246
|
+
if (params->pyobj_kwargs) {
|
247
|
+
kwargs = pycall_pyobject_to_ruby(params->pyobj_kwargs);
|
245
248
|
rb_ary_push(args, kwargs);
|
246
249
|
}
|
247
250
|
|
@@ -255,18 +258,38 @@ PyRuby_call(PyRubyObject *pyro, PyObject *pyobj_args, PyObject *pyobj_kwargs)
|
|
255
258
|
}
|
256
259
|
|
257
260
|
static PyObject *
|
258
|
-
|
261
|
+
PyRuby_call_with_gvl(PyRubyObject *pyro, PyObject *pyobj_args, PyObject *pyobj_kwargs)
|
262
|
+
{
|
263
|
+
struct PyRuby_call_params params;
|
264
|
+
params.pyro = pyro;
|
265
|
+
params.pyobj_args = pyobj_args;
|
266
|
+
params.pyobj_kwargs = pyobj_kwargs;
|
267
|
+
|
268
|
+
if (!ruby_thread_has_gvl_p()) {
|
269
|
+
return CALL_WITH_GVL(PyRuby_call, ¶ms);
|
270
|
+
}
|
271
|
+
|
272
|
+
return PyRuby_call(¶ms);
|
273
|
+
}
|
274
|
+
|
275
|
+
struct PyRuby_getattro_params {
|
276
|
+
PyRubyObject *pyro;
|
277
|
+
PyObject *pyobj_name;
|
278
|
+
};
|
279
|
+
|
280
|
+
static PyObject *
|
281
|
+
PyRuby_getattro(struct PyRuby_getattro_params *params)
|
259
282
|
{
|
260
283
|
VALUE obj, name, res;
|
261
284
|
char const *name_cstr;
|
262
285
|
ID name_id;
|
263
286
|
PyObject *pyobj_res;
|
264
287
|
|
265
|
-
obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)pyro);
|
288
|
+
obj = PyRuby_get_ruby_object_and_set_pyerr((PyObject *)params->pyro);
|
266
289
|
if (obj == Qundef)
|
267
290
|
return NULL;
|
268
291
|
|
269
|
-
name = pycall_pyobject_to_ruby(pyobj_name);
|
292
|
+
name = pycall_pyobject_to_ruby(params->pyobj_name);
|
270
293
|
name_cstr = StringValueCStr(name);
|
271
294
|
name_id = rb_intern(name_cstr);
|
272
295
|
|
@@ -299,21 +322,35 @@ PyRuby_getattro(PyRubyObject *pyro, PyObject *pyobj_name)
|
|
299
322
|
else if (name_cstr[0] == '_' && name_cstr[1] == '_') {
|
300
323
|
/* name.start_with? "__" */
|
301
324
|
/* TODO: handle `__code__` and `func_code` */
|
302
|
-
return Py_API(PyObject_GenericGetAttr)((PyObject *)pyro, pyobj_name);
|
325
|
+
return Py_API(PyObject_GenericGetAttr)((PyObject *)params->pyro, params->pyobj_name);
|
303
326
|
}
|
304
327
|
else {
|
305
328
|
/* TODO: handle `__code__` and `func_code` */
|
306
329
|
if (rb_respond_to(obj, name_id)) {
|
307
330
|
VALUE method = rb_obj_method(obj, name);
|
308
|
-
return
|
331
|
+
return PyRuby_New_impl(method);
|
309
332
|
}
|
310
|
-
return Py_API(PyObject_GenericGetAttr)((PyObject *)pyro, pyobj_name);
|
333
|
+
return Py_API(PyObject_GenericGetAttr)((PyObject *)params->pyro, params->pyobj_name);
|
311
334
|
}
|
312
335
|
|
313
336
|
pyobj_res = pycall_pyobject_from_ruby(res);
|
314
337
|
return pyobj_res;
|
315
338
|
}
|
316
339
|
|
340
|
+
static PyObject *
|
341
|
+
PyRuby_getattro_with_gvl(PyRubyObject *pyro, PyObject *pyobj_name)
|
342
|
+
{
|
343
|
+
struct PyRuby_getattro_params params;
|
344
|
+
params.pyro = pyro;
|
345
|
+
params.pyobj_name = pyobj_name;
|
346
|
+
|
347
|
+
if (!ruby_thread_has_gvl_p()) {
|
348
|
+
return CALL_WITH_GVL(PyRuby_getattro, ¶ms);
|
349
|
+
}
|
350
|
+
|
351
|
+
return PyRuby_getattro(¶ms);
|
352
|
+
}
|
353
|
+
|
317
354
|
/* ==== PyCall::PyRubyPtr ==== */
|
318
355
|
|
319
356
|
VALUE cPyRubyPtr;
|
@@ -411,9 +448,9 @@ pycall_init_ruby_wrapper(void)
|
|
411
448
|
PyRuby_Type.tp_flags |= pycall_default_tp_flags();
|
412
449
|
PyRuby_Type.tp_new = Py_API(PyType_GenericNew);
|
413
450
|
if (pycall_python_long_hash)
|
414
|
-
PyRuby_Type.tp_hash._long = (hashfunc_long)
|
451
|
+
PyRuby_Type.tp_hash._long = (hashfunc_long)PyRuby_hash_long_with_gvl;
|
415
452
|
else
|
416
|
-
PyRuby_Type.tp_hash._hash_t = (hashfunc_hash_t)
|
453
|
+
PyRuby_Type.tp_hash._hash_t = (hashfunc_hash_t)PyRuby_hash_hash_t_with_gvl;
|
417
454
|
|
418
455
|
if (Py_API(PyType_Ready)(&PyRuby_Type) < 0) {
|
419
456
|
pycall_pyerror_fetch_and_raise("PyType_Ready in pycall_init_ruby_wrapper");
|
@@ -430,3 +467,57 @@ pycall_init_ruby_wrapper(void)
|
|
430
467
|
|
431
468
|
rb_define_module_function(mPyCall, "wrap_ruby_object", pycall_m_wrap_ruby_object, 1);
|
432
469
|
}
|
470
|
+
|
471
|
+
/* --- File internal utilities --- */
|
472
|
+
|
473
|
+
static VALUE
|
474
|
+
funcall_id2ref(VALUE object_id)
|
475
|
+
{
|
476
|
+
VALUE rb_mObjSpace;
|
477
|
+
object_id = rb_check_to_integer(object_id, "to_int");
|
478
|
+
rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
|
479
|
+
return rb_funcall(rb_mObjSpace, rb_intern("_id2ref"), 1, object_id);
|
480
|
+
}
|
481
|
+
|
482
|
+
static VALUE
|
483
|
+
protect_id2ref(VALUE object_id)
|
484
|
+
{
|
485
|
+
VALUE obj;
|
486
|
+
int state;
|
487
|
+
|
488
|
+
obj = rb_protect((VALUE (*)(VALUE))funcall_id2ref, object_id, &state);
|
489
|
+
if (state)
|
490
|
+
return Qundef;
|
491
|
+
|
492
|
+
return obj;
|
493
|
+
}
|
494
|
+
|
495
|
+
static VALUE
|
496
|
+
protect_id2ref_and_set_pyerr(VALUE object_id)
|
497
|
+
{
|
498
|
+
VALUE obj = protect_id2ref(object_id);
|
499
|
+
if (obj != Qundef)
|
500
|
+
return obj;
|
501
|
+
|
502
|
+
obj = rb_errinfo();
|
503
|
+
if (RTEST(rb_obj_is_kind_of(obj, rb_eRangeError))) {
|
504
|
+
Py_API(PyErr_SetString)(Py_API(PyExc_RuntimeError), "[BUG] referenced object was garbage-collected");
|
505
|
+
}
|
506
|
+
else {
|
507
|
+
VALUE emesg = rb_check_funcall(obj, rb_intern("message"), 0, 0);
|
508
|
+
Py_API(PyErr_Format)(Py_API(PyExc_RuntimeError),
|
509
|
+
"[BUG] Unable to obtain ruby object from ID: %s (%s)",
|
510
|
+
StringValueCStr(emesg), rb_class2name(CLASS_OF(obj)));
|
511
|
+
}
|
512
|
+
return Qundef;
|
513
|
+
}
|
514
|
+
|
515
|
+
static VALUE
|
516
|
+
PyRuby_get_ruby_object_and_set_pyerr(PyObject *pyobj)
|
517
|
+
{
|
518
|
+
VALUE obj_id;
|
519
|
+
if (!PyRuby_Check(pyobj))
|
520
|
+
return Qundef;
|
521
|
+
obj_id = rb_obj_id(PyRuby_get_ruby_object(pyobj));
|
522
|
+
return protect_id2ref_and_set_pyerr(obj_id);
|
523
|
+
}
|
data/lib/pycall/conversion.rb
CHANGED
@@ -32,7 +32,7 @@ module PyCall
|
|
32
32
|
#
|
33
33
|
# @return a Ruby object converted from `pyptr`.
|
34
34
|
def self.to_ruby(pyptr)
|
35
|
-
return nil if pyptr.null? ||
|
35
|
+
return nil if pyptr.null? || pyptr.none?
|
36
36
|
|
37
37
|
case
|
38
38
|
when PyCall::Types.pyisinstance(pyptr, LibPython.PyType_Type)
|
data/lib/pycall/version.rb
CHANGED
data/pycall.gemspec
CHANGED
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.0.
|
4
|
+
version: 1.1.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kenta Murata
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -167,6 +167,7 @@ files:
|
|
167
167
|
- ext/pycall/gc.c
|
168
168
|
- ext/pycall/libpython.c
|
169
169
|
- ext/pycall/pycall.c
|
170
|
+
- ext/pycall/pycall.h
|
170
171
|
- ext/pycall/pycall_internal.h
|
171
172
|
- ext/pycall/range.c
|
172
173
|
- ext/pycall/ruby_wrapper.c
|
@@ -213,12 +214,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
213
214
|
version: '0'
|
214
215
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
215
216
|
requirements:
|
216
|
-
- - "
|
217
|
+
- - ">"
|
217
218
|
- !ruby/object:Gem::Version
|
218
|
-
version:
|
219
|
+
version: 1.3.1
|
219
220
|
requirements: []
|
220
221
|
rubyforge_project:
|
221
|
-
rubygems_version: 2.
|
222
|
+
rubygems_version: 2.7.4
|
222
223
|
signing_key:
|
223
224
|
specification_version: 4
|
224
225
|
summary: pycall
|