pycall 1.0.3 → 1.1.0.rc1
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 +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
|
-
[](https://travis-ci.org/mrkn/pycall.rb)
|
4
|
+
[](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
|